This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 75471
Collapse All | Expand All

(-)j2seproject/src/org/netbeans/modules/java/j2seproject/J2SEProject.java (-1 / +6 lines)
Lines 25-33 Link Here
25
import org.netbeans.api.project.Project;
25
import org.netbeans.api.project.Project;
26
import org.netbeans.api.project.ProjectInformation;
26
import org.netbeans.api.project.ProjectInformation;
27
import org.netbeans.api.project.ProjectManager;
27
import org.netbeans.api.project.ProjectManager;
28
import org.netbeans.api.project.SourceGroup;
29
import org.netbeans.api.project.Sources;
28
import org.netbeans.api.project.ant.AntArtifact;
30
import org.netbeans.api.project.ant.AntArtifact;
29
import org.netbeans.modules.java.j2seproject.classpath.ClassPathProviderImpl;
31
import org.netbeans.modules.java.j2seproject.classpath.ClassPathProviderImpl;
30
import org.netbeans.modules.java.j2seproject.classpath.J2SEProjectClassPathExtender;
32
import org.netbeans.modules.java.j2seproject.classpath.J2SEProjectClassPathExtender;
33
import org.netbeans.modules.java.j2seproject.classpath.J2SEProjectClassPathModifier;
31
import org.netbeans.modules.java.j2seproject.queries.CompiledSourceForBinaryQuery;
34
import org.netbeans.modules.java.j2seproject.queries.CompiledSourceForBinaryQuery;
32
import org.netbeans.modules.java.j2seproject.queries.JavadocForBinaryQueryImpl;
35
import org.netbeans.modules.java.j2seproject.queries.JavadocForBinaryQueryImpl;
33
import org.netbeans.modules.java.j2seproject.queries.SourceLevelQueryImpl;
36
import org.netbeans.modules.java.j2seproject.queries.SourceLevelQueryImpl;
Lines 144-149 Link Here
144
147
145
    private Lookup createLookup(AuxiliaryConfiguration aux) {
148
    private Lookup createLookup(AuxiliaryConfiguration aux) {
146
        SubprojectProvider spp = refHelper.createSubprojectProvider();
149
        SubprojectProvider spp = refHelper.createSubprojectProvider();
150
        final J2SEProjectClassPathModifier cpMod = new J2SEProjectClassPathModifier(this, this.updateHelper, eval, refHelper);
147
        return Lookups.fixed(new Object[] {
151
        return Lookups.fixed(new Object[] {
148
            new Info(),
152
            new Info(),
149
            aux,
153
            aux,
Lines 165-171 Link Here
165
            new J2SESharabilityQuery (this.helper, evaluator(), getSourceRoots(), getTestSourceRoots()), //Does not use APH to get/put properties/cfgdata
169
            new J2SESharabilityQuery (this.helper, evaluator(), getSourceRoots(), getTestSourceRoots()), //Does not use APH to get/put properties/cfgdata
166
            new J2SEFileBuiltQuery (this.helper, evaluator(),getSourceRoots(),getTestSourceRoots()), //Does not use APH to get/put properties/cfgdata
170
            new J2SEFileBuiltQuery (this.helper, evaluator(),getSourceRoots(),getTestSourceRoots()), //Does not use APH to get/put properties/cfgdata
167
            new RecommendedTemplatesImpl (this.updateHelper),
171
            new RecommendedTemplatesImpl (this.updateHelper),
168
            new J2SEProjectClassPathExtender(this, this.updateHelper, eval,refHelper),
172
            new J2SEProjectClassPathExtender(cpMod),
173
            cpMod,
169
            this, // never cast an externally obtained Project to J2SEProject - use lookup instead
174
            this, // never cast an externally obtained Project to J2SEProject - use lookup instead
170
            new J2SEProjectOperations(this),
175
            new J2SEProjectOperations(this),
171
            new J2SEProjectWebServicesSupportProvider()
176
            new J2SEProjectWebServicesSupportProvider()
(-)j2seproject/src/org/netbeans/modules/java/j2seproject/classpath/ClassPathProviderImpl.java (-4 / +44 lines)
Lines 19-24 Link Here
19
import java.util.HashMap;
19
import java.util.HashMap;
20
20
21
import org.netbeans.api.java.classpath.ClassPath;
21
import org.netbeans.api.java.classpath.ClassPath;
22
import org.netbeans.api.project.SourceGroup;
22
import org.netbeans.spi.java.classpath.ClassPathFactory;
23
import org.netbeans.spi.java.classpath.ClassPathFactory;
23
import org.netbeans.spi.java.classpath.ClassPathProvider;
24
import org.netbeans.spi.java.classpath.ClassPathProvider;
24
import org.netbeans.spi.java.project.classpath.support.ProjectClassPathSupport;
25
import org.netbeans.spi.java.project.classpath.support.ProjectClassPathSupport;
Lines 38-43 Link Here
38
    private static final String DIST_JAR = "dist.jar"; // NOI18N
39
    private static final String DIST_JAR = "dist.jar"; // NOI18N
39
    private static final String BUILD_TEST_CLASSES_DIR = "build.test.classes.dir"; // NOI18N
40
    private static final String BUILD_TEST_CLASSES_DIR = "build.test.classes.dir"; // NOI18N
40
    
41
    
42
    private static final String JAVAC_CLASSPATH = "javac.classpath";    //NOI18N
43
    private static final String JAVAC_TEST_CLASSPATH = "javac.test.classpath";  //NOI18N
44
    private static final String RUN_CLASSPATH = "run.classpath";    //NOI18N
45
    private static final String RUN_TEST_CLASSPATH = "run.test.classpath";  //NOI18N
46
    
47
    
41
    private final AntProjectHelper helper;
48
    private final AntProjectHelper helper;
42
    private final File projectDirectory;
49
    private final File projectDirectory;
43
    private final PropertyEvaluator evaluator;
50
    private final PropertyEvaluator evaluator;
Lines 149-160 Link Here
149
            if (type == 0) {
156
            if (type == 0) {
150
                cp = ClassPathFactory.createClassPath(
157
                cp = ClassPathFactory.createClassPath(
151
                    ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
158
                    ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
152
                    projectDirectory, evaluator, new String[] {"javac.classpath"})); // NOI18N
159
                    projectDirectory, evaluator, new String[] {JAVAC_CLASSPATH})); // NOI18N
153
            }
160
            }
154
            else {
161
            else {
155
                cp = ClassPathFactory.createClassPath(
162
                cp = ClassPathFactory.createClassPath(
156
                    ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
163
                    ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
157
                    projectDirectory, evaluator, new String[] {"javac.test.classpath"})); // NOI18N
164
                    projectDirectory, evaluator, new String[] {JAVAC_TEST_CLASSPATH})); // NOI18N
158
            }
165
            }
159
            cache[2+type] = cp;
166
            cache[2+type] = cp;
160
        }
167
        }
Lines 177-188 Link Here
177
            if (type == 0) {
184
            if (type == 0) {
178
                cp = ClassPathFactory.createClassPath(
185
                cp = ClassPathFactory.createClassPath(
179
                    ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
186
                    ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
180
                    projectDirectory, evaluator, new String[] {"run.classpath"})); // NOI18N
187
                    projectDirectory, evaluator, new String[] {RUN_CLASSPATH})); // NOI18N
181
            }
188
            }
182
            else if (type == 1) {
189
            else if (type == 1) {
183
                cp = ClassPathFactory.createClassPath(
190
                cp = ClassPathFactory.createClassPath(
184
                    ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
191
                    ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
185
                    projectDirectory, evaluator, new String[] {"run.test.classpath"})); // NOI18N
192
                    projectDirectory, evaluator, new String[] {RUN_TEST_CLASSPATH})); // NOI18N
186
            }
193
            }
187
            else if (type == 2) {
194
            else if (type == 2) {
188
                //Only to make the CompiledDataNode hapy
195
                //Only to make the CompiledDataNode hapy
Lines 269-274 Link Here
269
276
270
    public synchronized void propertyChange(PropertyChangeEvent evt) {
277
    public synchronized void propertyChange(PropertyChangeEvent evt) {
271
        dirCache.remove(evt.getPropertyName());
278
        dirCache.remove(evt.getPropertyName());
279
    }
280
    
281
    public String getPropertyName (SourceGroup sg, String classPathId) {
282
        FileObject root = sg.getRootFolder();
283
        FileObject[] path = getPrimarySrcPath();
284
        for (int i=0; i<path.length; i++) {
285
            if (root.equals(path[i])) {
286
                if (ClassPath.COMPILE.equals(classPathId)) {
287
                    return JAVAC_CLASSPATH;
288
                }
289
                else if (ClassPath.EXECUTE.equals(classPathId)) {
290
                    return RUN_CLASSPATH;
291
                }
292
                else {
293
                    return null;
294
                }
295
            }
296
        }
297
        path = getTestSrcDir();
298
        for (int i=0; i<path.length; i++) {
299
            if (root.equals(path[i])) {
300
                if (ClassPath.COMPILE.equals(classPathId)) {
301
                    return JAVAC_TEST_CLASSPATH;
302
                }
303
                else if (ClassPath.EXECUTE.equals(classPathId)) {
304
                    return RUN_TEST_CLASSPATH;
305
                }
306
                else {
307
                    return null;
308
                }
309
            }
310
        }
311
        return null;
272
    }
312
    }
273
    
313
    
274
}
314
}
(-)j2seproject/src/org/netbeans/modules/java/j2seproject/classpath/J2SEProjectClassPathExtender.java (-113 / +11 lines)
Lines 15-20 Link Here
15
import java.io.IOException;
15
import java.io.IOException;
16
import java.io.File;
16
import java.io.File;
17
import java.net.URI;
17
import java.net.URI;
18
import java.net.URL;
18
import java.util.List;
19
import java.util.List;
19
import org.netbeans.modules.java.j2seproject.ui.customizer.AntArtifactChooser;
20
import org.netbeans.modules.java.j2seproject.ui.customizer.AntArtifactChooser;
20
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties;
21
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties;
Lines 39-63 Link Here
39
    
