GlobalSourcePath.java :  » IDE-Netbeans » java » org » netbeans » modules » java » source » classpath » Java Open Source

Java Open Source » IDE Netbeans » java 
java » org » netbeans » modules » java » source » classpath » GlobalSourcePath.java
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */

package org.netbeans.modules.java.source.classpath;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TooManyListenersException;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Logger;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.classpath.GlobalPathRegistry;
import org.netbeans.api.java.classpath.GlobalPathRegistryEvent;
import org.netbeans.api.java.classpath.GlobalPathRegistryListener;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.java.platform.JavaPlatformManager;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.api.project.Sources;
import org.netbeans.api.project.libraries.Library;
import org.netbeans.api.project.libraries.LibraryManager;
import org.netbeans.spi.java.classpath.ClassPathImplementation;
import org.netbeans.spi.java.classpath.PathResourceImplementation;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.netbeans.spi.project.libraries.support.LibrariesSupport;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.util.Exceptions;
import org.openide.util.Mutex;
import org.openide.util.RequestProcessor;
import org.openide.util.Utilities;
import org.openide.util.WeakListeners;

/**
 *
 * @author Tomas Zezula
 */
public class GlobalSourcePath {
    
    public static final String PROP_INCLUDES = ClassPath.PROP_INCLUDES;

    private static final RequestProcessor firer = new RequestProcessor ();
    
    private static GlobalSourcePath instance;
    
    private final GlobalPathRegistry gpr;
    private List<? extends PathResourceImplementation> resources;
    private List<? extends PathResourceImplementation> unknownResources;
    private List<? extends PathResourceImplementation> binaryResources;
    private Set<ClassPath> activeCps;
    private Map<URL, SourceForBinaryQuery.Result> sourceResults;
    private Map<URL, URL[]> translatedRoots;
    private Map<URL, WeakValue> unknownRoots;
    private long timeStamp;             //Lamport event ordering
    private Runnable debugCallBack;
    private volatile boolean useLibraries = true;
    
    private final SourcePathImplementation sourcePath;
    private final BinaryPathImplementation binaryPath;
    private final UnknownSourcePathImplementation unknownSourcePath;
    
    private final JavaPlatformManager pm;
    private Set<JavaPlatform> seenPlatforms;
    private Set<Library> seenLibs;
    private Collection<LibraryManager> seenLibManagers;
    
    private Set<URL> libsSrcs;
    
    private final Listener listener;
    private final LibsListener libsListener;
    
    private volatile PropertyChangeListener excludesListener;

    /** Creates a new instance of GlobalSourcePath */
    private GlobalSourcePath() {
        this.listener = new Listener ();
        this.sourcePath = new SourcePathImplementation ();
        this.binaryPath = new BinaryPathImplementation ();
        this.unknownSourcePath = new UnknownSourcePathImplementation ();
        this.timeStamp = -1;
        this.gpr = GlobalPathRegistry.getDefault();
        this.activeCps = Collections.emptySet();
        this.sourceResults = Collections.emptyMap();
        this.unknownRoots = new HashMap<URL, WeakValue>();
        this.translatedRoots = new HashMap<URL, URL[]> ();
        this.gpr.addGlobalPathRegistryListener ((GlobalPathRegistryListener)WeakListeners.create(GlobalPathRegistryListener.class,this.listener,this.gpr));        
        this.seenPlatforms = new HashSet<JavaPlatform>();
        this.seenLibs = new HashSet<Library> ();
        this.seenLibManagers = new HashSet<LibraryManager>();
        this.libsListener = new LibsListener ();
        LibraryManager.addOpenManagersPropertyChangeListener(WeakListeners.propertyChange(libsListener, null));
        this.pm = JavaPlatformManager.getDefault();
        this.pm.addPropertyChangeListener(WeakListeners.propertyChange(libsListener, this.pm));
    }
    
    
    public synchronized void setExcludesListener (final PropertyChangeListener listener) throws TooManyListenersException {
        if (listener != null && this.excludesListener != null) {
            throw new TooManyListenersException ();
        }
        this.excludesListener=listener;
    }
    
