? pcpm.diff Index: j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java =================================================================== RCS file: /cvs/java/j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java,v retrieving revision 1.60 diff -u -r1.60 J2SEProject.java --- j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java 4 Jan 2006 17:48:38 -0000 1.60 +++ j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java 9 May 2006 15:59:46 -0000 @@ -25,9 +25,12 @@ import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectInformation; import org.netbeans.api.project.ProjectManager; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.Sources; import org.netbeans.api.project.ant.AntArtifact; import org.netbeans.modules.java.j2seproject.classpath.ClassPathProviderImpl; import org.netbeans.modules.java.j2seproject.classpath.J2SEProjectClassPathExtender; +import org.netbeans.modules.java.j2seproject.classpath.J2SEProjectClassPathModifier; import org.netbeans.modules.java.j2seproject.queries.CompiledSourceForBinaryQuery; import org.netbeans.modules.java.j2seproject.queries.JavadocForBinaryQueryImpl; import org.netbeans.modules.java.j2seproject.queries.SourceLevelQueryImpl; @@ -144,6 +147,7 @@ private Lookup createLookup(AuxiliaryConfiguration aux) { SubprojectProvider spp = refHelper.createSubprojectProvider(); + final J2SEProjectClassPathModifier cpMod = new J2SEProjectClassPathModifier(this, this.updateHelper, eval, refHelper); return Lookups.fixed(new Object[] { new Info(), aux, @@ -165,7 +169,8 @@ new J2SESharabilityQuery (this.helper, evaluator(), getSourceRoots(), getTestSourceRoots()), //Does not use APH to get/put properties/cfgdata new J2SEFileBuiltQuery (this.helper, evaluator(),getSourceRoots(),getTestSourceRoots()), //Does not use APH to get/put properties/cfgdata new RecommendedTemplatesImpl (this.updateHelper), - new J2SEProjectClassPathExtender(this, this.updateHelper, eval,refHelper), + new J2SEProjectClassPathExtender(cpMod), + cpMod, this, // never cast an externally obtained Project to J2SEProject - use lookup instead new J2SEProjectOperations(this), new J2SEProjectWebServicesSupportProvider() Index: j2seproject/src/org/netbeans/modules/java/j2seproject/classpath/ClassPathProviderImpl.java =================================================================== RCS file: /cvs/java/j2seproject/src/org/netbeans/modules/java/j2seproject/classpath/ClassPathProviderImpl.java,v retrieving revision 1.17 diff -u -r1.17 ClassPathProviderImpl.java --- j2seproject/src/org/netbeans/modules/java/j2seproject/classpath/ClassPathProviderImpl.java 23 Nov 2005 11:00:04 -0000 1.17 +++ j2seproject/src/org/netbeans/modules/java/j2seproject/classpath/ClassPathProviderImpl.java 9 May 2006 15:59:46 -0000 @@ -19,6 +19,7 @@ import java.util.HashMap; import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.project.SourceGroup; import org.netbeans.spi.java.classpath.ClassPathFactory; import org.netbeans.spi.java.classpath.ClassPathProvider; import org.netbeans.spi.java.project.classpath.support.ProjectClassPathSupport; @@ -38,6 +39,12 @@ private static final String DIST_JAR = "dist.jar"; // NOI18N private static final String BUILD_TEST_CLASSES_DIR = "build.test.classes.dir"; // NOI18N + private static final String JAVAC_CLASSPATH = "javac.classpath"; //NOI18N + private static final String JAVAC_TEST_CLASSPATH = "javac.test.classpath"; //NOI18N + private static final String RUN_CLASSPATH = "run.classpath"; //NOI18N + private static final String RUN_TEST_CLASSPATH = "run.test.classpath"; //NOI18N + + private final AntProjectHelper helper; private final File projectDirectory; private final PropertyEvaluator evaluator; @@ -149,12 +156,12 @@ if (type == 0) { cp = ClassPathFactory.createClassPath( ProjectClassPathSupport.createPropertyBasedClassPathImplementation( - projectDirectory, evaluator, new String[] {"javac.classpath"})); // NOI18N + projectDirectory, evaluator, new String[] {JAVAC_CLASSPATH})); // NOI18N } else { cp = ClassPathFactory.createClassPath( ProjectClassPathSupport.createPropertyBasedClassPathImplementation( - projectDirectory, evaluator, new String[] {"javac.test.classpath"})); // NOI18N + projectDirectory, evaluator, new String[] {JAVAC_TEST_CLASSPATH})); // NOI18N } cache[2+type] = cp; } @@ -177,12 +184,12 @@ if (type == 0) { cp = ClassPathFactory.createClassPath( ProjectClassPathSupport.createPropertyBasedClassPathImplementation( - projectDirectory, evaluator, new String[] {"run.classpath"})); // NOI18N + projectDirectory, evaluator, new String[] {RUN_CLASSPATH})); // NOI18N } else if (type == 1) { cp = ClassPathFactory.createClassPath( ProjectClassPathSupport.createPropertyBasedClassPathImplementation( - projectDirectory, evaluator, new String[] {"run.test.classpath"})); // NOI18N + projectDirectory, evaluator, new String[] {RUN_TEST_CLASSPATH})); // NOI18N } else if (type == 2) { //Only to make the CompiledDataNode hapy @@ -269,6 +276,39 @@ public synchronized void propertyChange(PropertyChangeEvent evt) { dirCache.remove(evt.getPropertyName()); + } + + public String getPropertyName (SourceGroup sg, String classPathId) { + FileObject root = sg.getRootFolder(); + FileObject[] path = getPrimarySrcPath(); + for (int i=0; i*/ changed = new ArrayList/**/ (libraries.length); + for (int i=0; i< libraries.length; i++) { + assert libraries[i] != null; + ClassPathSupport.Item item = ClassPathSupport.Item.create( libraries[i], null ); + if (operation == ADD && !resources.contains(item)) { + resources.add (item); + changed.add(item); + } + else if (operation == REMOVE && resources.contains(item)) { + resources.remove(item); + changed.add(item); + } + } + if (!changed.isEmpty()) { + String itemRefs[] = cs.encodeToStrings( resources.iterator() ); + props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH); //PathParser may change the EditableProperties + props.setProperty(classPathProperty, itemRefs); + if (operation == ADD) { + for (Iterator/**/ it = changed.iterator(); it.hasNext();) { + String prop = cs.getLibraryReference( (ClassPathSupport.Item) it.next() ); + prop = prop.substring(2, prop.length()-1); // XXX make a PropertyUtils method for this! + ClassPathSupport.relativizeLibraryClassPath(props, helper.getAntProjectHelper(), prop); + } + } + helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, props); + ProjectManager.getDefault().saveProject(project); + return Boolean.TRUE; + } + return Boolean.FALSE; + } + } + )).booleanValue(); + } catch (MutexException e) { + throw (IOException) e.getException(); + } + } + + private String getClassPathProperty (final SourceGroup sg, final String classPathId) throws UnsupportedOperationException { + assert sg != null : "SourceGroup cannot be null"; //NOI18N + assert classPathId != null : "ClassPathId cannot be null"; //NOI18N + final String classPathProperty = ((ClassPathProviderImpl)project.getLookup().lookup(ClassPathProviderImpl.class)).getPropertyName (sg, classPathId); + if (classPathProperty == null) { + throw new UnsupportedOperationException ("Modification of [" + sg.getRootFolder().getPath() +", " + classPathId + "] is not supported"); //NOI8N + } + return classPathProperty; + } +} Index: j2seproject/test/unit/src/org/netbeans/modules/java/j2seproject/classpath/J2SEProjectClassPathModifierTest.java =================================================================== RCS file: j2seproject/test/unit/src/org/netbeans/modules/java/j2seproject/classpath/J2SEProjectClassPathModifierTest.java diff -N j2seproject/test/unit/src/org/netbeans/modules/java/j2seproject/classpath/J2SEProjectClassPathModifierTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ j2seproject/test/unit/src/org/netbeans/modules/java/j2seproject/classpath/J2SEProjectClassPathModifierTest.java 9 May 2006 15:59:46 -0000 @@ -0,0 +1,352 @@ +/* + * 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-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ +package org.netbeans.modules.java.j2seproject.classpath; + +import java.beans.Customizer; +import java.beans.PropertyChangeListener; +import java.io.OutputStream; +import java.net.URL; +import java.util.Arrays; +import java.util.Collections; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import junit.framework.*; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.List; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.java.project.JavaProjectConstants; +import org.netbeans.api.java.project.classpath.ProjectClassPathModifier; +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.TestUtil; +import org.netbeans.api.project.ant.AntArtifact; +import org.netbeans.api.project.libraries.Library; +import org.netbeans.api.project.libraries.LibraryManager; +import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.java.j2seproject.J2SEProjectGenerator; +import org.netbeans.modules.java.j2seproject.UpdateHelper; +import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties; +import org.netbeans.spi.java.project.classpath.ProjectClassPathExtender; +import org.netbeans.spi.project.ant.AntArtifactProvider; +import org.netbeans.spi.project.libraries.LibraryImplementation; +import org.netbeans.spi.project.libraries.LibraryProvider; +import org.netbeans.spi.project.libraries.LibraryTypeProvider; +import org.netbeans.spi.project.support.ant.AntProjectHelper; +import org.netbeans.spi.project.support.ant.EditableProperties; +import org.netbeans.spi.project.support.ant.PropertyEvaluator; +import org.netbeans.spi.project.support.ant.PropertyUtils; +import org.netbeans.spi.project.support.ant.ReferenceHelper; +import org.openide.ErrorManager; +import org.openide.filesystems.FileLock; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.modules.SpecificationVersion; +import org.openide.util.Lookup; +import org.openide.util.Mutex; +import org.openide.util.MutexException; + +/** + * + * @author tom + */ +public class J2SEProjectClassPathModifierTest extends NbTestCase { + + private FileObject scratch; + private AntProjectHelper helper; + private PropertyEvaluator eval; + private Project prj; + + public J2SEProjectClassPathModifierTest(String testName) { + super(testName); + } + + protected void setUp() throws Exception { + super.setUp(); + TestUtil.setLookup(new Object[] { + new org.netbeans.modules.java.j2seproject.J2SEProjectType(), + new org.netbeans.modules.projectapi.SimpleFileOwnerQueryImplementation(), + new TestLibraryProvider (), + }); + this.scratch = TestUtil.makeScratchDir(this); + FileObject projdir = scratch.createFolder("proj"); //NOI18N + J2SEProjectGenerator.setDefaultSourceLevel(new SpecificationVersion ("1.4")); //NOI18N + this.helper = J2SEProjectGenerator.createProject(FileUtil.toFile(projdir),"proj",null,null); //NOI18N + this.eval = this.helper.getStandardPropertyEvaluator(); + J2SEProjectGenerator.setDefaultSourceLevel(null); + this.prj = FileOwnerQuery.getOwner(projdir); + assertNotNull (this.prj); + } + + protected void tearDown() throws Exception { + } + + public void testAddRemoveRoot () throws Exception { + final FileObject rootFolder = this.scratch.createFolder("Root"); + final FileObject jarFile = this.scratch.createData("archive","jar"); + FileLock lck = jarFile.lock(); + try { + ZipOutputStream jf = new ZipOutputStream (jarFile.getOutputStream(lck)); + try { + jf.putNextEntry(new ZipEntry("Test.properties")); + }finally { + jf.close(); + } + } finally { + lck.releaseLock(); + } + final FileObject jarRoot = FileUtil.getArchiveRoot(jarFile); + ProjectClassPathModifier.Extendable[] extendables = ProjectClassPathModifier.findExtendables(this.prj); + assertNotNull (extendables); + assertEquals(4,extendables.length); + ProjectClassPathModifier.Extendable se=null, te=null; + for (int i=0; i + + + New ProjectClassPathModifier SPI for modification of project's classpath + + + + + + The new SPI interface ProjectClassPathModifier was created to allow extension modules to + add or remove classpath elements (archive files, folders, libraries, subprojects) from the + project's classpath. + + + + + + + Semantic changes in the BrokenReferencesModel.updateReference behavior Index: project/manifest.mf =================================================================== RCS file: /cvs/java/project/manifest.mf,v retrieving revision 1.18 diff -u -r1.18 manifest.mf --- project/manifest.mf 12 Dec 2005 15:40:01 -0000 1.18 +++ project/manifest.mf 9 May 2006 15:59:47 -0000 @@ -2,6 +2,6 @@ OpenIDE-Module: org.netbeans.modules.java.project/1 OpenIDE-Module-Layer: org/netbeans/modules/java/project/layer.xml OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/project/Bundle.properties -OpenIDE-Module-Specification-Version: 1.9 +OpenIDE-Module-Specification-Version: 1.10 OpenIDE-Module-Requires: org.netbeans.modules.project.uiapi.ActionsFactory Index: project/nbproject/project.properties =================================================================== RCS file: /cvs/java/project/nbproject/project.properties,v retrieving revision 1.20 diff -u -r1.20 project.properties --- project/nbproject/project.properties 17 Apr 2006 15:48:42 -0000 1.20 +++ project/nbproject/project.properties 9 May 2006 15:59:47 -0000 @@ -11,6 +11,7 @@ is.autoload=true +javac.source=1.5 javadoc.title=Java Project API javadoc.overview=${basedir}/overview.html javadoc.arch=${basedir}/arch.xml Index: project/src/org/netbeans/api/java/project/classpath/ProjectClassPathModifier.java =================================================================== RCS file: project/src/org/netbeans/api/java/project/classpath/ProjectClassPathModifier.java diff -N project/src/org/netbeans/api/java/project/classpath/ProjectClassPathModifier.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ project/src/org/netbeans/api/java/project/classpath/ProjectClassPathModifier.java 9 May 2006 15:59:47 -0000 @@ -0,0 +1,320 @@ +/* + * 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-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.api.java.project.classpath; + +import java.io.Externalizable; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.ant.AntArtifact; +import org.netbeans.api.project.libraries.Library; +import org.netbeans.modules.java.project.classpath.ProjectClassPathModifierAccessor; +import org.netbeans.spi.java.project.classpath.ProjectClassPathExtender; +import org.netbeans.spi.java.project.classpath.ProjectClassPathModifierImplementation; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.filesystems.URLMapper; + +/** + * An API for project's classpaths modification. + * An client can use this interface to add or remove classpath element (folder, archive, library, subproject) + * from the project's classpath. Not all operations on all project's classpath are supported. The client firstly + * needs to obtain the list of {@link ProjectClassPathModifier#Extendable} representing the compilation unit's + * classpaths which are allowed to change. Then the client may use the Extendable to change the project classpath. + *
+ *

+ * Typical usage would be: + *

+ *
+ * ProjectClassPathModifier.Extendable[] extendables = ProjectClassPathModifier.findExtendables (project);
+ * if (extendables.length > 0) {
+ *   //Select the right extendable - representing ClassPath.COMPILE on the sources
+ *   ProjectClassPathModifier.Extendable extendable = null;
+ *   for (ProjectClassPathModifier.Extendable e : extendables) {
+ *       if (ClassPath.COMPILE.equals(e.getClassPathType()) && (e.getSourceGroup() == null || sources.equals(e.getSourceGroup()))) {
+ *          extendable = e;
+ *          break;
+ *       }
+ *   }
+ *   if (extendable != null) {
+ *      ProjectClassPathModifier.addLibrary (library, extendable);
+ *   }
+ * }
+ * 
+ *
+ * @since org.netbeans.modules.java.project/1 1.10 + */ +public class ProjectClassPathModifier { + + + + private ProjectClassPathModifier () { + + } + + /** + * Returns {@link ProjectClassPathModifier#Extendable}s for given project. An Extendable + * implies a classpath to be extended. Different project type may provide different types + * of Extendable. + * @param project a project for which the Extendable should be found + * @return an array (may be empty) of Extendable, never returns null. In case when the + * project supports the {@link ProjectClassPathModifierImplementation}, the interface is + * used to create the Extendables. If this interface is not provided, but project provides + * the deprecated {@link ProjectClassPathExtender} interface, the single Extendable, which + * {@link ProjectClassPathExtender#Extendable#getSourceGroup} method returns null, is returned. + * In case when neither {@link ProjectClassPathModifierImplementation} nor {@link ProjectClassPathExtender} + * is supported an empty array is returned. + */ + public static Extendable[] findExtendables (final Project project) { + final List/**/ result = new ArrayList/**/(); + final ProjectClassPathModifierImplementation pm = (ProjectClassPathModifierImplementation) project.getLookup().lookup(ProjectClassPathModifierImplementation.class); + if (pm != null) { + final SourceGroup[] sgs = ProjectClassPathModifierAccessor.INSTANCE.getExtendableSourceGroups(pm); + assert sgs != null : "Class: " + pm.getClass() + " returned null as source groups."; //NOI18N + for (int i=0; i< sgs.length; i++) { + final String[] types = ProjectClassPathModifierAccessor.INSTANCE.getExtendableClassPathTypes(pm,sgs[i]); + assert types != null : "Class: " + pm.getClass() + " returned null as classpath types."; //NOI18N + for (int j=0; j