40
    
40
    private static final String CP_CLASS_PATH = "javac.classpath"; //NOI18N
41
    private static final String CP_CLASS_PATH = "javac.classpath"; //NOI18N
41
42
42
    private Project project;
43
    private final J2SEProjectClassPathModifier delegate;
43
    private UpdateHelper helper;
44
    private ReferenceHelper refHelper;
45
    private PropertyEvaluator eval;
46
    
47
    
48
    private ClassPathSupport cs;
49
44
50
    public J2SEProjectClassPathExtender (Project project, UpdateHelper helper, PropertyEvaluator eval, ReferenceHelper refHelper) {
45
    public J2SEProjectClassPathExtender (final J2SEProjectClassPathModifier delegate) {
51
        this.project = project;
46
        assert delegate != null;
52
        this.helper = helper;
47
        this.delegate = delegate;
53
        this.eval = eval;
54
        this.refHelper = refHelper;
55
        
56
        this.cs = new ClassPathSupport( eval, refHelper, helper.getAntProjectHelper(), 
57
                                        J2SEProjectProperties.WELL_KNOWN_PATHS, 
58
                                        J2SEProjectProperties.LIBRARY_PREFIX, 
59
                                        J2SEProjectProperties.LIBRARY_SUFFIX, 
60
                                        J2SEProjectProperties.ANT_ARTIFACT_PREFIX );        
61
    }
48
    }
62
49
63
    public boolean addLibrary(final Library library) throws IOException {
50
    public boolean addLibrary(final Library library) throws IOException {
Lines 65-141 Link Here
65
    }
52
    }
66
53
67
    public boolean addLibrary(final String classPathId, final Library library) throws IOException {
54
    public boolean addLibrary(final String classPathId, final Library library) throws IOException {
68
        assert library != null : "Parameter cannot be null";       //NOI18N
55
        return this.delegate.handleLibraries (new Library[] {library},classPathId, J2SEProjectClassPathModifier.ADD);
69
        try {
70
            return ((Boolean)ProjectManager.mutex().writeAccess(
71
                    new Mutex.ExceptionAction () {
72
                        public Object run() throws IOException {
73
                            EditableProperties props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);
74
                            String raw = props.getProperty(classPathId);
75
                            List resources = cs.itemsList( raw );
76
                            ClassPathSupport.Item item = ClassPathSupport.Item.create( library, null );
77
                            if (!resources.contains(item)) {
78
                                resources.add (item);                                
79
                                String itemRefs[] = cs.encodeToStrings( resources.iterator() );                                
80
                                props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);    //PathParser may change the EditableProperties                                
81
                                props.setProperty(classPathId, itemRefs);                                
82
                                String prop = cs.getLibraryReference( item );
83
                                prop = prop.substring(2, prop.length()-1); // XXX make a PropertyUtils method for this!
84
                                ClassPathSupport.relativizeLibraryClassPath(props, helper.getAntProjectHelper(), prop);                                
85
                                helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, props);
86
                                ProjectManager.getDefault().saveProject(project);
87
                                return Boolean.TRUE;
88
                            }
89
                            return Boolean.FALSE;
90
                        }
91
                    }
92
            )).booleanValue();
93
        } catch (MutexException e) {
94
            throw (IOException) e.getException();
95
        }
96
    }
56
    }
97
57
98
    public boolean addArchiveFile(final FileObject archiveFile) throws IOException {
58
    public boolean addArchiveFile(final FileObject archiveFile) throws IOException {
99
        return addArchiveFile(CP_CLASS_PATH,archiveFile);
59
        return addArchiveFile(CP_CLASS_PATH,archiveFile);
100
    }
60
    }
101
61
102
    public boolean addArchiveFile(final String classPathId, final FileObject archiveFile) throws IOException {
62
    public boolean addArchiveFile(final String classPathId, FileObject archiveFile) throws IOException {
103
        assert archiveFile != null : "Parameter cannot be null";       //NOI18N
63
        if (FileUtil.isArchiveFile(archiveFile)) {
104
        try {
64
            archiveFile = FileUtil.getArchiveRoot (archiveFile);
105
            return ((Boolean)ProjectManager.mutex().writeAccess(
106
                    new Mutex.ExceptionAction () {
107
                        public Object run() throws Exception {
108
                            EditableProperties props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);
109
                            String raw = props.getProperty(classPathId);                            
110
                            List resources = cs.itemsList( raw );                                                        
111
                            File f = FileUtil.toFile (archiveFile);
112
                            if (f == null ) {
113
                                throw new IllegalArgumentException ("The file must exist on disk");     //NOI18N
114
                            }
115
                            ClassPathSupport.Item item = ClassPathSupport.Item.create( f, null );
116
117
                            if (!resources.contains(item)) {
118
                                resources.add (item);
119
                                String itemRefs[] = cs.encodeToStrings( resources.iterator() );
120
                                props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);  //PathParser may change the EditableProperties
121
                                props.setProperty(classPathId, itemRefs);
122
                                helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, props);
123
                                ProjectManager.getDefault().saveProject(project);
124
                                return Boolean.TRUE;
125
                            }
126
                            return Boolean.FALSE;
127
                        }
128
                    }
129
            )).booleanValue();
130
        } catch (Exception e) {
131
            if (e instanceof IOException) {
132
                throw (IOException) e;
133
            }
134
            else {
135
                Exception t = new IOException ();
136
                throw (IOException) ErrorManager.getDefault().annotate(t,e);
137
            }
138
        }
65
        }
66
        return this.delegate.handleRoots(new URL[] {archiveFile.getURL()},classPathId,J2SEProjectClassPathModifier.ADD);
139
    }
67
    }
140
68
141
    public boolean addAntArtifact(final AntArtifact artifact, final URI artifactElement) throws IOException {
69
    public boolean addAntArtifact(final AntArtifact artifact, final URI artifactElement) throws IOException {
Lines 143-179 Link Here
143
    }
71
    }
144
72
145
    public boolean addAntArtifact(final String classPathId, final AntArtifact artifact, final URI artifactElement) throws IOException {
73
    public boolean addAntArtifact(final String classPathId, final AntArtifact artifact, final URI artifactElement) throws IOException {
146
        assert artifact != null : "Parameter cannot be null";       //NOI18N
74
        return this.delegate.handleAntArtifacts(new AntArtifact[] {artifact}, new URI[] {artifactElement},classPathId,J2SEProjectClassPathModifier.ADD);
147
        try {
148
            return ((Boolean)ProjectManager.mutex().writeAccess(
149
                    new Mutex.ExceptionAction () {
150
                        public Object run() throws Exception {
151
                            EditableProperties props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);
152
                            String raw = props.getProperty (classPathId);
153
                            List resources = cs.itemsList( raw );
154
                            ClassPathSupport.Item item = ClassPathSupport.Item.create( artifact, artifactElement, null );                            
155
                            if (!resources.contains(item)) {
156
                                resources.add (item);
157
                                String itemRefs[] = cs.encodeToStrings( resources.iterator() );                                
158
                                props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);    //Reread the properties, PathParser changes them
159
                                props.setProperty (classPathId, itemRefs);
160
                                helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, props);
161
                                ProjectManager.getDefault().saveProject(project);
162
                                return Boolean.TRUE;
163
                            }
164
                            return Boolean.FALSE;
165
                        }
166
                    }
167
            )).booleanValue();
168
        } catch (Exception e) {
169
            if (e instanceof IOException) {
170
                throw (IOException) e;
171
            }
172
            else {
173
                Exception t = new IOException ();
174
                throw (IOException) ErrorManager.getDefault().annotate(t,e);
175
            }
176
        }
177
    }
75
    }