    public URL[] getSourceRootForBinaryRoot (final URL binaryRoot, final ClassPath definingClassPath, final boolean fire) {
        URL[] result = this.translatedRoots.get(binaryRoot);
        if (result != null) {
            if (result.length > 0) {
                return result;
            }
            else {
                return null;
            }
        } 
        else {
            List<URL> cacheRoots = new ArrayList<URL> ();
            Collection<? extends PathResourceImplementation> unknownRes = getSources(SourceForBinaryQuery.findSourceRoots(binaryRoot).getRoots(),cacheRoots,null);
            if (unknownRes.isEmpty()) {
                return null;
            }
            else {                
                result = new URL[cacheRoots.size()];
                synchronized (this) {
                    Iterator<URL> it = cacheRoots.iterator();
                    for (int i=0; it.hasNext(); i++) {
                        result[i] = it.next ();
                        unknownRoots.put(result[i],new WeakValue(definingClassPath,result[i]));
                    }
                }
                if (fire) {
                    this.resetCacheAndFire();
                }
                return result;
            }
        }
    }
    
    public boolean isLibrary (final ClassPath cp) {
        assert cp != null;
        Set<URL> libs = getLibsSources();
        for (ClassPath.Entry entry : cp.entries()) {
            if (libs.contains(entry.getURL())) {
                return true;
            }
        }
        return false;
    }
    
    public boolean isLibrary (final URL root) {
        assert root != null;
        Set<URL> libs = getLibsSources();
        return libs.contains(root);
    }
    
    public ClassPathImplementation getSourcePath () {
        return this.sourcePath;
    }
    
    public ClassPathImplementation getUnknownSourcePath () {
        return this.unknownSourcePath;
    }
    
    public ClassPathImplementation getBinaryPath () {
        return this.binaryPath;
    }
    
    private void resetCacheAndFire () {
        synchronized (this) {
            this.resources = null;
            this.binaryResources = null;
            this.unknownResources = null;
            this.timeStamp++;
        }

        firer.post(new Runnable () {
            public void run() {
                sourcePath.firePropertyChange ();
                binaryPath.firePropertyChange ();
                unknownSourcePath.firePropertyChange();
            }
        });        
    }
    
