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 |
} |