alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 *
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.modules.javacore.classpath;


import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyChangeEvent;
import java.net.URL;
import java.util.*;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileStateInvalidException;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.modules.javacore.Cache;
import org.netbeans.modules.javacore.JMManager;
import org.netbeans.spi.java.classpath.ClassPathImplementation;
import org.netbeans.spi.java.classpath.ClassPathFactory;
import org.netbeans.spi.java.classpath.PathResourceImplementation;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.openide.util.WeakListeners;


/**
 * FilterClassPathImplementation
 * @author Tomas Zezula, Martin Matula
 */
public class FilterClassPathImplementation implements ClassPathImplementation, PropertyChangeListener, Cache.CachedElement {
    
    private static final boolean DEBUG = false;

    private final PropertyChangeSupport support;
    private final Object key;
    private final List resources;
    private boolean isUpToDate = true;
    
    private static HashMap resourceCache = new HashMap();
    private static HashMap instanceMap = new HashMap(15);
    private static HashMap implToCP = new HashMap(15);
    private static Cache cache = new Cache(10);
    private static ClassPath validator;

    private FilterClassPathImplementation(List/**/ original, boolean preferSources) {
        assert original != null && original.size() > 0 : "Array of original classpaths can not be null or empty or contain nulls: " + original;     //NOI18N
        this.support = new PropertyChangeSupport(this);
        this.key = getKey(original, preferSources);
        this.resources = Collections.unmodifiableList(createResources(original, preferSources));
        instanceMap.put(key, this);
    }

    public void release() {
        if (DEBUG) System.err.println("dropping unused classpath: " + key); // NOI18N
        implToCP.remove(this);
        instanceMap.remove(key);
    }
    
    public boolean isValid() {
        return isUpToDate;
    }

    public void propertyChange(PropertyChangeEvent evt) {
        isUpToDate = false;
    }

    public List getResources() {
        return resources;
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        this.support.addPropertyChangeListener (listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        this.support.removePropertyChangeListener (listener);
    }
    
    private List createResources(List/**/ original, boolean preferSources) {
        List list = new ArrayList ();

        if (validator == null) {
            validator = ((JMManager) JMManager.getManager()).getMergedClassPath();
        }
        Set set = new HashSet(Arrays.asList((Object[]) validator.getRoots()));
        Set visited = new HashSet();
        Set added = new HashSet();
        validator.addPropertyChangeListener((PropertyChangeListener) WeakListeners.create(PropertyChangeListener.class, this, validator));
        if (DEBUG) System.err.println("creating resources from paths: "); // NOI18N
        for (int j = 0; j < original.size(); j++) {
            if (DEBUG) System.err.println("    path[" + j + "]"); // NOI18N
            ClassPath origCP = (ClassPath) original.get(j);
            if (origCP == null) continue;
            for (Iterator it = origCP.entries().iterator(); it.hasNext();) {
                ClassPath.Entry entry = (ClassPath.Entry) it.next();
                URL url = entry.getURL();
                if (DEBUG) System.err.println("        root: " + url); // NOI18N
                // if the root is not in the classpath yet, let's try to add it
                if (visited.add(url)) {
                    FileObject root = entry.getRoot();
                    boolean addBinary = false;
                    // check if the root exists and whether the MDR already knows about it - set the force flag if not
                    boolean forceSource = !(root != null && set.contains(root));
                    if (DEBUG) System.err.println("        forceSource=" + forceSource); // NOI18N
                    // try to take all source roots from this root
                    FileObject[] sroots = SourceForBinaryQuery.findSourceRoots (url).getRoots();
                    // if yes, first check if the source roots are read-only - if not, then it is likely that the binary root will change too often
                    // (e.g. during clean, build, compile, etc.)
                    // i.e. in that case it is better to add the source root so that everything is resolved to source elements
                    if (DEBUG) System.err.println("        source roots: " + Arrays.asList((Object[]) sroots)); // NOI18N
                    if (sroots.length > 0 && (set.containsAll(Arrays.asList((Object[]) sroots)) || forceSource)) {
                        for (int i = 0; i < sroots.length; i++) {
                            if (!forceSource || set.contains(sroots[i])) {
                                try {
                                    URL surl = sroots[i].getURL();
                                    if (visited.add(surl)) {
                                        if (preferSources || forceSource || sroots.length != 1 || !surl.getProtocol().equals("jar")) { // NOI18N
                                            // if the source root is not a zip file or there are more than one source roots,
                                            // or forceSource flag is set, sources need to be added to the classpath instead of binaries
                                            PathResourceImplementation resource = (PathResourceImplementation) resourceCache.get(surl);
                                            if (resource == null) {
                                                resource = ClassPathSupport.createResource(surl);
                                            }
                                            resourceCache.put(surl, resource);
                                            list.add(resource);
                                            added.add(surl);
                                            if (DEBUG) System.err.println("        * adding source root: " + surl); // NOI18N
                                        } else {
                                            addBinary = true;
                                        }
                                    } else {
                                        if (!added.contains(surl)) {
                                            addBinary = true;
                                        }
                                    }
                                } catch (FileStateInvalidException fsie) {
                                    //Skip it illegal source root
                                }
                            }
                        }
                    } else {
                        addBinary = true;
                    }
                    if (addBinary && !forceSource) {
                        // the sources for this binary root were not added to the classpath yet -> we will add this root
                        PathResourceImplementation resource = (PathResourceImplementation) resourceCache.get(url);
                        if (resource == null) {
                            resource = ClassPathSupport.createResource(url);
                        }
                        resourceCache.put(url, resource);
                        list.add(resource);
                        if (DEBUG) System.err.println("        * adding root: " + url); // NOI18N
                    }
                }
            }
            origCP.addPropertyChangeListener((PropertyChangeListener) WeakListeners.create(PropertyChangeListener.class, this, origCP));
        }
        return list;
    }
    
    private static Object getKey(List/**/ original, boolean preferSources) {
        StringBuffer buf = new StringBuffer(1024);
        
        ClassPath mergedPath = ((JMManager) JMManager.getManager()).getMergedClassPath();
        for (Iterator it = original.iterator(); it.hasNext();) {
            Object item = it.next();
            if (item == mergedPath) {
                buf.append("Merged");
            } else {
                buf.append(item);
            }
        }
        return buf.toString() + preferSources;
    }

    public static synchronized ClassPath createClassPath(List/**/ original, boolean preferSources) {
        if (DEBUG) System.err.println();
        if (DEBUG) System.err.println("**************** request for classpath"); // NOI18N
        FilterClassPathImplementation instance = (FilterClassPathImplementation) instanceMap.get(getKey(original, preferSources));
        ClassPath result;
        if (instance == null || !instance.isUpToDate) {
            if (DEBUG) System.err.println("classpath does not exist or is not up to date - creating..."); // NOI18N
            if (DEBUG) Thread.dumpStack();
            instance = new FilterClassPathImplementation(original, preferSources);
            result = ClassPathFactory.createClassPath(instance);
            implToCP.put(instance, result);
        } else {
            result = (ClassPath) implToCP.get(instance);
        }
        cache.put(instance);
        return result;
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.