    private Result createResources (final Request r) {
        assert r != null;
        Set<PathResourceImplementation> result = new HashSet<PathResourceImplementation> ();
        Set<PathResourceImplementation> unknownResult = new HashSet<PathResourceImplementation> ();
        Set<PathResourceImplementation> binaryResult = new HashSet<PathResourceImplementation> ();
        final Map<URL,URL[]> translatedRoots = new HashMap<URL, URL[]>();
        Set<ClassPath> newCps = new HashSet<ClassPath> ();
        for (ClassPath cp : r.sourceCps) {
            boolean isNew = !r.oldCps.remove(cp);
            for (ClassPath.Entry entry : cp.entries()) {
                result.add(ClassPathSupport.createResource(entry.getURL()));
            }
            boolean notContained = newCps.add (cp);
            if (isNew && notContained) {
               cp.addPropertyChangeListener(r.propertyListener);
            }
        }
        Map<URL,SourceForBinaryQuery.Result> newSR = new HashMap<URL,SourceForBinaryQuery.Result> ();
        for (ClassPath cp : r.bootCps) {
            boolean isNew = !r.oldCps.remove(cp);
            for (ClassPath.Entry entry : cp.entries()) {
                URL url = entry.getURL();
                if (!translatedRoots.containsKey(url)) {
                    SourceForBinaryQuery.Result sr = r.oldSR.remove (url);
                    boolean isNewSR;
                    if (sr == null) {
                        sr = SourceForBinaryQuery.findSourceRoots(url);
                        isNewSR = true;                    
                    }
                    else {
                        isNewSR = false;
                    }    
                    assert !newSR.containsKey(url);
                    newSR.put(url,sr);
                    List<URL> cacheURLs = new ArrayList<URL> ();
                    Collection<? extends PathResourceImplementation> srcRoots = getSources (sr.getRoots(), cacheURLs, r.unknownRoots);
                    if (srcRoots.isEmpty()) {
                        binaryResult.add (ClassPathSupport.createResource(url));
                    }
                    else {
                        result.addAll(srcRoots);
                    }
                    translatedRoots.put(url, cacheURLs.toArray(new URL[cacheURLs.size()]));
                    if (isNewSR) {
                        sr.addChangeListener(r.changeListener);
                    }
                }                
            }
            boolean notContained = newCps.add (cp);
            if (isNew && notContained) {
                cp.addPropertyChangeListener(r.propertyListener);
            }
        }
        
        for (ClassPath cp : r.compileCps) {
            boolean isNew = !r.oldCps.remove(cp);
            for (ClassPath.Entry entry : cp.entries()) {
                URL url = entry.getURL();
                if (!translatedRoots.containsKey(url)) {
                    SourceForBinaryQuery.Result sr = r.oldSR.remove (url);
                    boolean isNewSR;
                    if (sr == null) {
                        sr = SourceForBinaryQuery.findSourceRoots(url);
                        isNewSR = true;                    
                    }
                    else {
                        isNewSR = false;
                    }
                    assert !newSR.containsKey(url);
                    newSR.put(url,sr);
                    List<URL> cacheURLs = new ArrayList<URL> ();
                    Collection<? extends PathResourceImplementation> srcRoots = getSources(sr.getRoots(),cacheURLs, r.unknownRoots);
                    if (srcRoots.isEmpty()) {
                        binaryResult.add(ClassPathSupport.createResource(url));
                    }
                    else {
                        result.addAll(srcRoots);
                    }
                    translatedRoots.put(url, cacheURLs.toArray(new URL[cacheURLs.size()]));
                    if (isNewSR) {
                        sr.addChangeListener(r.changeListener);
                    }
                }
            }
            boolean notContained = newCps.add (cp);
            if (isNew && notContained) {
                cp.addPropertyChangeListener(r.propertyListener);
            }
        }
        
        for (ClassPath cp : r.oldCps) {
            cp.removePropertyChangeListener(r.propertyListener);
        }
        
        for (Map.Entry<URL,SourceForBinaryQuery.Result> entry : r.oldSR.entrySet()) {
            entry.getValue().removeChangeListener(r.changeListener);
        }                        
        for (URL unknownRoot : r.unknownRoots.keySet()) {
            unknownResult.add (ClassPathSupport.createResource(unknownRoot));
        }        
        return new Result (r.timeStamp, new ArrayList<PathResourceImplementation> (result), new ArrayList(binaryResult), new ArrayList<PathResourceImplementation>(unknownResult),
                newCps,newSR,translatedRoots, r.unknownRoots);
    }    
    
    /**
     * Unit test method, used to set a callback which is called
     * form getResources to emulate a race condition.
     * The access to debugCallBack is not synchronized, it should be
     * set before test and unset after test.
     * @param callBack to be called
     *
     **/
    void setDebugCallBack (final Runnable callBack) {
        this.debugCallBack = callBack;
    }
    
    /**
     * Unit test method, used to set disable use of {@link Library}
     * int the test in which the libraries SPI is not initialized.   
     * @param use if false libraries will not be used
     *
     **/
    void setUseLibraries (final boolean use) {
        StackTraceElement[] st = Thread.currentThread().getStackTrace();
        final String myClass = this.getClass().getName();
        final String expectedCallerClass = this.getClass().getPackage().getName() + 
            ".GlobalSourcePathTestUtil";          //NOI18N
        for (int i=0; i<st.length; i++) {
            if (myClass.equals(st[i].getClassName())) {
                if (expectedCallerClass.equals(st[i+1].getClassName())) {
                    this.useLibraries = use;
                    return;
                }
                else {
                    throw new AssertionError ("Can be called only by GlobalSourcePathTestUtil");    //NOI18N
                }
            }
        }
    }
    
