Package org.netbeans.gradle.project.model

Source Code of org.netbeans.gradle.project.model.GradleModelCache$CacheKey

package org.netbeans.gradle.project.model;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jtrim.utils.ExceptionHelper;
import org.netbeans.gradle.project.api.event.NbListenerRef;
import org.netbeans.gradle.project.properties.GlobalGradleSettings;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;

public final class GradleModelCache {
    private static final AtomicReference<GradleModelCache> DEFAULT_REF
            = new AtomicReference<>(null);

    private final ReentrantLock cacheLock;
    private final Map<CacheKey, NbGradleModel> cache;
    private final AtomicInteger maxCapacity;
    private final PropertyChangeSupport updateListeners;

    public GradleModelCache(int maxCapacity) {
        if (maxCapacity < 0) {
            throw new IllegalArgumentException("Illegal max. capacity value: " + maxCapacity);
        }

        this.cacheLock = new ReentrantLock();
        this.maxCapacity = new AtomicInteger(maxCapacity);

        float loadFactor = 0.75f;
        int capacity = (int)Math.floor((float)(maxCapacity + 1) / loadFactor);
        this.cache = new LinkedHashMap<>(capacity, loadFactor, true);
        this.updateListeners = new PropertyChangeSupport(this);
    }

    private static int getProjectCacheSize() {
        return GlobalGradleSettings.getProjectCacheSize().getValue();
    }

    public static GradleModelCache getDefault() {
        GradleModelCache result = DEFAULT_REF.get();
        if (result == null) {
            result = new GradleModelCache(getProjectCacheSize());
            if (DEFAULT_REF.compareAndSet(null, result)) {
                final GradleModelCache cache = result;
                GlobalGradleSettings.getProjectCacheSize().addChangeListener(new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        cache.setMaxCapacity(getProjectCacheSize());
                    }
                });
                cache.setMaxCapacity(getProjectCacheSize());
            }
            else {
                result = DEFAULT_REF.get();
            }
        }
        return result;
    }

    private void cleanupCache() {
        assert cacheLock.isHeldByCurrentThread();

        int currentMaxCapacity = maxCapacity.get();
        // Don't create the iterator.
        if (cache.size() <= currentMaxCapacity) {
            return;
        }

        Iterator<?> itr = cache.entrySet().iterator();
        while (cache.size() > currentMaxCapacity && itr.hasNext()) {
            itr.next();
            itr.remove();
        }
    }

    public void setMaxCapacity(int maxCapacity) {
        if (maxCapacity < 0) {
            throw new IllegalArgumentException("Illegal max. capacity value: " + maxCapacity);
        }

        int prevCapacity = this.maxCapacity.getAndSet(maxCapacity);
        if (prevCapacity > maxCapacity) {
            cacheLock.lock();
            try {
                cleanupCache();
            } finally {
                cacheLock.unlock();
            }
        }
    }

    private static CacheKey tryCreateKey(NbGradleModel model) {
        ExceptionHelper.checkNotNullArgument(model, "model");

        File projectDir = model.getGenericInfo().getProjectDir();

        FileObject settingsFileObj = model.getGenericInfo().tryGetSettingsFileObj();
        File settingsFile = settingsFileObj != null
                ? FileUtil.toFile(settingsFileObj)
                : null;

        if (projectDir == null || (settingsFile == null && settingsFileObj != null)) {
            return null;
        }

        return new CacheKey(projectDir, settingsFile);
    }

    public NbListenerRef addModelUpdateListener(final ProjectModelUpdatedListener listener) {
        ExceptionHelper.checkNotNullArgument(listener, "listener");

        final PropertyChangeListener forwarder = new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                listener.onUpdateProject((NbGradleModel)evt.getNewValue());
            }
        };

        updateListeners.addPropertyChangeListener(forwarder);
        return new NbListenerRef() {
            private volatile boolean registered = true;

            @Override
            public boolean isRegistered() {
                return registered;
            }

            @Override
            public void unregister() {
                updateListeners.removePropertyChangeListener(forwarder);
                registered = true;
            }
        };
    }

    private void notifyUpdate(NbGradleModel newModel) {
        updateListeners.firePropertyChange("newModel", null, newModel);
    }

    public NbGradleModel updateEntry(NbGradleModel model) {
        CacheKey key = tryCreateKey(model);
        if (key == null) {
            return null;
        }

        NbGradleModel newModel = model;
        NbGradleModel prevModel;
        cacheLock.lock();
        try {
            prevModel = cache.get(key);
            if (prevModel == null) {
                cache.put(key, newModel);
                cleanupCache();
            }
            else {
                newModel = prevModel.updateEntry(newModel);
                cache.put(key, newModel);
            }
        } finally {
            cacheLock.unlock();
        }

        if (prevModel != null) {
            notifyUpdate(model);
        }
        return newModel;
    }

    public void replaceEntry(NbGradleModel model) {
        CacheKey key = tryCreateKey(model);
        if (key == null) {
            return;
        }

        NbGradleModel prevModel;
        cacheLock.lock();
        try {
            prevModel = cache.put(key, model);
            cleanupCache();
        } finally {
            cacheLock.unlock();
        }

        if (prevModel != null && prevModel != model) {
            notifyUpdate(model);
        }
    }

    public NbGradleModel tryGet(File projectDir, File settingsFile) {
        CacheKey key = new CacheKey(projectDir, settingsFile);
        cacheLock.lock();
        try {
            return cache.get(key);
        } finally {
            cacheLock.unlock();
        }
    }

    private static class CacheKey {
        private final File projectDir;
        private final File settingsFile;

        public CacheKey(File projectDir, File settingsFile) {
            ExceptionHelper.checkNotNullArgument(projectDir, "projectDir");
            this.projectDir = projectDir;
            this.settingsFile = settingsFile;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 89 * hash + this.projectDir.hashCode();
            hash = 89 * hash + (this.settingsFile != null ? this.settingsFile.hashCode() : 0);
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == this) return true;
            if (obj == null) return false;
            if (getClass() != obj.getClass()) return false;

            final CacheKey other = (CacheKey)obj;

            if (this.projectDir != other.projectDir && (!this.projectDir.equals(other.projectDir))) {
                return false;
            }
            return this.settingsFile == other.settingsFile
                    || (this.settingsFile != null && this.settingsFile.equals(other.settingsFile));
        }
    }
}
TOP

Related Classes of org.netbeans.gradle.project.model.GradleModelCache$CacheKey

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.