Package org.netbeans.gradle.project.properties

Source Code of org.netbeans.gradle.project.properties.ProjectPropertiesProxy

package org.netbeans.gradle.project.properties;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jtrim.cancel.CancellationToken;
import org.jtrim.concurrent.WaitableSignal;
import org.jtrim.utils.ExceptionHelper;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.gradle.project.NbGradleProject;
import org.netbeans.gradle.project.api.entry.ProjectPlatform;
import org.netbeans.gradle.project.persistent.PropertiesPersister;
import org.openide.util.ChangeSupport;
import org.w3c.dom.Element;

public final class ProjectPropertiesProxy extends AbstractProjectProperties {
    private static final Logger LOGGER = Logger.getLogger(ProjectPropertiesProxy.class.getName());

    private final NbGradleProject project;
    private final AtomicReference<ProjectProperties> propertiesRef;
    private final ChangeSupport changes;

    private final MutablePropertyProxy<String> sourceLevelProxy;
    private final MutablePropertyProxy<ProjectPlatform> platformProxy;
    private final MutablePropertyProxy<JavaPlatform> scriptPlatformProxy;
    private final MutablePropertyProxy<GradleLocation> gradleHomeProxy;
    private final MutablePropertyProxy<Charset> sourceEncodingProxy;
    private final MutablePropertyProxy<List<PredefinedTask>> commonTasksProxy;
    private final MutablePropertyProxy<LicenseHeaderInfo> licenseHeaderProxy;
    private final MutablePropertyProxy<Void> auxConfigListener;
    private final ConcurrentMap<String, MutablePropertyProxy<PredefinedTask>> builtInTasks;
    private final ConcurrentMap<DomElementKey, AuxConfigProperty> auxProperties;
    private final WaitableSignal loadedSignal;

    public ProjectPropertiesProxy(NbGradleProject project) {
        ExceptionHelper.checkNotNullArgument(project, "project");

        this.project = project;
        this.propertiesRef = new AtomicReference<>(null);
        this.changes = new ChangeSupport(this);
        this.loadedSignal = new WaitableSignal();

        this.auxProperties = new ConcurrentHashMap<>();
        this.auxConfigListener = new MutablePropertyProxy<>(new ProjectMutablePropertyRef<Void>(this) {
            @Override
            public MutableProperty<Void> getProperty() {
                return super.getProperties().getAuxConfigListener();
            }
        });
        this.sourceLevelProxy = new MutablePropertyProxy<>(new ProjectMutablePropertyRef<String>(this) {
            @Override
            public MutableProperty<String> getProperty() {
                return super.getProperties().getSourceLevel();
            }
        });
        this.platformProxy = new MutablePropertyProxy<>(new ProjectMutablePropertyRef<ProjectPlatform>(this) {
            @Override
            public MutableProperty<ProjectPlatform> getProperty() {
                return super.getProperties().getPlatform();
            }
        });
        this.scriptPlatformProxy = new MutablePropertyProxy<>(new ProjectMutablePropertyRef<JavaPlatform>(this) {
            @Override
            public MutableProperty<JavaPlatform> getProperty() {
                return super.getProperties().getScriptPlatform();
            }
        });
        this.gradleHomeProxy = new MutablePropertyProxy<>(new ProjectMutablePropertyRef<GradleLocation>(this) {
            @Override
            public MutableProperty<GradleLocation> getProperty() {
                return super.getProperties().getGradleLocation();
            }
        });
        this.sourceEncodingProxy = new MutablePropertyProxy<>(new ProjectMutablePropertyRef<Charset>(this) {
            @Override
            public MutableProperty<Charset> getProperty() {
                return super.getProperties().getSourceEncoding();
            }
        });
        this.licenseHeaderProxy = new MutablePropertyProxy<>(new ProjectMutablePropertyRef<LicenseHeaderInfo>(this) {
            @Override
            public MutableProperty<LicenseHeaderInfo> getProperty() {
                return super.getProperties().getLicenseHeader();
            }
        });
        this.commonTasksProxy = new MutablePropertyProxy<>(new ProjectMutablePropertyRef<List<PredefinedTask>>(this) {
            @Override
            public MutableProperty<List<PredefinedTask>> getProperty() {
                return super.getProperties().getCommonTasks();
            }
        });

        this.builtInTasks = new ConcurrentHashMap<>();
    }