    private Collection <? extends PathResourceImplementation> getSources (final FileObject[] roots, final List<URL> cacheDirs, final Map<URL, WeakValue> unknownRoots) {
        assert roots != null;        
        URL[] urls = new URL[roots.length];
        boolean add = true;
        Set<URL> libs = getLibsSources();
        for (int i=0; i<roots.length; i++) {
            try {
                URL url = roots[i].getURL();
                if (!"file".equals(url.getProtocol())) {     //NOI18N
                    add = false;
                    break;
                }
                if (libs.contains (url)) {
                    add = false;
                    break;
                }
                urls[i] = url;
            } catch (FileStateInvalidException e) {
                ErrorManager.getDefault().notify(e);
            }
        }        
        if (add) {
            List<PathResourceImplementation> result = new ArrayList<PathResourceImplementation> (roots.length);
            for (int i=0; i<urls.length; i++) {
                if (cacheDirs != null) {
                    cacheDirs.add (urls[i]);                        
                }
                if (unknownRoots != null) {
                    unknownRoots.remove (urls[i]);
                }
                result.add(ClassPathSupport.createResource(urls[i]));
            }
            return result;
        }
        return Collections.<PathResourceImplementation>emptySet();
    }
    
    private Set<URL> getLibsSources () {
        if (!useLibraries) {
            //Running in the test where libraries modules SPI is not initialized
            return Collections.<URL>emptySet();
        }
        // retrieve list outside of java mutex:
        final Collection<LibraryManager> libraryManagers = LibraryManager.getOpenManagers();
        final Mutex.Action<Set<URL>> libsTask = new Mutex.Action<Set<URL>> () {
            public Set<URL> run () {
                synchronized (GlobalSourcePath.this) {
                    if (GlobalSourcePath.this.libsSrcs == null) {
                        final Set<URL> _libSrcs = new HashSet<URL>();
                        Set<JavaPlatform> platforms = new HashSet<JavaPlatform> (Arrays.asList(pm.getInstalledPlatforms()));
                        Set<JavaPlatform> oldPlatforms = new HashSet<JavaPlatform> (GlobalSourcePath.this.seenPlatforms);
                        OUTER: for (JavaPlatform platform : platforms) {                
                            if (!oldPlatforms.remove(platform)) {
                                platform.addPropertyChangeListener(GlobalSourcePath.this.libsListener);
                            }
                            ClassPath cp = platform.getSourceFolders();
                            assert cp != null : platform.getClass();
                            for (ClassPath.Entry e : cp.entries()) {
                                URL url = e.getURL();
                                try {
                                    Project p = FileOwnerQuery.getOwner(url.toURI());
                                    if (p != null) {
                                        Sources src = p.getLookup().lookup(Sources.class);
                                        if (src != null) {
                                            for (SourceGroup group : src.getSourceGroups("java")) {        //NOI18N
                                                if (url.equals(group.getRootFolder().getURL())) {
                                                    continue OUTER;
                                                }
                                            }
                                        }
                                    }
                                } catch (URISyntaxException ex) {
                                    Exceptions.printStackTrace(ex);
                                }
                                catch (FileStateInvalidException ex) {
                                    Exceptions.printStackTrace(ex);
                                }
                                _libSrcs.add(url);
                            }
                        }
                        for (JavaPlatform platform : oldPlatforms) {
                            platform.removePropertyChangeListener(GlobalSourcePath.this.libsListener);
                        }
                        GlobalSourcePath.this.seenPlatforms = platforms;

                        for (LibraryManager lm : GlobalSourcePath.this.seenLibManagers) {
                            lm.removePropertyChangeListener(libsListener);
                        }
                        Set<Library> oldLibs = new HashSet<Library>(GlobalSourcePath.this.seenLibs);
                        Set<Library> newLibs = new HashSet<Library>();
                        for (LibraryManager lm : libraryManagers) {
                            lm.addPropertyChangeListener(libsListener);

                            Set<Library> libs = new HashSet<Library> (Arrays.asList(lm.getLibraries()));
                            OUTER: for (Library lib :libs) {
                                newLibs.add(lib);
                                if (!oldLibs.remove(lib)) {
                                    lib.addPropertyChangeListener(GlobalSourcePath.this.libsListener);
                                }
                                if (lib.getContent("classpath") != null) {      //NOI18N
                                    List<URL> libSrc = lib.getContent("src");      //NOI18N
                                    for (URL url : libSrc) {                        
                                        try {
                                            url = LibrariesSupport.resolveLibraryEntryURL(lm.getLocation(), url);
                                            Project p = FileOwnerQuery.getOwner(url.toURI());
                                            if (p != null) {
                                                Sources src = p.getLookup().lookup(Sources.class);
                                                if (src != null) {
                                                    for (SourceGroup group : src.getSourceGroups("java")) {        //NOI18N
                                                        if (url.equals(group.getRootFolder().getURL())) {
                                                            continue OUTER;
                                                        }
                                                    }
                                                }
                                            }
                                        } catch (URISyntaxException ex) {
                                            Exceptions.printStackTrace(ex);
                                        }
                                        catch (FileStateInvalidException ex) {
                                            Exceptions.printStackTrace(ex);
                                        }                        
                                        _libSrcs.add(url);
                                    }

                                }
                            }
                        }
                        for (Library lib : oldLibs) {
                            lib.removePropertyChangeListener(GlobalSourcePath.this.libsListener);
                        }
                        GlobalSourcePath.this.seenLibManagers = libraryManagers;
                        GlobalSourcePath.this.seenLibs = newLibs;
                        GlobalSourcePath.this.libsSrcs = _libSrcs;
                    }
                    return GlobalSourcePath.this.libsSrcs;
                }
            }
        };
        return ProjectManager.mutex().readAccess(libsTask);
    }
       