178
76
179
}
77
}
(-)j2seproject/src/org/netbeans/modules/java/j2seproject/classpath/J2SEProjectClassPathModifier.java (+276 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 *
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 *
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans.modules.java.j2seproject.classpath;
15
16
import java.beans.PropertyChangeListener;
17
import java.io.File;
18
import java.io.IOException;
19
import java.net.URI;
20
import java.net.URL;
21
import java.util.ArrayList;
22
import java.util.Iterator;
23
import java.util.List;
24
import javax.swing.Icon;
25
import org.netbeans.api.java.classpath.ClassPath;
26
import org.netbeans.api.java.project.JavaProjectConstants;
27
import org.netbeans.api.project.Project;
28
import org.netbeans.api.project.ProjectManager;
29
import org.netbeans.api.project.SourceGroup;
30
import org.netbeans.api.project.Sources;
31
import org.netbeans.api.project.ant.AntArtifact;
32
import org.netbeans.api.project.libraries.Library;
33
import org.netbeans.modules.java.j2seproject.UpdateHelper;
34
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties;
35
import org.netbeans.spi.java.project.classpath.ProjectClassPathModifierImplementation;
36
import org.netbeans.spi.project.support.ant.AntProjectHelper;
37
import org.netbeans.spi.project.support.ant.EditableProperties;
38
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
39
import org.netbeans.spi.project.support.ant.ReferenceHelper;
40
import org.openide.ErrorManager;
41
import org.openide.filesystems.FileObject;
42
import org.openide.filesystems.FileUtil;
43
import org.openide.util.Mutex;
44
import org.openide.util.MutexException;
45
46
/**
47
 *@author Tomas Zezula
48
 *
49
 */
50
public class J2SEProjectClassPathModifier extends ProjectClassPathModifierImplementation {
51
    
52
    static final int ADD = 1;
53
    static final int REMOVE = 2;
54
    
55
    private final Project project;
56
    private final UpdateHelper helper;
57
    private final ReferenceHelper refHelper;
58
    private final PropertyEvaluator eval;    
59
    private final ClassPathSupport cs;    
60
    
61
    /** Creates a new instance of J2SEProjectClassPathModifier */
62
    public J2SEProjectClassPathModifier(final Project project, final UpdateHelper helper, final PropertyEvaluator eval, final ReferenceHelper refHelper) {
63
        assert project != null;
64
        assert helper != null;
65
        assert eval != null;
66
        assert refHelper != null;
67
        this.project = project;
68
        this.helper = helper;
69
        this.eval = eval;
70
        this.refHelper = refHelper;        
71
        this.cs = new ClassPathSupport( eval, refHelper, helper.getAntProjectHelper(), 
72
                                        J2SEProjectProperties.WELL_KNOWN_PATHS, 
73
                                        J2SEProjectProperties.LIBRARY_PREFIX, 
74
                                        J2SEProjectProperties.LIBRARY_SUFFIX, 
75
                                        J2SEProjectProperties.ANT_ARTIFACT_PREFIX );
76
    }
77
    
78
    protected SourceGroup[] getExtendableSourceGroups() {
79
        Sources s = (Sources) this.project.getLookup().lookup(Sources.class);
80
        assert s != null;
81
        return s.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
82
    }
83
    
84
    protected String[] getExtendableClassPathTypes (SourceGroup sg) {
85
        return new String[] {
86
            ClassPath.COMPILE,
87
            ClassPath.EXECUTE
88
        };
89
    }
90
91
    protected boolean removeRoots(final URL[] classPathRoots, final SourceGroup sourceGroup, final String classPathId) throws IOException, UnsupportedOperationException {
92
        return handleRoots (classPathRoots, getClassPathProperty(sourceGroup, classPathId), REMOVE);
93
    }
94
95
    protected boolean addRoots (final URL[] classPathRoots, final SourceGroup sourceGroup, final String classPathId) throws IOException, UnsupportedOperationException {        
96
        return handleRoots (classPathRoots, getClassPathProperty(sourceGroup, classPathId), ADD);
97
    }
98
    
99
    boolean handleRoots (final URL[] classPathRoots, final String classPathProperty, final int operation) throws IOException, UnsupportedOperationException {
100
        assert classPathRoots != null : "The classPathRoots cannot be null";      //NOI18N        
101
        assert classPathProperty != null;
102
        try {
103
            return ((Boolean)ProjectManager.mutex().writeAccess(
104
                    new Mutex.ExceptionAction () {
105
                        public Object run() throws Exception {
106
                            EditableProperties props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);
107
                            String raw = props.getProperty(classPathProperty);                            
108
                            List resources = cs.itemsList( raw );
109
                            boolean changed = false;
110
                            for (int i=0; i< classPathRoots.length; i++) {
111
                                assert classPathRoots[i] != null;
112
                                assert classPathRoots[i].toExternalForm().endsWith("/");    //NOI18N
113
                                URL toAdd = FileUtil.getArchiveFile(classPathRoots[i]);
114
                                if (toAdd == null) {
115
                                    toAdd = classPathRoots[i];
116
                                }
117
                                File f = FileUtil.normalizeFile( new File (URI.create(toAdd.toExternalForm())));
118
                                if (f == null ) {
119
                                    throw new IllegalArgumentException ("The file must exist on disk");     //NOI18N
120
                                }
121
                                ClassPathSupport.Item item = ClassPathSupport.Item.create( f, null );
122
                                if (operation == ADD && !resources.contains(item)) {
123
                                    resources.add (item);
124
                                    changed = true;
125
                                }                            
126
                                else if (operation == REMOVE && resources.contains(item)) {
127
                                    resources.remove(item);
128
                                    changed = true;
129
                                }
130
                            }                                                                                                                
131
                            if (changed) {
132
                                String itemRefs[] = cs.encodeToStrings( resources.iterator() );
133
                                props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);  //PathParser may change the EditableProperties
134
                                props.setProperty(classPathProperty, itemRefs);
135
                                helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, props);
136
                                ProjectManager.getDefault().saveProject(project);
137
                                return Boolean.TRUE;
138
                            }
139
                            return Boolean.FALSE;
140
                        }
141
                    }
142
            )).booleanValue();
143
        } catch (Exception e) {
144
            if (e instanceof IOException) {
145
                throw (IOException) e;
146
            }
147
            else {
148
                Exception t = new IOException ();
149
                throw (IOException) ErrorManager.getDefault().annotate(t,e);
150
            }
151
        }
152
    }
153
154
    protected boolean removeAntArtifacts(final AntArtifact[] artifacts, final URI[] artifactElements, final SourceGroup sourceGroup, final String classPathId) throws IOException, UnsupportedOperationException {
155
        return handleAntArtifacts (artifacts, artifactElements, getClassPathProperty(sourceGroup, classPathId), REMOVE);
156
    }
157
158
    protected boolean addAntArtifacts(final AntArtifact[] artifacts, final URI[] artifactElements, final SourceGroup sourceGroup, final String classPathId) throws IOException, UnsupportedOperationException {
159
        return handleAntArtifacts (artifacts, artifactElements, getClassPathProperty(sourceGroup, classPathId), ADD);
160
    }
161
    
162
    boolean handleAntArtifacts (final AntArtifact[] artifacts, final URI[] artifactElements, final String classPathProperty, final int operation) throws IOException, UnsupportedOperationException {
163
        assert artifacts != null : "Artifacts cannot be null";    //NOI18N
164
        assert artifactElements != null : "ArtifactElements cannot be null";  //NOI18N
165
        assert artifacts.length == artifactElements.length : "Each artifact has to have corresponding artifactElement"; //NOI18N
166
        assert classPathProperty != null;
167
        try {
168
            return ((Boolean)ProjectManager.mutex().writeAccess(
169
                    new Mutex.ExceptionAction () {
170
                        public Object run() throws Exception {
171
                            EditableProperties props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);
172
                            String raw = props.getProperty (classPathProperty);
173
                            List resources = cs.itemsList( raw );
174
                            boolean changed = false;
175
                            for (int i=0; i<artifacts.length; i++) {
176
                                assert artifacts[i] != null;
177
                                assert artifactElements[i] != null;
178
                                ClassPathSupport.Item item = ClassPathSupport.Item.create( artifacts[i], artifactElements[i], null );
179
                                if (operation == ADD && !resources.contains(item)) {
180
                                    resources.add (item);
181
                                    changed = true;
182
                                }
183
                                else if (operation == REMOVE && resources.contains(item)) {
184
                                    resources.remove(item);
185
                                    changed = true;
186
                                }
187
                            }                            
188
                            if (changed) {
189
                                String itemRefs[] = cs.encodeToStrings( resources.iterator() );                                
190
                                props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);    //Reread the properties, PathParser changes them
191
                                props.setProperty (classPathProperty, itemRefs);
192
                                helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, props);
193
                                ProjectManager.getDefault().saveProject(project);
194
                                return Boolean.TRUE;
195
                            }
196
                            return Boolean.FALSE;
197
                        }
198
                    }
199
            )).booleanValue();
200
        } catch (Exception e) {
201
            if (e instanceof IOException) {
202
                throw (IOException) e;
203
            }
204
            else {
205
                Exception t = new IOException ();
206
                throw (IOException) ErrorManager.getDefault().annotate(t,e);
207
            }
208
        }
209
    }
210
    
211
    
212
    protected boolean removeLibraries(final Library[] libraries, final SourceGroup sourceGroup, final String classPathId) throws IOException, UnsupportedOperationException {
213
        return handleLibraries (libraries, getClassPathProperty(sourceGroup, classPathId), REMOVE);
214
    }
215
216
    protected boolean addLibraries(final Library[] libraries, final SourceGroup sourceGroup, final String classPathId) throws IOException, UnsupportedOperationException {
217
        return handleLibraries (libraries, getClassPathProperty(sourceGroup, classPathId), ADD);
218
    }
219
    
220
    boolean handleLibraries (final Library[] libraries, final String classPathProperty, final int operation) throws IOException, UnsupportedOperationException {
221
        assert libraries != null : "Libraries cannot be null";  //NOI18N
222
        assert classPathProperty != null;
223
        try {
224
            return ((Boolean)ProjectManager.mutex().writeAccess(
225
                    new Mutex.ExceptionAction () {
226
                        public Object run() throws IOException {
227
                            EditableProperties props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);
228
                            String raw = props.getProperty(classPathProperty);
229
                            List resources = cs.itemsList( raw );
230
                            List/*<ClassPathSupport.Item>*/ changed = new ArrayList/*<ClassPathSupport.Item>*/ (libraries.length);
231
                            for (int i=0; i< libraries.length; i++) {
232
                                assert libraries[i] != null;
233
                                ClassPathSupport.Item item = ClassPathSupport.Item.create( libraries[i], null );
234
                                if (operation == ADD && !resources.contains(item)) {
235
                                    resources.add (item);                                
236
                                    changed.add(item);
237
                                }
238
                                else if (operation == REMOVE && resources.contains(item)) {
239
                                    resources.remove(item);
240
                                    changed.add(item);
241
                                }
242
                            }
243
                            if (!changed.isEmpty()) {
244
                                String itemRefs[] = cs.encodeToStrings( resources.iterator() );                                
245
                                props = helper.getProperties (AntProjectHelper.PROJECT_PROPERTIES_PATH);    //PathParser may change the EditableProperties                                
246
                                props.setProperty(classPathProperty, itemRefs);                                
247
                                if (operation == ADD) {
248
                                    for (Iterator/*<ClassPathSupport.Item>*/ it = changed.iterator(); it.hasNext();) {
249
                                        String prop = cs.getLibraryReference( (ClassPathSupport.Item) it.next() );
250
                                        prop = prop.substring(2, prop.length()-1); // XXX make a PropertyUtils method for this!
251
                                        ClassPathSupport.relativizeLibraryClassPath(props, helper.getAntProjectHelper(), prop);
252
                                    }
253
                                }
254
                                helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, props);
255
                                ProjectManager.getDefault().saveProject(project);
256
                                return Boolean.TRUE;
257
                            }
258
                            return Boolean.FALSE;
259
                        }
260
                    }
261
            )).booleanValue();
