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.ant.freeform;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
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.WeakHashMap;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.classpath.GlobalPathRegistry;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.java.platform.JavaPlatformManager;
import org.netbeans.api.java.platform.Specification;
import org.netbeans.spi.java.classpath.ClassPathFactory;
import org.netbeans.spi.java.classpath.ClassPathImplementation;
import org.netbeans.spi.java.classpath.ClassPathProvider;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.netbeans.spi.project.AuxiliaryConfiguration;
import org.netbeans.spi.project.support.ant.AntProjectEvent;
import org.netbeans.spi.project.support.ant.AntProjectListener;
import org.netbeans.spi.project.support.ant.PropertyUtils;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.modules.SpecificationVersion;
import org.w3c.dom.Element;

/**
 * Handle classpaths for the freeform project.
 * Keeps three caches:
 * 
    *
  1. Classpaths registered when the project is opened. The same are unregistered * when it is closed again, regardless of what might have changed since. *
  2. A map from abstract compilation units (keyed by the literal text of the * <package-root> elements) to implementations which do the * actual listening and (re-)computation of roots. *
  3. A map from actual package roots to the matching classpath. *
* The complexity here is needed because *
    *
  1. It is necessary to always unregister the exact same set of ClassPath objects * you initially registered (even if some have since become invalid, etc.). * Ideally, adding or removing whole paths would dynamically register or unregister * them (if the project is currently open); the current code does not do this. *
  2. A given ClassPath object must fire changes if its list of roots changes. *
  3. It is necessary to return the same ClassPath object for the same FileObject. *
* @author Jesse Glick */ final class Classpaths implements ClassPathProvider, AntProjectListener, PropertyChangeListener { private final FreeformProject project; /** * Map from classpath types to maps from package roots to classpaths. */ private final Map/*>*/ classpaths = new HashMap(); /** * Map from classpath types to maps from lists of package root names to classpath impls. */ private final Map/*,MutableClassPathImplementation>>*/ mutablePathImpls = new HashMap(); /** * Map from classpath types to sets of classpaths we last registered to GlobalPathRegistry. */ private Map/*>*/ registeredClasspaths = null; public Classpaths(FreeformProject project) { this.project = project; project.helper().addAntProjectListener(this); project.evaluator().addPropertyChangeListener(this); } public synchronized ClassPath findClassPath(FileObject file, String type) { Map/**/ classpathsByType = (Map)classpaths.get(type); if (classpathsByType == null) { classpathsByType = new WeakHashMap(); classpaths.put(type, classpathsByType); } // Check for cached value. Iterator it = classpathsByType.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); FileObject root = (FileObject)entry.getKey(); if (root == file || FileUtil.isParentOf(root, file)) { // Already have it. return (ClassPath)entry.getValue(); } } // Need to create it. AuxiliaryConfiguration aux = (AuxiliaryConfiguration)project.getLookup().lookup(AuxiliaryConfiguration.class); assert aux != null; Element java = aux.getConfigurationFragment("java-data", FreeformProjectType.NS_JAVA, true); // NOI18N if (java == null) { return null; } List/**/ compilationUnits = Util.findSubElements(java); it = compilationUnits.iterator(); while (it.hasNext()) { Element compilationUnitEl = (Element)it.next(); assert compilationUnitEl.getLocalName().equals("compilation-unit") : compilationUnitEl; List/**/ packageRoots = findPackageRoots(project, compilationUnitEl); Iterator it2 = packageRoots.iterator(); while (it2.hasNext()) { FileObject root = (FileObject)it2.next(); if (root == file || FileUtil.isParentOf(root, file)) { // Got it. Compute classpath and cache it (for each root). ClassPath cp = createPath(compilationUnitEl, packageRoots, type); it2 = packageRoots.iterator(); while (it2.hasNext()) { FileObject root2 = (FileObject)it2.next(); classpathsByType.put(root2, cp); } return cp; } } } //WebModule classpath WebModules wms = (WebModules) project.getLookup ().lookup (WebModules.class); if (wms != null) { return wms.findClassPath (file, type); } // Didn't find anything. return null; } /** All classpath types we handle. */ private static final String[] TYPES = { ClassPath.SOURCE, ClassPath.BOOT, ClassPath.EXECUTE, ClassPath.COMPILE, }; /** * Called when project is opened. * Tries to find all compilation units and calculate all the paths needed * for each of them and register them all. */ public synchronized void opened() { if (registeredClasspaths != null) { return; } Map/*>*/ _registeredClasspaths = new HashMap(); for (int i = 0; i < TYPES.length; i++) { String type = TYPES[i]; _registeredClasspaths.put(type, new HashSet()); } AuxiliaryConfiguration aux = (AuxiliaryConfiguration)project.getLookup().lookup(AuxiliaryConfiguration.class); assert aux != null; Element java = aux.getConfigurationFragment("java-data", FreeformProjectType.NS_JAVA, true); // NOI18N if (java == null) { return; } List/**/ compilationUnits = Util.findSubElements(java); Iterator it = compilationUnits.iterator(); while (it.hasNext()) { Element compilationUnitEl = (Element)it.next(); assert compilationUnitEl.getLocalName().equals("compilation-unit") : compilationUnitEl; // For each compilation unit, find the package roots first. List/**/ packageRoots = findPackageRoots(project, compilationUnitEl); for (int i = 0; i < TYPES.length; i++) { String type = TYPES[i]; // Then for each type, collect the classpath (creating it as needed). Map/**/ classpathsByType = (Map)classpaths.get(type); if (classpathsByType == null) { classpathsByType = new WeakHashMap(); classpaths.put(type, classpathsByType); } Set/**/ registeredClasspathsOfType = (Set) _registeredClasspaths.get(type); assert registeredClasspathsOfType != null; // Check if there is already a ClassPath registered to one of these roots. ClassPath cp = null; Iterator it2 = packageRoots.iterator(); while (cp == null && it2.hasNext()) { FileObject root = (FileObject)it2.next(); cp = (ClassPath)classpathsByType.get(root); } if (cp == null) { // Nope. Calculate and register it now. cp = createPath(compilationUnitEl, packageRoots, type); it2 = packageRoots.iterator(); while (it2.hasNext()) { FileObject root = (FileObject)it2.next(); classpathsByType.put(root, cp); } } assert cp != null; registeredClasspathsOfType.add(cp); } } if (Util.err.isLoggable(ErrorManager.INFORMATIONAL)) { Util.err.log("classpaths for " + project.getProjectDirectory() + ": " + classpaths); } // Don't do this before it is calculated, or a runtime error above might corrupt state: this.registeredClasspaths = _registeredClasspaths; // Register all of the classpaths we found. GlobalPathRegistry gpr = GlobalPathRegistry.getDefault(); for (int i = 0; i < TYPES.length; i++) { String type = TYPES[i]; Set/**/ registeredClasspathsOfType = (Set)registeredClasspaths.get(type); gpr.register(type, (ClassPath[])registeredClasspathsOfType.toArray(new ClassPath[registeredClasspathsOfType.size()])); } } /** * Called when project is closed. * Unregisters any previously registered classpaths. */ public synchronized void closed() { if (registeredClasspaths == null) { return; } GlobalPathRegistry gpr = GlobalPathRegistry.getDefault(); for (int i = 0; i < TYPES.length; i++) { String type = TYPES[i]; Set/**/ registeredClasspathsOfType = (Set)registeredClasspaths.get(type); gpr.unregister(type, (ClassPath[])registeredClasspathsOfType.toArray(new ClassPath[registeredClasspathsOfType.size()])); } registeredClasspaths = null; } private static List/**/ findPackageRootNames(Element compilationUnitEl) { List/**/ names = new ArrayList(); Iterator it = Util.findSubElements(compilationUnitEl).iterator(); while (it.hasNext()) { Element e = (Element) it.next(); if (!e.getLocalName().equals("package-root")) { // NOI18N continue; } String location = Util.findText(e); names.add(location); } return names; } private static List/**/ findPackageRoots(FreeformProject project, List/**/ packageRootNames) { List/**/ roots = new ArrayList(packageRootNames.size()); Iterator it = packageRootNames.iterator(); while (it.hasNext()) { String location = (String) it.next(); String locationEval = project.evaluator().evaluate(location); if (locationEval != null) { File locationFile = project.helper().resolveFile(locationEval); FileObject locationFileObject = FileUtil.toFileObject(locationFile); if (locationFileObject != null) { if (FileUtil.isArchiveFile(locationFileObject)) { locationFileObject = FileUtil.getArchiveRoot(locationFileObject); } roots.add(locationFileObject); } } } return roots; } public static List/**/ findPackageRoots(FreeformProject project, Element compilationUnitEl) { return findPackageRoots(project, findPackageRootNames(compilationUnitEl)); } private ClassPath createPath(Element compilationUnitEl, List/**/ packageRoots, String type) { if (type.equals(ClassPath.SOURCE) || type.equals(ClassPath.COMPILE) || type.equals(ClassPath.EXECUTE) || type.equals(ClassPath.BOOT)) { List/**/ packageRootNames = findPackageRootNames(compilationUnitEl); Map/*,MutableClassPathImplementation>*/ mutablePathImplsByType = (Map) mutablePathImpls.get(type); if (mutablePathImplsByType == null) { mutablePathImplsByType = new HashMap(); mutablePathImpls.put(type, mutablePathImplsByType); } MutableClassPathImplementation impl = (MutableClassPathImplementation) mutablePathImplsByType.get(packageRootNames); if (impl == null) { // XXX will it ever not be null? impl = new MutableClassPathImplementation(packageRootNames, type, compilationUnitEl); mutablePathImplsByType.put(packageRootNames, impl); } return ClassPathFactory.createClassPath(impl); } else { // Unknown. return null; } } private List/**/ createSourcePath(List/**/ packageRootNames) { List/**/ roots = new ArrayList(packageRootNames.size()); Iterator it = packageRootNames.iterator(); while (it.hasNext()) { String location = (String) it.next(); String locationEval = project.evaluator().evaluate(location); if (locationEval != null) { File locationFile = project.helper().resolveFile(locationEval); URL root; try { root = locationFile.toURI().toURL(); } catch (MalformedURLException e) { Util.err.notify(e); continue; } if (FileUtil.isArchiveFile(root)) { root = FileUtil.getArchiveRoot(root); } roots.add(root); } } return roots; } private List/**/ createCompileClasspath(Element compilationUnitEl) { Iterator/**/ it = Util.findSubElements(compilationUnitEl).iterator(); while (it.hasNext()) { Element e = (Element)it.next(); if (e.getLocalName().equals("classpath") && e.getAttribute("mode").equals("compile")) { // NOI18N return createClasspath(e); } } // None specified; assume it is empty. return Collections.EMPTY_LIST; } /** * Create a classpath from a <classpath> element. */ private List/**/ createClasspath(Element classpathEl) { String cp = Util.findText(classpathEl); if (cp == null) { cp = ""; } String cpEval = project.evaluator().evaluate(cp); if (cpEval == null) { return null; } String[] path = PropertyUtils.tokenizePath(cpEval); URL[] pathURL = new URL[path.length]; for (int i = 0; i < path.length; i++) { File entryFile = project.helper().resolveFile(path[i]); URL entry; try { entry = entryFile.toURI().toURL(); } catch (MalformedURLException x) { throw new AssertionError(x); } if (FileUtil.isArchiveFile(entry)) { entry = FileUtil.getArchiveRoot(entry); } else { String entryS = entry.toExternalForm(); if (!entryS.endsWith("/")) { // NOI18N // A nonexistent dir. Have to add trailing slash ourselves. try { entry = new URL(entryS + '/'); } catch (MalformedURLException x) { throw new AssertionError(x); } } } pathURL[i] = entry; } return Arrays.asList(pathURL); } private List/**/ createExecuteClasspath(Element compilationUnitEl) { Iterator/**/ it = Util.findSubElements(compilationUnitEl).iterator(); while (it.hasNext()) { Element e = (Element)it.next(); if (e.getLocalName().equals("classpath") && e.getAttribute("mode").equals("execute")) { // NOI18N return createClasspath(e); } } // None specified; assume it is same as compile classpath. // XXX but add built-to dirs return createCompileClasspath(compilationUnitEl); } private List/**/ createBootClasspath(Element compilationUnitEl) { Iterator/**/ it = Util.findSubElements(compilationUnitEl).iterator(); while (it.hasNext()) { Element e = (Element)it.next(); if (e.getLocalName().equals("classpath") && e.getAttribute("mode").equals("boot")) { // NOI18N return createClasspath(e); } } // None specified; try to find a matching Java platform. JavaPlatformManager jpm = JavaPlatformManager.getDefault(); JavaPlatform platform = jpm.getDefaultPlatform(); // fallback it = Util.findSubElements(compilationUnitEl).iterator(); while (it.hasNext()) { Element e = (Element)it.next(); if (e.getLocalName().equals("source-level")) { // NOI18N String level = Util.findText(e); Specification spec = new Specification("j2se", new SpecificationVersion(level)); // NOI18N JavaPlatform[] matchingPlatforms = jpm.getPlatforms(null, spec); if (matchingPlatforms.length > 0) { // Pick one. platform = matchingPlatforms[0]; } break; } } if (platform != null) { // XXX this is not ideal; should try to reuse the ClassPath as is? // The current impl will not listen to changes in the platform classpath correctly. List/**/ entries = platform.getBootstrapLibraries().entries(); List/**/ urls = new ArrayList(entries.size()); Iterator it2 = entries.iterator(); while (it2.hasNext()) { ClassPath.Entry entry = (ClassPath.Entry) it2.next(); urls.add(entry.getURL()); } return urls; } else { assert false : "JavaPlatformManager has no default platform"; return Collections.EMPTY_LIST; } } public void configurationXmlChanged(AntProjectEvent ev) { pathsChanged(); } public void propertiesChanged(AntProjectEvent ev) { // ignore } public void propertyChange(PropertyChangeEvent evt) { pathsChanged(); } private void pathsChanged() { // Not safe, since need to return same ClassPath's where possible. // But might need to check for now-ignored roots? //classpaths.clear(); //System.err.println("pathsChanged: " + mutablePathImpls); Iterator/*,MutableClassPathImplementation>>*/ it1 = mutablePathImpls.values().iterator(); while (it1.hasNext()) { Map/*,MutableClassPathImplementation>*/ m = (Map) it1.next(); Iterator/**/ it2 = m.values().iterator(); while (it2.hasNext()) { MutableClassPathImplementation impl = (MutableClassPathImplementation) it2.next(); impl.change(); } } } /** * Representation of one path. * Listens to changes in project.xml and/or evaluator and responds. */ private final class MutableClassPathImplementation implements ClassPathImplementation { private final List/**/ packageRootNames; private final String type; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private List/**/ roots; // should always be non-null public MutableClassPathImplementation(List/**/ packageRootNames, String type, Element initialCompilationUnit) { this.packageRootNames = packageRootNames; this.type = type; initRoots(initialCompilationUnit); } private Element findCompilationUnit() { AuxiliaryConfiguration aux = (AuxiliaryConfiguration) project.getLookup().lookup(AuxiliaryConfiguration.class); assert aux != null; Element java = aux.getConfigurationFragment("java-data", FreeformProjectType.NS_JAVA, true); // NOI18N if (java == null) { return null; } List/**/ compilationUnits = Util.findSubElements(java); Iterator it = compilationUnits.iterator(); while (it.hasNext()) { Element compilationUnitEl = (Element)it.next(); assert compilationUnitEl.getLocalName().equals("compilation-unit") : compilationUnitEl; if (packageRootNames.equals(findPackageRootNames(compilationUnitEl))) { // Found a matching compilation unit. return compilationUnitEl; } } // Did not find it. return null; } /** * Initialize list of URL roots. */ private void initRoots(Element compilationUnitEl) { if (compilationUnitEl == null) { // Dead. roots = Collections.EMPTY_LIST; return; } if (type.equals(ClassPath.SOURCE)) { roots = createSourcePath(packageRootNames); } else if (type.equals(ClassPath.COMPILE)) { roots = createCompileClasspath(compilationUnitEl); } else if (type.equals(ClassPath.EXECUTE)) { roots = createExecuteClasspath(compilationUnitEl); } else { assert type.equals(ClassPath.BOOT) : type; roots = createBootClasspath(compilationUnitEl); } assert roots != null; } public List/**/ getResources() { List/**/ impls = new ArrayList(roots.size()); Iterator it = roots.iterator(); while (it.hasNext()) { URL root = (URL) it.next(); impls.add(ClassPathSupport.createResource(root)); } return impls; } /** * Notify impl of a possible change in data. */ public void change() { List/**/ oldRoots = roots; initRoots(findCompilationUnit()); if (Util.err.isLoggable(ErrorManager.INFORMATIONAL)) { Util.err.log("MutableClassPathImplementation.change: packageRootNames=" + packageRootNames + " type=" + type + " oldRoots=" + oldRoots + " roots=" + roots); } if (!roots.equals(oldRoots)) { pcs.firePropertyChange(ClassPathImplementation.PROP_RESOURCES, null, null); } } public void addPropertyChangeListener(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { pcs.removePropertyChangeListener(listener); } } }
... 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.