    private class WeakValue extends WeakReference<ClassPath> implements Runnable {
        
        private URL key;
        
        public WeakValue (ClassPath ref, URL key) {
            super (ref, Utilities.activeReferenceQueue());
            assert key != null;
            this.key = key;                        
        }                
        
        public void run () {
            boolean fire = false;
            synchronized (GlobalSourcePath.this) {                
                fire = (GlobalSourcePath.this.unknownRoots.remove (key) != null);                
            }
            if (fire) {                
                GlobalSourcePath.this.resetCacheAndFire();
            }
        }        
    }
    
    private long getTimeStamp () {
        return this.timeStamp;        
    }    
    
    private static class Request {
        
        final long timeStamp;
        final Set<ClassPath> sourceCps;
        final Set<ClassPath> bootCps;
        final Set<ClassPath> compileCps;
        final Set<ClassPath> oldCps;
        final Map <URL, SourceForBinaryQuery.Result> oldSR;
        final Map<URL, WeakValue> unknownRoots;
        final PropertyChangeListener propertyListener;
        final ChangeListener changeListener;
        
        public Request (final long timeStamp, final Set<ClassPath> sourceCps, final Set<ClassPath> bootCps, final Set<ClassPath> compileCps,
            final Set<ClassPath> oldCps, final Map <URL, SourceForBinaryQuery.Result> oldSR, final Map<URL, WeakValue> unknownRoots,
            final PropertyChangeListener propertyListener, final ChangeListener changeListener) {
            assert sourceCps != null;
            assert bootCps != null;
            assert compileCps != null;
            assert oldCps != null;
            assert oldSR != null;
            assert unknownRoots != null;
            assert propertyListener != null;
            assert changeListener != null;
            
            this.timeStamp = timeStamp;
            this.sourceCps = sourceCps;
            this.bootCps = bootCps;
            this.compileCps = compileCps;
            this.oldCps = oldCps;
            this.oldSR = oldSR;
            this.unknownRoots = unknownRoots;
            this.propertyListener = propertyListener;
            this.changeListener = changeListener;
        }
    }
    