262
        } catch (MutexException e) {
263
            throw (IOException) e.getException();
264
        }
265
    }
266
    
267
    private String getClassPathProperty (final SourceGroup sg, final String classPathId) throws UnsupportedOperationException {
268
        assert sg != null : "SourceGroup cannot be null";  //NOI18N
269
        assert classPathId != null : "ClassPathId cannot be null";  //NOI18N
270
        final String classPathProperty = ((ClassPathProviderImpl)project.getLookup().lookup(ClassPathProviderImpl.class)).getPropertyName (sg, classPathId);
271
        if (classPathProperty == null) {
272
            throw new UnsupportedOperationException ("Modification of [" + sg.getRootFolder().getPath() +", " + classPathId + "] is not supported"); //NOI8N
273
        }
274
        return classPathProperty;
275
    }
276
}
(-)j2seproject/test/unit/src/org/netbeans/modules/java/j2seproject/classpath/J2SEProjectClassPathModifierTest.java (+352 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
package org.netbeans.modules.java.j2seproject.classpath;
14
15
import java.beans.Customizer;
16
import java.beans.PropertyChangeListener;
17
import java.io.OutputStream;
18
import java.net.URL;
19
import java.util.Arrays;
20
import java.util.Collections;
21
import java.util.jar.JarFile;
22
import java.util.jar.JarOutputStream;
23
import java.util.zip.ZipEntry;
24
import java.util.zip.ZipOutputStream;
25
import junit.framework.*;
26
import java.io.File;
27
import java.io.IOException;
28
import java.net.URI;
29
import java.util.List;
30
import org.netbeans.api.java.classpath.ClassPath;
31
import org.netbeans.api.java.project.JavaProjectConstants;
32
import org.netbeans.api.java.project.classpath.ProjectClassPathModifier;
33
import org.netbeans.api.project.FileOwnerQuery;
34
import org.netbeans.api.project.Project;
35
import org.netbeans.api.project.ProjectManager;
36
import org.netbeans.api.project.SourceGroup;
37
import org.netbeans.api.project.Sources;
38
import org.netbeans.api.project.TestUtil;
39
import org.netbeans.api.project.ant.AntArtifact;
40
import org.netbeans.api.project.libraries.Library;
41
import org.netbeans.api.project.libraries.LibraryManager;
42
import org.netbeans.junit.NbTestCase;
43
import org.netbeans.modules.java.j2seproject.J2SEProjectGenerator;
44
import org.netbeans.modules.java.j2seproject.UpdateHelper;
45
import org.netbeans.modules.java.j2seproject.ui.customizer.J2SEProjectProperties;
46
import org.netbeans.spi.java.project.classpath.ProjectClassPathExtender;
47
import org.netbeans.spi.project.ant.AntArtifactProvider;
48
import org.netbeans.spi.project.libraries.LibraryImplementation;
49
import org.netbeans.spi.project.libraries.LibraryProvider;
50
import org.netbeans.spi.project.libraries.LibraryTypeProvider;
51
import org.netbeans.spi.project.support.ant.AntProjectHelper;
52
import org.netbeans.spi.project.support.ant.EditableProperties;
53
import org.netbeans.spi.project.support.ant.PropertyEvaluator;
54
import org.netbeans.spi.project.support.ant.PropertyUtils;
55
import org.netbeans.spi.project.support.ant.ReferenceHelper;
56
import org.openide.ErrorManager;
57
import org.openide.filesystems.FileLock;
58
import org.openide.filesystems.FileObject;
59
import org.openide.filesystems.FileUtil;
60
import org.openide.modules.SpecificationVersion;
61
import org.openide.util.Lookup;
62
import org.openide.util.Mutex;
63
import org.openide.util.MutexException;
64
65
/**
66
 *
67
 * @author tom
68
 */
69
public class J2SEProjectClassPathModifierTest extends NbTestCase {
70
    
71
    private FileObject scratch;
72
    private AntProjectHelper helper;
73
    private PropertyEvaluator eval;
74
    private Project prj;
75
    
76
    public J2SEProjectClassPathModifierTest(String testName) {
77
        super(testName);
78
    }       
79
    
80
    protected void setUp() throws Exception {
81
        super.setUp();
82
        TestUtil.setLookup(new Object[] {
83
            new org.netbeans.modules.java.j2seproject.J2SEProjectType(),
84
            new org.netbeans.modules.projectapi.SimpleFileOwnerQueryImplementation(),
85
            new TestLibraryProvider (),
86
        });
87
        this.scratch = TestUtil.makeScratchDir(this);
88
        FileObject projdir = scratch.createFolder("proj");  //NOI18N
89
        J2SEProjectGenerator.setDefaultSourceLevel(new SpecificationVersion ("1.4"));   //NOI18N    
90
        this.helper = J2SEProjectGenerator.createProject(FileUtil.toFile(projdir),"proj",null,null); //NOI18N
91
        this.eval = this.helper.getStandardPropertyEvaluator();
92
        J2SEProjectGenerator.setDefaultSourceLevel(null);
93
        this.prj = FileOwnerQuery.getOwner(projdir);
94
        assertNotNull (this.prj);
95
    }
96
97
    protected void tearDown() throws Exception {
98
    }
99
    
100
    public void testAddRemoveRoot () throws Exception {        
101
        final FileObject rootFolder = this.scratch.createFolder("Root");
102
        final FileObject jarFile = this.scratch.createData("archive","jar");
103
        FileLock lck = jarFile.lock();
104
        try {
105
            ZipOutputStream jf = new ZipOutputStream (jarFile.getOutputStream(lck));            
106
            try {
107
                jf.putNextEntry(new ZipEntry("Test.properties"));
108
            }finally {
109
                jf.close();
110
            }
111
        } finally {
112
            lck.releaseLock();
113
        }
114
        final FileObject jarRoot = FileUtil.getArchiveRoot(jarFile);        
115
        ProjectClassPathModifier.Extendable[] extendables = ProjectClassPathModifier.findExtendables(this.prj);
116
        assertNotNull (extendables);
117
        assertEquals(4,extendables.length);
118
        ProjectClassPathModifier.Extendable se=null, te=null;
119
        for (int i=0; i<extendables.length; i++) {
120
            if (extendables[i].getSourceGroup().getRootFolder().getName().equals("src") && extendables[i].getClassPathType().equals(ClassPath.COMPILE)) {
121
                se = extendables[i];
122
            }
123
            else if (extendables[i].getSourceGroup().getRootFolder().getName().equals("test") && extendables[i].getClassPathType().equals(ClassPath.EXECUTE)) {
124
                te = extendables[i];
125
            }
126
        }
127
        assertNotNull(se);
128
        assertNotNull(te);
129
        ProjectClassPathModifier.addRoots (new URL[] {rootFolder.getURL()},se);
130
        String cp = this.eval.getProperty("javac.classpath");
131
        assertNotNull (cp);
132
        String[] cpRoots = PropertyUtils.tokenizePath (cp);
133
        assertNotNull (cpRoots);
134
        assertEquals(1,cpRoots.length);
135
        assertEquals(rootFolder,this.helper.resolveFileObject(cpRoots[0]));
136
        ProjectClassPathModifier.removeRoots (new URL[] {rootFolder.getURL()},se);
137
        cp = this.eval.getProperty("javac.classpath");
138
        assertNotNull (cp);
139
        cpRoots = PropertyUtils.tokenizePath (cp);
140
        assertNotNull (cpRoots);
141
        assertEquals(0,cpRoots.length);
142
        ProjectClassPathModifier.addRoots(new URL[] {jarRoot.getURL()},te);
143
        cp = this.eval.getProperty("run.test.classpath");
144
        assertNotNull (cp);
145
        cpRoots = PropertyUtils.tokenizePath (cp);
146
        assertNotNull (cpRoots);
147
        assertEquals(4,cpRoots.length);
148
        assertEquals(this.helper.resolveFileObject(cpRoots[3]),jarFile);
149
    }
150
    
151
    public void testAddRemoveArtifact () throws Exception {
152
        FileObject projdir = scratch.createFolder("libPrj");  //NOI18N
153
        J2SEProjectGenerator.setDefaultSourceLevel(new SpecificationVersion ("1.4"));   //NOI18N    
154
        AntProjectHelper helper = J2SEProjectGenerator.createProject(FileUtil.toFile(projdir),"libProj",null,null); //NOI18N        
155
        J2SEProjectGenerator.setDefaultSourceLevel(null);
156
        Project libPrj = FileOwnerQuery.getOwner(projdir);
157
        assertNotNull (this.prj);
158
        AntArtifactProvider ap = (AntArtifactProvider) libPrj.getLookup().lookup(AntArtifactProvider.class);
159
        AntArtifact[] aas = ap.getBuildArtifacts();
160
        AntArtifact output = null;
161
        for (int i=0; i<aas.length; i++) {
162
            if (JavaProjectConstants.ARTIFACT_TYPE_JAR.equals(aas[i].getType())) {
163
                output = aas[i];
164
                break;
165
            }
166
        }
167
        assertNotNull (output);        
168
        ProjectClassPathModifier.Extendable[] extendables = ProjectClassPathModifier.findExtendables(this.prj);
169
        assertNotNull (extendables);
170
        assertEquals(4,extendables.length);
171
        ProjectClassPathModifier.Extendable se = null;
172
        for (int i=0; i<extendables.length; i++) {
173
            if (extendables[i].getSourceGroup().getRootFolder().getName().equals("src") && extendables[i].getClassPathType().equals(ClassPath.COMPILE)) {
174
                se = extendables[i];
175
                break;
176
            }
177
        }                                
178
        ProjectClassPathModifier.addAntArtifacts(new AntArtifact[] {output}, new URI[] {output.getArtifactLocations()[0]},se);
179
        String cp = this.eval.getProperty("javac.classpath");
180
        assertNotNull (cp);
181
        String[] cpRoots = PropertyUtils.tokenizePath (cp);
182
        assertNotNull (cpRoots);
183
        assertEquals(1,cpRoots.length);
184
        URI projectURI = URI.create(output.getProject().getProjectDirectory().getURL().toExternalForm());
185
        URI expected = projectURI.resolve(output.getArtifactLocations()[0]);
186
        assertEquals(expected,this.helper.resolveFile(cpRoots[0]).toURI());
187
        ProjectClassPathModifier.removeAntArtifacts(new AntArtifact[] {output}, new URI[] {output.getArtifactLocations()[0]},se);
188
        cp = this.eval.getProperty("javac.classpath");
189
        assertNotNull (cp);
190
        cpRoots = PropertyUtils.tokenizePath (cp);
191
        assertNotNull (cpRoots);
192
        assertEquals(0,cpRoots.length);
193
    }
194
    
195
    public void testAddRemoveLibrary () throws Exception {
196
        LibraryProvider lp = (LibraryProvider) Lookup.getDefault().lookup(LibraryProvider.class);
197
        assertNotNull (lp);
198
        LibraryImplementation[] impls = lp.getLibraries();
199
        assertNotNull (impls);
200
        assertEquals(1,impls.length);
201
        FileObject libRoot = this.scratch.createFolder("libRoot");
202
        impls[0].setContent("classpath",Collections.singletonList(libRoot.getURL()));
203
        Library[] libs =LibraryManager.getDefault().getLibraries();
204
        assertNotNull (libs);
205
        assertEquals(1,libs.length);                
206
        ProjectClassPathModifier.Extendable[] extendables = ProjectClassPathModifier.findExtendables(this.prj);
207
        assertNotNull (extendables);
208
        assertEquals(4,extendables.length);
209
        ProjectClassPathModifier.Extendable se = null;
210
        for (int i=0; i<extendables.length; i++) {
211
            if (extendables[i].getSourceGroup().getRootFolder().getName().equals("src") && extendables[i].getClassPathType().equals(ClassPath.COMPILE)) {
212
                se = extendables[i];
213
                break;
214
            }
215
        }        
216
        assertNotNull (se);
217
        ProjectClassPathModifier.addLibraries(libs,se);
218
        String cp = this.eval.getProperty("javac.classpath");
219
        assertNotNull (cp);
220
        String[] cpRoots = PropertyUtils.tokenizePath (cp);
221
        assertNotNull (cpRoots);
222
        assertEquals(1,cpRoots.length);
223
        assertEquals("${libs.Test.classpath}",cpRoots[0]);    //There is no build.properties filled, the libraries are not resolved
224
        ProjectClassPathModifier.removeLibraries(libs,se);
225
        cp = this.eval.getProperty("javac.classpath");
226
        assertNotNull (cp);
227
        cpRoots = PropertyUtils.tokenizePath (cp);
228
        assertNotNull (cpRoots);
229
        assertEquals(0,cpRoots.length);
230
    }
231
    
232
    public void testClassPathExtenderCompatibility () throws Exception {
233
        final FileObject rootFolder = this.scratch.createFolder("Root");
234
        final FileObject jarFile = this.scratch.createData("archive","jar");
235
        FileLock lck = jarFile.lock();
236
        try {
237
            ZipOutputStream jf = new ZipOutputStream (jarFile.getOutputStream(lck));            
238
            try {
239
                jf.putNextEntry(new ZipEntry("Test.properties"));
240
            }finally {
241
                jf.close();
242
            }
243
        } finally {
244
            lck.releaseLock();
245
        }
246
        final FileObject jarRoot = FileUtil.getArchiveRoot(jarFile);
247
        ProjectClassPathExtender extender = (ProjectClassPathExtender) this.prj.getLookup().lookup(ProjectClassPathExtender.class);
248
        assertNotNull (extender);
249
        extender.addArchiveFile(rootFolder);
250
        extender.addArchiveFile(jarFile);
251
        String cp = this.eval.getProperty("javac.classpath");
252
        assertNotNull (cp);
253
        String[] cpRoots = PropertyUtils.tokenizePath (cp);
254
        assertNotNull (cpRoots);
255
        assertEquals(2,cpRoots.length);
256
        assertEquals(rootFolder,this.helper.resolveFileObject(cpRoots[0]));
257
        assertEquals(jarFile,this.helper.resolveFileObject(cpRoots[1]));
258
    }
259
    
260
    
261
    private static class TestLibraryProvider implements LibraryProvider {
262
        
263
        private LibraryImplementation[] libs;
264
        
265
        public void removePropertyChangeListener(PropertyChangeListener listener) {
266
        }
267
268
        public void addPropertyChangeListener(PropertyChangeListener listener) {
269
        }
270
271
        public LibraryImplementation[] getLibraries() {
272
            if (libs == null) {
273
                this.libs = new LibraryImplementation[] { new TestLibrary ("Test")};
274
            }
275
            return this.libs;
276
        }
277
        
278
    }    
279
    
280
    private static class TestLibrary implements LibraryImplementation {
281
        
282
        private String name;
283
        private List cp = Collections.EMPTY_LIST;
284
        private List src = Collections.EMPTY_LIST;
285
        private List jdoc = Collections.EMPTY_LIST;
286
        
287
        public TestLibrary (String name) {
288
            this.name = name;
289
        }
290
        
291
        public void setName(String name) {
292
        }
293
294
        public void setLocalizingBundle(String resourceName) {
295
        }
296
297
        public void setDescription(String text) {
298
        }
299
300
        public List getContent(String volumeType) throws IllegalArgumentException {
301
            if ("classpath".equals(volumeType)) {
302
                return this.cp; 
303
            }
304
            else if ("src".equals(volumeType)) {
305
                return this.src;
306
            }
307
            else if ("jdoc".equals(volumeType)) {
308
                return this.jdoc;
309
            }
310
            throw new IllegalArgumentException ();
311
        }
312
313
        public void removePropertyChangeListener(PropertyChangeListener l) {
314
        }
315
316
        public void addPropertyChangeListener(PropertyChangeListener l) {
317
        }
318
319
        public void setContent(String volumeType, List path) throws IllegalArgumentException {
320
            if ("classpath".equals(volumeType)) {
321
                this.cp = path;
322
            }
323
            else if ("src".equals(volumeType)) {
324
                this.src = path;
325
            }
326
            else if ("jdoc".equals(volumeType)) {
327
                this.jdoc = path;
328
            }
329
            else {
330
                throw new IllegalArgumentException ();
331
            }
332
        }
333
334
        public String getType() {
335
            return "j2se";
336
        }
337
338
        public String getName() {
339
            return this.name;
340
        }
341
342
        public String getLocalizingBundle() {
343
            return null;
344
        }
345
346
        public String getDescription() {
347
            return null;
348
        }
349
        
350
    }
351
    
352
}
(-)project/apichanges.xml (+18 lines)
Lines 77-82 Link Here
77
    <!-- ACTUAL CHANGES BEGIN HERE: -->
77
    <!-- ACTUAL CHANGES BEGIN HERE: -->
78
78
79
    <changes>
79
    <changes>
80
    <change id="ProjectClassPathModifier">
81
        <api name="classpath"/>
82
        <summary>New ProjectClassPathModifier SPI for modification of project's classpath</summary>
83
        <version major="1" minor="10"/>
84
        <date day="3" month="5" year="2006"/>
85
        <author login="tzezula"/>
86
        <compatibility addition="yes"/>
87
        <description>
88
        The new SPI interface ProjectClassPathModifier was created to allow extension modules to
89
        add or remove classpath elements (archive files, folders, libraries, subprojects) from the
90
        project's classpath.
91
        </description>
92
        <class package="org.netbeans.spi.java.project.classpath" name="ProjectClassPathModifier"/>
93
         <issue number="74356"/>
94
         <issue number="75469"/>
95
         <issue number="60852"/>
96
    </change>
97
                                                                                                                                
80
    <change id="BrokenReferencesModel.updateReference">
98
    <change id="BrokenReferencesModel.updateReference">
81
        <api name="general"/>
99
        <api name="general"/>
82
        <summary>Semantic changes in the BrokenReferencesModel.updateReference behavior</summary>
100
        <summary>Semantic changes in the BrokenReferencesModel.updateReference behavior</summary>
(-)project/manifest.mf (-1 / +1 lines)
Lines 2-7 Link Here
2
OpenIDE-Module: org.netbeans.modules.java.project/1
2
OpenIDE-Module: org.netbeans.modules.java.project/1
3
OpenIDE-Module-Layer: org/netbeans/modules/java/project/layer.xml
3
OpenIDE-Module-Layer: org/netbeans/modules/java/project/layer.xml
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/project/Bundle.properties
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/project/Bundle.properties
5
OpenIDE-Module-Specification-Version: 1.9
5
OpenIDE-Module-Specification-Version: 1.10
6
OpenIDE-Module-Requires: org.netbeans.modules.project.uiapi.ActionsFactory
6
OpenIDE-Module-Requires: org.netbeans.modules.project.uiapi.ActionsFactory
7
7
(-)project/nbproject/project.properties (+1 lines)
Lines 11-16 Link Here
11
11
12
is.autoload=true
12
is.autoload=true
13
13
14
javac.source=1.5
14
javadoc.title=Java Project API
15
javadoc.title=Java Project API
15
javadoc.overview=${basedir}/overview.html
16
javadoc.overview=${basedir}/overview.html
16
javadoc.arch=${basedir}/arch.xml
17
javadoc.arch=${basedir}/arch.xml
(-)project/src/org/netbeans/api/java/project/classpath/ProjectClassPathModifier.java (+320 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans.api.java.project.classpath;
15
16
import java.io.Externalizable;
17
import java.io.IOException;
18
import java.net.URI;
19
import java.net.URL;
20
import java.util.ArrayList;
21
import java.util.List;
22
import org.netbeans.api.java.classpath.ClassPath;
23
import org.netbeans.api.project.FileOwnerQuery;
24
import org.netbeans.api.project.Project;
25
import org.netbeans.api.project.SourceGroup;
26
import org.netbeans.api.project.ant.AntArtifact;
27
import org.netbeans.api.project.libraries.Library;
28
import org.netbeans.modules.java.project.classpath.ProjectClassPathModifierAccessor;
29
import org.netbeans.spi.java.project.classpath.ProjectClassPathExtender;
30
import org.netbeans.spi.java.project.classpath.ProjectClassPathModifierImplementation;
31
import org.openide.filesystems.FileObject;
32
import org.openide.filesystems.FileUtil;
33
import org.openide.filesystems.URLMapper;
34
35
/**
36
 * An API for project's classpaths modification.
37
 * An client can use this interface to add or remove classpath element (folder, archive, library, subproject)
38
 * from the project's classpath. Not all operations on all project's classpath are supported. The client firstly
39
 * needs to obtain the list of {@link ProjectClassPathModifier#Extendable} representing the compilation unit's
40
 * classpaths which are allowed to change. Then the client may use the Extendable to change the project classpath.
41
 * <div class="nonnormative">
42
 * <p>
43
 * Typical usage would be:
44
 * </p>
45
 * <pre>
46
 * ProjectClassPathModifier.Extendable[] extendables = ProjectClassPathModifier.findExtendables (project);
47
 * if (extendables.length > 0) {
48
 *   //Select the right extendable - representing ClassPath.COMPILE on the sources
49
 *   ProjectClassPathModifier.Extendable extendable = null;
50
 *   for (ProjectClassPathModifier.Extendable e : extendables) {
51
 *       if (ClassPath.COMPILE.equals(e.getClassPathType()) && (e.getSourceGroup() == null || sources.equals(e.getSourceGroup()))) {
52
 *          extendable = e;
53
 *          break;
54
 *       }
55
 *   }
56
 *   if (extendable != null) {
57
 *      ProjectClassPathModifier.addLibrary (library, extendable);
58
 *   }
59
 * }
60
 * </pre>
61
 * </div>
62
 * @since org.netbeans.modules.java.project/1 1.10
63
 */
64
public class ProjectClassPathModifier {
65
    
66
    
67
    
68
    private ProjectClassPathModifier () {
69
        
70
    }
71
    
72
    /**
73
     * Returns {@link ProjectClassPathModifier#Extendable}s for given project. An Extendable
74
     * implies a classpath to be extended. Different project type may provide different types
75
     * of Extendable.
76
     * @param project a project for which the Extendable should be found
77
     * @return an array (may be empty) of Extendable, never returns null. In case when the
78
     * project supports the {@link ProjectClassPathModifierImplementation}, the interface is
79
     * used to create the Extendables. If this interface is not provided, but project provides
80
     * the deprecated {@link ProjectClassPathExtender} interface, the single Extendable, which
81
     * {@link ProjectClassPathExtender#Extendable#getSourceGroup} method returns null, is returned.
82
     * In case when neither {@link ProjectClassPathModifierImplementation} nor {@link ProjectClassPathExtender}
83
     * is supported an empty array is returned.
84
     */
85
    public static Extendable[] findExtendables (final Project project) {
86
        final List/*<Extendable>*/ result = new ArrayList/*<Externalizable>*/();
87
        final ProjectClassPathModifierImplementation pm = (ProjectClassPathModifierImplementation) project.getLookup().lookup(ProjectClassPathModifierImplementation.class);
88
        if (pm != null) {            
89
            final SourceGroup[] sgs = ProjectClassPathModifierAccessor.INSTANCE.getExtendableSourceGroups(pm);
90
            assert sgs != null   : "Class: " + pm.getClass() + " returned null as source groups.";    //NOI18N
91
            for (int i=0; i< sgs.length; i++) {
92
                final String[] types = ProjectClassPathModifierAccessor.INSTANCE.getExtendableClassPathTypes(pm,sgs[i]);
93
                assert types != null : "Class: " + pm.getClass() + " returned null as classpath types.";    //NOI18N
94
                for (int j=0; j<types.length; j++) {
95
                    result.add (new Extendable (pm, sgs[i], types[j]));
96
                }
97
            }
98
        }
99
        else {
100
            final ProjectClassPathExtender pe = (ProjectClassPathExtender) project.getLookup().lookup(ProjectClassPathExtender.class);
101
            if (pe != null) {
102
                result.add (new Extendable (pe));
103
            }
104
        }
105
        return (Extendable[]) result.toArray(new Extendable[result.size()]);
106
    }
107
    
108
    /**
109
     * Adds libraries into the project's classpath if the
110
     * libraries are not already included.
111
     * @param libraries to be added
112
     * @param extendable to add the libraries into.
113
     * @return true in case the classpath was changed (at least one library was added to the classpath),
114
     * the value false is returned when all the libraries are already included on the classpath.
115
     * @exception IOException in case the project metadata cannot be changed
116
     * @exception UnsupportedOperationException is thrown when the project does not support
117
     * adding of a library to the classpath of the given id.
118
     */
119
    public static boolean addLibraries (final Library[] libraries, final Extendable extendable) throws IOException, UnsupportedOperationException {
120
        if (extendable.pcmi != null) {
121
            assert extendable.sg != null;
122
            assert extendable.classPathType != null;
123
            return ProjectClassPathModifierAccessor.INSTANCE.addLibraries (libraries, extendable.pcmi, extendable.sg, extendable.classPathType);
124
        }
125
        else if (extendable.pcpe != null) {
126
            boolean result = false;
127
            for (int i=0; i< libraries.length; i++) {
128
                result |= extendable.pcpe.addLibrary (libraries[i]);
129
            }
130
            return result;
131
        }
132
        throw new UnsupportedOperationException ();
133
    }
134
    
135
    
136
    /**
137
     * Removes libraries from the project's classpath if the
138
     * libraries are included on it.
139
     * @param libraries to be removed
140
     * @param extendable to remove the libraries from
141
     * @return true in case the classpath was changed, (at least one library was removed from the classpath),
142
     * the value false is returned when none of the libraries was included on the classpath.
143
     * @exception IOException in case the project metadata cannot be changed
144
     * @exception UnsupportedOperationException is thrown when the project does not support
145
     * removing of a library from the classpath of the given id.
146
     */
147
    public static boolean removeLibraries (final Library[] libraries, final Extendable extendable) throws IOException, UnsupportedOperationException {
148
        if (extendable.pcmi != null) {
149
            assert extendable.sg != null;
150
            assert extendable.classPathType != null;
151
            return ProjectClassPathModifierAccessor.INSTANCE.removeLibraries (libraries, extendable.pcmi, extendable.sg, extendable.classPathType);
152
        }
153
        throw new UnsupportedOperationException ();
154
    }
155
    
156
    /**
157
     * Adds archive files or folders into the project's classpath if the
158
     * entries are not already there.
159
     * @param classPathRoots roots to be added, each root has to be either a root of an archive or a folder
160
     * @param extendable to add the classPathRoots into.
161
     * @return true in case the classpath was changed, (at least one classpath root was added to the classpath),
162
     * the value false is returned when all the classpath roots are already included on the classpath.
163
     * @exception IOException in case the project metadata cannot be changed
164
     * @exception UnsupportedOperationException is thrown when the project does not support
165
     * adding of a root to the classpath of the given id.
166
     */
167
    public static boolean addRoots (final URL[] classPathRoots, final Extendable extendable) throws IOException, UnsupportedOperationException {
168
        if (extendable.pcmi != null) {
169
            assert extendable.sg != null;
170
            assert extendable.classPathType != null;
171
            return ProjectClassPathModifierAccessor.INSTANCE.addRoots (classPathRoots, extendable.pcmi, extendable.sg, extendable.classPathType);
172
        }
173
        else if (extendable.pcpe != null) {
174
            boolean result = false;
175
            for (int i=0; i< classPathRoots.length; i++) {
176
                URL urlToAdd = classPathRoots[i];
177
                if ("jar".equals(urlToAdd.getProtocol())) {
178
                    urlToAdd = FileUtil.getArchiveFile (urlToAdd);
179
                }
180
                final FileObject fo = URLMapper.findFileObject(urlToAdd);
181
                if (fo == null) {
182
                    throw new UnsupportedOperationException ("Adding of a non existent root is not supported by project.");  //NOI18N
183
                }
184
                result |= extendable.pcpe.addArchiveFile (fo);
185
            }
186
            return result;
187
        }
188
        throw new UnsupportedOperationException ();
189
    }
190
    
191
    /**
192
     * Removes archive files or folders from the project's classpath if the
193
     * entries are included on it.
194
     * @param classPathRoots roots to be removed, each root has to be either a root of an archive or a folder
195
     * @param extendable to remove the classPathRoots from
196
     * @return true in case the classpath was changed, (at least one classpath root was removed from the classpath),
197
     * the value false is returned when none of the classpath roots was included on the classpath.
198
     * @exception IOException in case the project metadata cannot be changed
199
     * @exception UnsupportedOperationException is thrown when the project does not support
200
     * removing of a root from the classpath of the given id.
201
     */
202
    public static boolean removeRoots (final URL[] classPathRoots, final Extendable extendable) throws IOException, UnsupportedOperationException {
203
        if (extendable.pcmi != null) {
204
            assert extendable.sg != null;
205
            assert extendable.classPathType != null;
206
            return ProjectClassPathModifierAccessor.INSTANCE.removeRoots (classPathRoots, extendable.pcmi, extendable.sg, extendable.classPathType);
207
        }
208
        throw new UnsupportedOperationException ();
209
    }
210
    
211
    /**
212
     * Adds artifacts (e.g. subprojects) into project's classpath if the
213
     * artifacts are not already on it.
214
     * @param artifacts to be added
215
     * @param artifactElements the URIs of the build output, the artifactElements has to have the same length
216
     * as artifacts. 
217
     * (must be owned by the artifact and be relative to it)
218
     * @param extendable to add the artifacts into.     
219
     * @return true in case the classpath was changed, (at least one artifact was added to the classpath),
220
     * the value false is returned when all the artifacts are already included on the classpath.
221
     * @exception IOException in case the project metadata cannot be changed
222
     * @exception UnsupportedOperationException is thrown when the project does not support
223
     * adding of an artifact to the classpath of the given id.
224
     */
225
    public static boolean addAntArtifacts (final AntArtifact[] artifacts, final URI[] artifactElements, final Extendable extendable) throws IOException, UnsupportedOperationException {
226
        assert artifacts.length == artifactElements.length;
227
        if (extendable.pcmi != null) {
228
            assert extendable.sg != null;
229
            assert extendable.classPathType != null;
230
            return ProjectClassPathModifierAccessor.INSTANCE.addAntArtifacts (artifacts, artifactElements, extendable.pcmi, extendable.sg, extendable.classPathType);
231
        }
232
        else if (extendable.pcpe != null) {
233
            boolean result = false;
234
            for (int i=0; i< artifacts.length; i++) {
235
                result |= extendable.pcpe.addAntArtifact (artifacts[i], artifactElements[i]);
236
            }
237
            return result;
238
        }
239
        throw new UnsupportedOperationException ();
240
    }
241
    
242
    /**
243
     * Removes artifacts (e.g. subprojects) from project's classpath if the
244
     * artifacts are included on it.
245
     * @param artifacts to be added
246
     * @param artifactElements the URIs of the build output, the artifactElements has to have the same length
247
     * as artifacts.
248
     * (must be owned by the artifact and be relative to it)
249
     * @param extendable to remove the artifacts from
250
     * @return true in case the classpath was changed, (at least one artifact was removed from the classpath),
251
     * the value false is returned when none of the artifacts was included on the classpath.
252
     * @exception IOException in case the project metadata cannot be changed
253
     * @exception UnsupportedOperationException is thrown when the project does not support
254
     * removing of an artifact from the classpath of the given id.
255
     */
256
    public static boolean removeAntArtifacts (final AntArtifact[] artifacts, final URI[] artifactElements, final Extendable extendable) throws IOException, UnsupportedOperationException {
257
        if (extendable.pcmi != null) {
258
            assert extendable.sg != null;
259
            assert extendable.classPathType != null;
260
            return ProjectClassPathModifierAccessor.INSTANCE.removeAntArtifacts (artifacts, artifactElements, extendable.pcmi, extendable.sg, extendable.classPathType);
261
        }
262
        throw new UnsupportedOperationException ();
263
    }
264
    
265
    
266
    
267
    /**
268
     * Extendable represents a classpath which may be changed by the
269
     * {@link ProjectClassPathModifier}. It encapsulates the compilation
270
     * unit and class path type, @see ClassPath.
271
     */
272
    public static final class Extendable {
273
        
274
        private final String classPathType;       
275
        private final SourceGroup sg;
276
        private final ProjectClassPathModifierImplementation pcmi;
277
        private final ProjectClassPathExtender pcpe;
278
        
279
        
280
        private Extendable (final ProjectClassPathModifierImplementation pcmi , final SourceGroup sg, final String classPathType) {
281
            assert pcmi != null;
282
            assert sg != null;
283
            assert classPathType != null;
284
            this.pcmi = pcmi;
285
            this.sg = sg;
286
            this.classPathType = classPathType;
287
            this.pcpe = null;
288
        }
289
        
290
        private Extendable (final ProjectClassPathExtender pcpe) {
291
            assert pcpe != null;
292
            this.pcpe = pcpe;
293
            this.pcmi = null;
294
            this.sg = null;
295
            this.classPathType = ClassPath.COMPILE;
296
        }        
297
298
        /**
299
         *Returns the type of classpath which may be changed by the
300
         *{@link ProjectClassPathModifier}, @see ClassPath.
301
         * @return the classpath type, never returns null
302
         */
303
        public String getClassPathType() {
304
            return this.classPathType;
305
        }
306
        
307
        /**
308
         * Returns the {@link SourceGroup} representing the
309
         * compilation unit which classpath may be changed by {@link ProjectClassPathModifier}
310
         * or null in the case when the project does not support compilation unit sensitive
311
         * classpath modification, in other words the project does not support {@link ProjectClassPathModifierImplementation}
312
         * interface but it provides the deprecated {@link ProjectClassPathExtender} interface.
313
         * @return the {@link SourceGroup} or null
314
         */
315
        public SourceGroup getSourceGroup () {
316
            return this.sg;
317
        }
318
    }    
319
320
}
(-)project/src/org/netbeans/modules/java/project/classpath/ProjectClassPathModifierAccessor.java (+63 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans.modules.java.project.classpath;
15
16
import java.io.IOException;
17
import java.net.URI;
18
import java.net.URL;
19
import org.netbeans.api.java.project.classpath.ProjectClassPathModifier;
20
import org.netbeans.api.project.SourceGroup;
21
import org.netbeans.api.project.ant.AntArtifact;
22
import org.netbeans.api.project.libraries.Library;
23
import org.netbeans.spi.java.project.classpath.ProjectClassPathModifierImplementation;
24
import org.openide.ErrorManager;
25
26
/**
27
 *
28
 * @author tom
29
 */
30
public abstract class ProjectClassPathModifierAccessor {
31
    
32
    public static ProjectClassPathModifierAccessor INSTANCE;
33
    
34
    static {
35
        Class c = ProjectClassPathModifierImplementation.class;
36
        try {
37
            Class.forName (c.getName(), true, c.getClassLoader());
38
        } catch (Exception ex) {
39
            ErrorManager.getDefault().notify(ex);
40
        }
41
    }
42
    
43
    /** Creates a new instance of ProjectClassPathModifierAccessor */
44
    public ProjectClassPathModifierAccessor() {
45
    }
46
    
47
    public abstract SourceGroup[] getExtendableSourceGroups (ProjectClassPathModifierImplementation m);
48
    
49
    public abstract String[] getExtendableClassPathTypes (ProjectClassPathModifierImplementation m, SourceGroup sg);
50
    
51
    public abstract boolean addLibraries (Library[] libraries, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
52
                
53
    public abstract boolean removeLibraries (Library[] libraries, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
54
        
55
    public abstract boolean addRoots (URL[] classPathRoots, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
56
       
57
    public abstract boolean removeRoots (URL[] classPathRoots, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
58
    
59
    public abstract boolean addAntArtifacts (AntArtifact[] artifacts, URI[] artifactElements, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
60
61
    public abstract boolean removeAntArtifacts (AntArtifact[] artifacts, URI[] artifactElements, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
62
    
63
}
(-)project/src/org/netbeans/spi/java/project/classpath/ProjectClassPathExtender.java (-2 / +6 lines)
Lines 24-32 Link Here
24
 * A project can provide this interface in its {@link org.netbeans.api.project.Project#getLookup lookup} to
24
 * A project can provide this interface in its {@link org.netbeans.api.project.Project#getLookup lookup} to
25
 * allow clients to extend its compilation classpath
25
 * allow clients to extend its compilation classpath
26
 * by a new classpath element (JAR, folder, dependent project, or library).
26
 * by a new classpath element (JAR, folder, dependent project, or library).
27
 * @since org.netbeans.modules.java.project/1 1.3 
27
 * @since org.netbeans.modules.java.project/1 1.3
28
 * @deprecated Please use the {@link ProjectClassPathModifier} instead.
28
 */
29
 */
29
public interface ProjectClassPathExtender {
30
public @Deprecated interface ProjectClassPathExtender {
30
31
31
    /**
32
    /**
32
     * Adds a library into the project's compile classpath if the
33
     * Adds a library into the project's compile classpath if the
Lines 34-39 Link Here
34
     * @param library to be added
35
     * @param library to be added
35
     * @return true in case the classpath was changed
36
     * @return true in case the classpath was changed
36
     * @exception IOException in case the project metadata cannot be changed
37
     * @exception IOException in case the project metadata cannot be changed
38
     * @deprecated Please use {@link ProjectClassPathModifier#addLibrary} instead.
37
     */
39
     */
38
    boolean addLibrary(Library library) throws IOException;
40
    boolean addLibrary(Library library) throws IOException;
39
41
Lines 43-48 Link Here
43
     * @param archiveFile ZIP/JAR file to be added
45
     * @param archiveFile ZIP/JAR file to be added
44
     * @return true in case the classpath was changed
46
     * @return true in case the classpath was changed
45
     * @exception IOException in case the project metadata cannot be changed
47
     * @exception IOException in case the project metadata cannot be changed
48
     * @deprecated Please use {@link ProjectClassPathModifier#addArchive} instead.
46
     */
49
     */
47
    boolean addArchiveFile(FileObject archiveFile) throws IOException;
50
    boolean addArchiveFile(FileObject archiveFile) throws IOException;
48
51
Lines 54-59 Link Here
54
     *                        (must be owned by the artifact and be relative to it)
57
     *                        (must be owned by the artifact and be relative to it)
55
     * @return true in case the classpath was changed
58
     * @return true in case the classpath was changed
56
     * @exception IOException in case the project metadata cannot be changed
59
     * @exception IOException in case the project metadata cannot be changed
60
     * @deprecated Please use {@link ProjectClassPathModifier#addAntArtifact} instead.
57
     */
61
     */
58
    boolean addAntArtifact(AntArtifact artifact, URI artifactElement) throws IOException;
62
    boolean addAntArtifact(AntArtifact artifact, URI artifactElement) throws IOException;
59
63
(-)project/src/org/netbeans/spi/java/project/classpath/ProjectClassPathModifierImplementation.java (+205 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 *
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 *
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans.spi.java.project.classpath;
15
16
import java.io.IOException;
17
import java.net.URI;
18
import java.net.URL;
19
import org.netbeans.api.project.SourceGroup;
20
import org.netbeans.api.project.ant.AntArtifact;
21
import org.netbeans.api.project.libraries.Library;
22
import org.netbeans.modules.java.project.classpath.ProjectClassPathModifierAccessor;
23
import org.openide.filesystems.FileObject;
24
25
/**
26
 * An SPI for project's classpaths modification.
27
 * A project can provide subclass of this class in its {@link org.netbeans.api.project.Project#getLookup lookup} to
28
 * allow clients to add or remove new classpath elements (JAR, folder, dependent project, or library) to its 
29
 * classpaths.
30
 * @since org.netbeans.modules.java.project/1 1.10
31
 */
32
public abstract class ProjectClassPathModifierImplementation {
33
    
34
    static {
35
        ProjectClassPathModifierAccessor.INSTANCE = new Accessor ();
36
    }    
37
    
38
    protected ProjectClassPathModifierImplementation () {
39
    }
40
    
41
    
42
    /**
43
     * Returns the {@link SourceGroup}s providing classpath(s)
44
     * which may be modified.
45
     * @return (possibly empty) array of {@link SourceGroup}, never returns null
46
     */
47
    protected abstract SourceGroup [] getExtendableSourceGroups ();
48
    
49
    
50
    /**
51
     * Returns the types of classpaths for given {@link SourceGroup} which may be modified.
52
     * @param sourceGroup for which the classpath types should be returned
53
     * @return (possibly empty) array of classpath types, never returns null
54
     */
55
    protected abstract String[] getExtendableClassPathTypes (SourceGroup sourceGroup);
56
            
57
    /**
58
     * Adds libraries into the project's classpath if the
59
     * libraries are not already included.
60
     * @param libraries to be added
61
     * @param sourceGroup of type {@link org.netbeans.api.java.project.JavaProjectConstants#SOURCES_TYPE_JAVA}
62
     * identifying the compilation unit to change
63
     * @param type the type of the classpath the library should be added to,
64
     * eg {@link org.netbeans.api.java.classpath.ClassPath.COMPILE}
65
     * @return true in case the classpath was changed (at least one library was added to the classpath),
66
     * the value false is returned when all the libraries are already included on the classpath.
67
     * @exception IOException in case the project metadata cannot be changed
68
     * @exception UnsupportedOperationException is thrown when the project does not support
69
     * adding of a library to the classpath of the given id.
70
     */
71
    protected abstract boolean addLibraries (Library[] libraries, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
72
    
73
    
74
    /**
75
     * Removes libraries from the project's classpath if the
76
     * libraries are included on it.
77
     * @param libraries to be removed
78
     * @param sourceGroup of type {@link org.netbeans.api.java.project.JavaProjectConstants#SOURCES_TYPE_JAVA}
79
     * identifying the compilation unit to change
80
     * @param type the type of the classpath the library should be removed from,
81
     * eg {@link org.netbeans.api.java.classpath.ClassPath.COMPILE}
82
     * @return true in case the classpath was changed, (at least one library was removed from the classpath),
83
     * the value false is returned when none of the libraries was included on the classpath.
84
     * @exception IOException in case the project metadata cannot be changed
85
     * @exception UnsupportedOperationException is thrown when the project does not support
86
     * removing of a library from the classpath of the given id.
87
     */
88
    protected abstract boolean removeLibraries (Library[] libraries, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
89
    
90
    /**
91
     * Adds archive files or folders into the project's classpath if the
92
     * entries are not already there.
93
     * @param classPathRoots roots to be added, each root has to be either a root of an archive or a folder
94
     * @param sourceGroup of type {@link org.netbeans.api.java.project.JavaProjectConstants#SOURCES_TYPE_JAVA}
95
     * identifying the compilation unit to change
96
     * @param type the type of the classpath the root should be added to,
97
     * eg {@link org.netbeans.api.java.classpath.ClassPath.COMPILE}
98
     * @return true in case the classpath was changed, (at least one classpath root was added to the classpath),
99
     * the value false is returned when all the classpath roots are already included on the classpath.
100
     * @exception IOException in case the project metadata cannot be changed
101
     * @exception UnsupportedOperationException is thrown when the project does not support
102
     * adding of a root to the classpath of the given id.
103
     */
104
    protected abstract boolean addRoots (URL[] classPathRoots, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
105
    
106
    /**
107
     * Removes archive files or folders from the project's classpath if the
108
     * entries are included on it.
109
     * @param classPathRoots roots to be removed, each root has to be either a root of an archive or a folder
110
     * @param sourceGroup of type {@link org.netbeans.api.java.project.JavaProjectConstants#SOURCES_TYPE_JAVA}
111
     * identifying the compilation unit to change
112
     * @param type the type of the classpath the root should be removed from,
113
     * eg {@link org.netbeans.api.java.classpath.ClassPath.COMPILE}
114
     * @return true in case the classpath was changed, (at least one classpath root was removed from the classpath),
115
     * the value false is returned when none of the classpath roots was included on the classpath.
116
     * @exception IOException in case the project metadata cannot be changed
117
     * @exception UnsupportedOperationException is thrown when the project does not support
118
     * removing of a root from the classpath of the given id.
119
     */
120
    protected abstract boolean removeRoots (URL[] classPathRoots, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
121
    
122
    /**
123
     * Adds artifacts (e.g. subprojects) into project's classpath if the
124
     * artifacts are not already on it.
125
     * @param artifacts to be added
126
     * @param artifactElements the URIs of the build output, the artifactElements has to have the same length
127
     * as artifacts. 
128
     * (must be owned by the artifact and be relative to it)
129
     * @param sourceGroup of type {@link org.netbeans.api.java.project.JavaProjectConstants#SOURCES_TYPE_JAVA}
130
     * identifying the compilation unit to change
131
     * @param type the type of the classpath the artifact should be added to,
132
     * eg {@link org.netbeans.api.java.classpath.ClassPath.COMPILE}
133
     * @return true in case the classpath was changed, (at least one artifact was added to the classpath),
134
     * the value false is returned when all the artifacts are already included on the classpath.
135
     * @exception IOException in case the project metadata cannot be changed
136
     * @exception UnsupportedOperationException is thrown when the project does not support
137
     * adding of an artifact to the classpath of the given id.
138
     */
139
    protected abstract boolean addAntArtifacts (AntArtifact[] artifacts, URI[] artifactElements, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
140
    
141
    /**
142
     * Removes artifacts (e.g. subprojects) from project's classpath if the
143
     * artifacts are included on it.
144
     * @param artifacts to be added
145
     * @param artifactElements the URIs of the build output, the artifactElements has to have the same length
146
     * as artifacts.
147
     * (must be owned by the artifact and be relative to it)
148
     * @param sourceGroup of type {@link org.netbeans.api.java.project.JavaProjectConstants#SOURCES_TYPE_JAVA}
149
     * identifying the compilation unit to change
150
     * @param type the type of the classpath the artifact should be removed from,
151
     * eg {@link org.netbeans.api.java.classpath.ClassPath.COMPILE}
152
     * @return true in case the classpath was changed, (at least one artifact was removed from the classpath),
153
     * the value false is returned when none of the artifacts was included on the classpath.
154
     * @exception IOException in case the project metadata cannot be changed
155
     * @exception UnsupportedOperationException is thrown when the project does not support
156
     * removing of an artifact from the classpath of the given id.
157
     */
158
    protected abstract boolean removeAntArtifacts (AntArtifact[] artifacts, URI[] artifactElements, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException;
159
160
    
161
    private static class Accessor extends ProjectClassPathModifierAccessor {        
162
        
163
        public SourceGroup[] getExtendableSourceGroups(final ProjectClassPathModifierImplementation m) {
164
            assert m != null;
165
            return m.getExtendableSourceGroups();
166
        }
167
        
168
        public String[] getExtendableClassPathTypes (final ProjectClassPathModifierImplementation m, SourceGroup sg) {
169
            assert m != null;
170
            assert sg != null;
171
            return m.getExtendableClassPathTypes(sg);
172
        }
173
        
174
        public boolean removeLibraries(Library[] libraries, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException {
175
            assert m!= null;
176
            return m.removeLibraries(libraries, sourceGroup, type);
177
        }
178
179
        public boolean removeAntArtifacts(AntArtifact[] artifacts, URI[] artifactElements, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException {
180
            assert m!= null;
181
            return m.removeAntArtifacts(artifacts, artifactElements, sourceGroup, type);
182
        }
183
184
        public boolean addLibraries (Library[] libraries, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException {
185
            assert m!= null;
186
            return m.addLibraries(libraries, sourceGroup, type);
187
        }
188
189
        public boolean addAntArtifacts (AntArtifact[] artifacts, URI[] artifactElements, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException {
190
            assert m!= null;
191
            return m.addAntArtifacts (artifacts, artifactElements, sourceGroup, type);
192
        }
193
194
        public boolean removeRoots (URL[] classPathRoots, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException {
195
            assert m!= null;
196
            return m.removeRoots(classPathRoots, sourceGroup, type);
197
        }
198
199
        public boolean addRoots (URL[] classPathRoots, ProjectClassPathModifierImplementation m, SourceGroup sourceGroup, String type) throws IOException, UnsupportedOperationException {
200
            assert m!= null;
201
            return m.addRoots (classPathRoots, sourceGroup, type);
202
        }       
203
                        
204
    }
205
}

Return to bug 75471