    public boolean isLoaded() {
        return loadedSignal.isSignaled();
    }

    public void waitForLoaded(CancellationToken cancelToken) {
        // Attempting to call this method from any of the threads below could
        // cause a dead-lock.
        if (NbGradleProject.PROJECT_PROCESSOR.isExecutingInThis()) {
            throw new IllegalStateException("This method cannot be access from the PROJECT_PROCESSOR.");
        }
        if (PropertiesPersister.PERSISTER_PROCESSOR.isExecutingInThis()) {
            throw new IllegalStateException("This method cannot be access from the PERSISTER_PROCESSOR.");
        }

        getProperties();
        loadedSignal.waitSignal(cancelToken);
    }

    private ProjectProperties getProperties() {
        ProjectProperties properties = propertiesRef.get();
        if (properties == null) {
            properties = ProjectPropertiesManager.getProperties(project, loadedSignal);
            if (propertiesRef.compareAndSet(null, properties)) {
                ChangeListener reloadTask = new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        propertiesRef.set(ProjectPropertiesManager.getProperties(project, loadedSignal));
                        changes.fireChange();
                    }
                };

                project.addModelChangeListener(reloadTask);
                project.addProfileChangeListener(reloadTask);
            }

            properties = propertiesRef.get();
        }
        return properties;
    }

    private void addModelChangeListener(ChangeListener listener) {
        changes.addChangeListener(listener);
    }

    private void removeModelChangeListener(ChangeListener listener) {
        changes.removeChangeListener(listener);
    }

    @Override
    public MutableProperty<LicenseHeaderInfo> getLicenseHeader() {
        return licenseHeaderProxy;
    }

    @Override
    public MutableProperty<String> getSourceLevel() {
        return sourceLevelProxy;
    }

    @Override
    public MutableProperty<ProjectPlatform> getPlatform() {
        return platformProxy;
    }

    @Override
    public MutableProperty<JavaPlatform> getScriptPlatform() {
        return scriptPlatformProxy;
    }

    @Override
    public MutableProperty<GradleLocation> getGradleLocation() {
        return gradleHomeProxy;
    }

    @Override
    public MutableProperty<Charset> getSourceEncoding() {
        return sourceEncodingProxy;
    }

    @Override
    public MutableProperty<List<PredefinedTask>> getCommonTasks() {
        return commonTasksProxy;
    }

    @Override
    public Set<String> getKnownBuiltInCommands() {
        return getProperties().getKnownBuiltInCommands();
    }

    @Override
    public MutableProperty<PredefinedTask> tryGetBuiltInTask(final String command) {
        ExceptionHelper.checkNotNullArgument(command, "command");

        MutableProperty<PredefinedTask> result = builtInTasks.get(command);
        if (result == null) {
            MutablePropertyProxy<PredefinedTask> proxy = new MutablePropertyProxy<>(new ProjectMutablePropertyRef<PredefinedTask>(this) {
                @Override
                public MutableProperty<PredefinedTask> getProperty() {
                    MutableProperty<PredefinedTask> taskProperty = super.getProperties().tryGetBuiltInTask(command);
                    if (taskProperty == null) {
                        throw new IllegalStateException("Missing customizable command: " + command);
                    }
                    return taskProperty;
                }
            });
            builtInTasks.putIfAbsent(command, proxy);
            result = builtInTasks.get(command);
        }
        return result;
    }

    @Override
    public AuxConfigProperty getAuxConfig(final String elementName, final String namespace) {
        DomElementKey key = new DomElementKey(elementName, namespace);
        AuxConfigProperty property = auxProperties.get(key);
        if (property != null) {
            return property;
        }

        MutablePropertyProxy<Element> proxy = new MutablePropertyProxy<>(new ProjectMutablePropertyRef<Element>(this) {
            @Override
            public MutableProperty<Element> getProperty() {
                return super.getProperties().getAuxConfig(elementName, namespace).getProperty();
            }
        });
        auxProperties.putIfAbsent(key, new AuxConfigProperty(key, proxy));
        return auxProperties.get(key);
    }

    @Override
    public MutableProperty<Void> getAuxConfigListener() {
        return auxConfigListener;
    }

    @Override
    public void setAllAuxConfigs(Collection<AuxConfig> configs) {
        for (AuxConfigProperty property: auxProperties.values()) {
            property.getProperty().setValue(null);
        }
        for (AuxConfig config: configs) {
            DomElementKey key = config.getKey();
            getAuxConfig(key.getName(), key.getNamespace()).getProperty().setValue(config.getValue());
        }
    }

    @Override
    public Collection<AuxConfigProperty> getAllAuxConfigs() {
        return new ArrayList<>(auxProperties.values());
    }

    private static interface MutablePropertyRef<ValueType> {
        public MutableProperty<ValueType> getProperty();

        public void addChangeListener(ChangeListener listener);
        public void removeChangeListener(ChangeListener listener);
    }

    private static abstract class ProjectMutablePropertyRef<ValueType>
    implements
            MutablePropertyRef<ValueType> {

        private final ProjectPropertiesProxy parent;

        public ProjectMutablePropertyRef(ProjectPropertiesProxy parent) {
            this.parent = parent;
        }

        protected final ProjectProperties getProperties() {
            return parent.getProperties();
        }

        @Override
        public final void addChangeListener(ChangeListener listener) {
            parent.addModelChangeListener(listener);
        }

        @Override
        public final void removeChangeListener(ChangeListener listener) {
            parent.removeModelChangeListener(listener);
        }
    }

    private static class MutablePropertyProxy<ValueType> implements MutableProperty<ValueType> {
        private final MutablePropertyRef<ValueType> propertyRef;

        private final Lock mainLock;
        private MutableProperty<?> forwardingTo;
        private final ChangeListener forwarder;
        private final List<ChangeListener> listeners;

        public MutablePropertyProxy(MutablePropertyRef<ValueType> propertyRef) {
            this.propertyRef = propertyRef;
            this.mainLock = new ReentrantLock();
            this.listeners = new LinkedList<>();
            this.forwardingTo = null;
            this.forwarder = new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    List<ChangeListener> listenersCopy = null;
                    mainLock.lock();
                    try {
                        if (!listeners.isEmpty()) {
                            listenersCopy = new ArrayList<>(listeners);
                        }
                    } finally {
                        mainLock.unlock();
                    }

                    if (listenersCopy != null) {
                        for (ChangeListener listener: listenersCopy) {
                            try {
                                listener.stateChanged(e);
                            } catch (Throwable ex) {
                                LOGGER.log(Level.SEVERE, "Unexpected exception in a listener.", ex);
                            }
                        }
                    }
                }
            };
        }

        @Override
        public void setValueFromSource(PropertySource<? extends ValueType> source) {
            propertyRef.getProperty().setValueFromSource(source);
        }

        @Override
        public void setValue(ValueType value) {
            propertyRef.getProperty().setValue(value);
        }

        @Override
        public ValueType getValue() {
            return propertyRef.getProperty().getValue();
        }

        @Override
        public boolean isDefault() {
            return propertyRef.getProperty().isDefault();
        }

        @Override
        public void addChangeListener(ChangeListener listener) {
            mainLock.lock();
            try {
                if (listeners.isEmpty()) {
                    forwardingTo = propertyRef.getProperty();
                    forwardingTo.addChangeListener(forwarder);
                    propertyRef.addChangeListener(forwarder);
                }
                listeners.add(listener);
            } finally {
                mainLock.unlock();
            }
        }

        @Override
        public void removeChangeListener(ChangeListener listener) {
            mainLock.lock();
            try {
                if (listeners.isEmpty()) {
                    return;
                }

                listeners.remove(listener);
                if (listeners.isEmpty()) {
                    if (forwardingTo != null) {
                        propertyRef.removeChangeListener(forwarder);
                        forwardingTo.removeChangeListener(listener);
                        forwardingTo = null;
                    }
                    else {
                        String logMessage = "Cannot remove forwarding listener.";
                        LOGGER.log(Level.SEVERE, logMessage, new IllegalStateException(logMessage));
                    }
                }
            } finally {
                mainLock.unlock();
            }
        }
    }
}
TOP

Related Classes of org.netbeans.gradle.project.properties.ProjectPropertiesProxy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.