    private static class Result {
     
        final long timeStamp;
        final List<? extends PathResourceImplementation> resources;
        final List<? extends PathResourceImplementation> binaryResources;
        final List<? extends PathResourceImplementation> unknownResources;
        final Set<ClassPath> newCps;
        final Map<URL, SourceForBinaryQuery.Result> newSR;
        final Map<URL, URL[]> translatedRoots;
        final Map<URL, WeakValue> unknownRoots;
        
        public Result (final long timeStamp, final List<? extends PathResourceImplementation> resources,
            final List<? extends PathResourceImplementation> binaryResources,
            final List<? extends PathResourceImplementation> unknownResources,
            final Set<ClassPath> newCps,
            final Map<URL, SourceForBinaryQuery.Result> newSR, final Map<URL, URL[]> translatedRoots,
            final Map<URL, WeakValue> unknownRoots) {
            assert resources != null;
            assert binaryResources != null;
            assert unknownResources != null;
            assert newCps != null;
            assert newSR  != null;
            assert translatedRoots != null;
            this.timeStamp = timeStamp;
            this.resources = resources;
            this.binaryResources = binaryResources;
            this.unknownResources = unknownResources;
            this.newCps = newCps;
            this.newSR = newSR;
            this.translatedRoots = translatedRoots;
            this.unknownRoots = unknownRoots;
        }
    }
    
    private class SourcePathImplementation implements ClassPathImplementation {
        
        private List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();
        
    
        public List<? extends PathResourceImplementation> getResources() {
            Request request;
            synchronized (GlobalSourcePath.this) {
                if (GlobalSourcePath.this.resources != null) {
                    return GlobalSourcePath.this.resources;
                }
                request = new Request (
                    GlobalSourcePath.this.getTimeStamp(),
                    GlobalSourcePath.this.gpr.getPaths(ClassPath.SOURCE),
                    GlobalSourcePath.this.gpr.getPaths(ClassPath.BOOT), 
                    GlobalSourcePath.this.gpr.getPaths(ClassPath.COMPILE),
                    new HashSet (GlobalSourcePath.this.activeCps),
                    new HashMap (GlobalSourcePath.this.sourceResults),
                    new HashMap<URL,WeakValue> (GlobalSourcePath.this.unknownRoots),
                    GlobalSourcePath.this.listener,
                    GlobalSourcePath.this.listener);
            }
            Result res = createResources (request);
            if (GlobalSourcePath.this.debugCallBack != null) {
                GlobalSourcePath.this.debugCallBack.run();
            }
            synchronized (this) {            
                if (GlobalSourcePath.this.getTimeStamp() == res.timeStamp) {
                    if (GlobalSourcePath.this.resources == null) {
                        GlobalSourcePath.this.resources = res.resources;
                        GlobalSourcePath.this.binaryResources = res.binaryResources;
                        GlobalSourcePath.this.unknownResources = res.unknownResources;
                        GlobalSourcePath.this.activeCps = res.newCps;
                        GlobalSourcePath.this.sourceResults = res.newSR;
                        GlobalSourcePath.this.translatedRoots = res.translatedRoots;
                        GlobalSourcePath.this.unknownRoots = res.unknownRoots;
                    }
                    return GlobalSourcePath.this.resources;
                }            
                else {
                    return res.resources;
                }
            }
        }
    
        public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
            assert listener != null;
            if (this.listeners == null) {
                this.listeners = new ArrayList<PropertyChangeListener> ();
            }
            this.listeners.add (listener);        
        }

        public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
            assert listener != null;
            if (this.listeners == null) {
                return;
            }
            this.listeners.remove(listener);
        }
        
        void firePropertyChange () {        
            PropertyChangeListener[] _listeners;
            synchronized (this) {
                if (this.listeners == null) {
                    return;
                }
                _listeners = this.listeners.toArray(new PropertyChangeListener[this.listeners.size()]);            
            }
            PropertyChangeEvent event = new PropertyChangeEvent (this,PROP_RESOURCES,null,null);
            for (PropertyChangeListener l : _listeners) {
                l.propertyChange (event);
            }
        }
    }
    
    private class UnknownSourcePathImplementation implements ClassPathImplementation {
        
        private List<PropertyChangeListener> listeners = new CopyOnWriteArrayList<PropertyChangeListener> ();
    
        public List<? extends PathResourceImplementation> getResources() {
            Request request;
            synchronized (GlobalSourcePath.this) {
                if (GlobalSourcePath.this.unknownResources != null) {
                    return GlobalSourcePath.this.unknownResources;
                }
                request = new Request (
                    GlobalSourcePath.this.getTimeStamp(),
                    GlobalSourcePath.this.gpr.getPaths(ClassPath.SOURCE),
                    GlobalSourcePath.this.gpr.getPaths(ClassPath.BOOT), 
                    GlobalSourcePath.this.gpr.getPaths(ClassPath.COMPILE),
                    new HashSet (GlobalSourcePath.this.activeCps),
                    new HashMap (GlobalSourcePath.this.sourceResults),
                    new HashMap<URL, WeakValue> (GlobalSourcePath.this.unknownRoots),
                    GlobalSourcePath.this.listener,
                    GlobalSourcePath.this.listener);
            }
            Result res = createResources (request);
            if (GlobalSourcePath.this.debugCallBack != null) {
                GlobalSourcePath.this.debugCallBack.run();
            }
            synchronized (this) {            
                if (GlobalSourcePath.this.getTimeStamp() == res.timeStamp) {
                    if (GlobalSourcePath.this.binaryResources == null) {
                        GlobalSourcePath.this.resources = res.resources;
                        GlobalSourcePath.this.binaryResources = res.binaryResources;
                        GlobalSourcePath.this.unknownResources = res.unknownResources;
                        GlobalSourcePath.this.activeCps = res.newCps;
                        GlobalSourcePath.this.sourceResults = res.newSR;
                        GlobalSourcePath.this.translatedRoots = res.translatedRoots;                    
                        GlobalSourcePath.this.unknownRoots = res.unknownRoots;
                    }
                    return GlobalSourcePath.this.unknownResources;
                }            
                else {
                    return res.unknownResources;
                }
            }
        }

        public void addPropertyChangeListener(PropertyChangeListener listener) {
            assert listener != null;
            this.listeners.add (listener);
        }

        public void removePropertyChangeListener(PropertyChangeListener listener) {
            assert listener != null;
            this.listeners.remove (listener);
        }
        
        
        void firePropertyChange () {        
            PropertyChangeEvent event = new PropertyChangeEvent (this,PROP_RESOURCES,null,null);
            for (PropertyChangeListener l : this.listeners) {
                l.propertyChange (event);
            }
        }
}
    
    private class BinaryPathImplementation implements ClassPathImplementation {
        private List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();
    
        public List<? extends PathResourceImplementation> getResources() {
            Request request;
            synchronized (GlobalSourcePath.this) {
                if (GlobalSourcePath.this.binaryResources != null) {
                    return GlobalSourcePath.this.binaryResources;
                }
                request = new Request (
                    GlobalSourcePath.this.getTimeStamp(),
                    GlobalSourcePath.this.gpr.getPaths(ClassPath.SOURCE),
                    GlobalSourcePath.this.gpr.getPaths(ClassPath.BOOT), 
                    GlobalSourcePath.this.gpr.getPaths(ClassPath.COMPILE),
                    new HashSet(GlobalSourcePath.this.activeCps),
                    new HashMap(GlobalSourcePath.this.sourceResults),
                    new HashMap<URL, WeakValue> (GlobalSourcePath.this.unknownRoots),
                    GlobalSourcePath.this.listener,
                    GlobalSourcePath.this.listener);
            }
            Result res = createResources (request);
            if (GlobalSourcePath.this.debugCallBack != null) {
                GlobalSourcePath.this.debugCallBack.run();
            }
            synchronized (this) {            
                if (GlobalSourcePath.this.getTimeStamp() == res.timeStamp) {
                    if (GlobalSourcePath.this.binaryResources == null) {
                        GlobalSourcePath.this.resources = res.resources;
                        GlobalSourcePath.this.binaryResources = res.binaryResources;
                        GlobalSourcePath.this.unknownResources = res.unknownResources;
                        GlobalSourcePath.this.activeCps = res.newCps;
                        GlobalSourcePath.this.sourceResults = res.newSR;
                        GlobalSourcePath.this.translatedRoots = res.translatedRoots;                    
                        GlobalSourcePath.this.unknownRoots = res.unknownRoots;
                    }
                    return GlobalSourcePath.this.binaryResources;
                }            
                else {
                    return res.binaryResources;
                }
            }
        }
        
        public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
            assert listener != null;
            if (this.listeners == null) {
                this.listeners = new ArrayList<PropertyChangeListener> ();
            }
            this.listeners.add (listener);        
        }

        public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
            assert listener != null;
            if (this.listeners == null) {
                return;
            }
            this.listeners.remove(listener);
        }
        
        void firePropertyChange () {        
            PropertyChangeListener[] _listeners;
            synchronized (this) {
                if (this.listeners == null) {
                    return;
                }
                _listeners = this.listeners.toArray(new PropertyChangeListener[this.listeners.size()]);            
            }
            PropertyChangeEvent event = new PropertyChangeEvent (this,PROP_RESOURCES,null,null);
            for (PropertyChangeListener l : _listeners) {
                l.propertyChange (event);
            }
        }
    }
    
    
    private class Listener implements GlobalPathRegistryListener, PropertyChangeListener, ChangeListener {
        
            private WeakReference<Object> lastPropagationId;
        
            public void pathsAdded(GlobalPathRegistryEvent event) {
                resetCacheAndFire ();
            }

            public void pathsRemoved(GlobalPathRegistryEvent event) {
                resetCacheAndFire ();
            }        

            public void propertyChange(PropertyChangeEvent evt) {
                String propName = evt.getPropertyName();
                if (ClassPath.PROP_ENTRIES.equals(propName)) {
                    resetCacheAndFire ();
                }
                else if (ClassPath.PROP_INCLUDES.equals(propName)) {
                    PropertyChangeListener _excludesListener;
                    _excludesListener = excludesListener;
                    if (_excludesListener != null) {
                        final Object newPropagationId = evt.getPropagationId();
                        boolean fire;
                        synchronized (this) {
                            fire = (newPropagationId == null || lastPropagationId == null || lastPropagationId.get() != newPropagationId);                                                    
                            lastPropagationId = new WeakReference<Object>(newPropagationId);
                        }                                                
                        if (fire) {
                            PropertyChangeEvent event = new PropertyChangeEvent (GlobalSourcePath.this,PROP_INCLUDES,evt.getSource(),evt.getSource());
                            _excludesListener.propertyChange(event);
                        }
                    }
                }
            }
    
            public void stateChanged (ChangeEvent event) {
                resetCacheAndFire();
            }
    }
    
    private class LibsListener implements PropertyChangeListener {

        public void propertyChange(PropertyChangeEvent evt) {
            synchronized (GlobalSourcePath.this) {
                GlobalSourcePath.this.libsSrcs = null;
            }
        }
        
    }
    
    public static synchronized GlobalSourcePath getDefault () {
        if (instance == null) {
            instance = new GlobalSourcePath ();
        }
        return instance;
    }
    
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.