]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/buildpath/ClasspathModifier.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core extension / org / eclipse / jdt / internal / corext / buildpath / ClasspathModifier.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Matt Chapman, mpchapman@gmail.com - 89977 Make JDT .java agnostic
11 *******************************************************************************/
12package org.eclipse.jdt.internal.corext.buildpath;
13
14import java.net.URI;
15import java.util.ArrayList;
16import java.util.Collections;
17import java.util.Iterator;
18import java.util.List;
19
20import org.eclipse.core.filesystem.EFS;
21import org.eclipse.core.filesystem.IFileStore;
22
23import org.eclipse.core.runtime.CoreException;
24import org.eclipse.core.runtime.IAdaptable;
25import org.eclipse.core.runtime.IPath;
26import org.eclipse.core.runtime.IProgressMonitor;
27import org.eclipse.core.runtime.IStatus;
28import org.eclipse.core.runtime.MultiStatus;
29import org.eclipse.core.runtime.NullProgressMonitor;
30import org.eclipse.core.runtime.OperationCanceledException;
31import org.eclipse.core.runtime.Path;
32import org.eclipse.core.runtime.SubProgressMonitor;
33
34import org.eclipse.core.resources.IContainer;
35import org.eclipse.core.resources.IFile;
36import org.eclipse.core.resources.IFolder;
37import org.eclipse.core.resources.IProject;
38import org.eclipse.core.resources.IResource;
39import org.eclipse.core.resources.IWorkspace;
40import org.eclipse.core.resources.IWorkspaceRoot;
41import org.eclipse.core.resources.ResourcesPlugin;
42
43import org.eclipse.jdt.core.IClasspathEntry;
44import org.eclipse.jdt.core.IJavaElement;
45import org.eclipse.jdt.core.IJavaModelStatus;
46import org.eclipse.jdt.core.IJavaProject;
47import org.eclipse.jdt.core.IPackageFragment;
48import org.eclipse.jdt.core.IPackageFragmentRoot;
49import org.eclipse.jdt.core.JavaConventions;
50import org.eclipse.jdt.core.JavaCore;
51import org.eclipse.jdt.core.JavaModelException;
52
53import org.eclipse.jdt.internal.corext.util.Messages;
54
55import org.eclipse.jdt.ui.PreferenceConstants;
56
57import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
58import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
59import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
60import org.eclipse.jdt.internal.ui.wizards.buildpaths.ArchiveFileFilter;
61import org.eclipse.jdt.internal.ui.wizards.buildpaths.BuildPathSupport;
62import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListElement;
63import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListElementAttribute;
64import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.ClasspathModifierQueries.OutputFolderValidator;
65
66public class ClasspathModifier {
67
68 private ClasspathModifier() {}
69
70 public static BuildpathDelta setOutputLocation(CPListElement elementToChange, IPath outputPath, boolean allowInvalidCP, CPJavaProject cpProject) throws CoreException {
71 BuildpathDelta result= new BuildpathDelta(NewWizardMessages.NewSourceContainerWorkbookPage_ToolBar_EditOutput_tooltip);
72
73 IJavaProject javaProject= cpProject.getJavaProject();
74 IProject project= javaProject.getProject();
75 IWorkspace workspace= project.getWorkspace();
76
77 IPath projectPath= project.getFullPath();
78
79 if (!allowInvalidCP && cpProject.getDefaultOutputLocation().segmentCount() == 1 && !projectPath.equals(elementToChange.getPath())) {
80 String outputFolderName= PreferenceConstants.getPreferenceStore().getString(PreferenceConstants.SRCBIN_BINNAME);
81 cpProject.setDefaultOutputLocation(cpProject.getDefaultOutputLocation().append(outputFolderName));
82 List<CPListElement> existingEntries= cpProject.getCPListElements();
83 CPListElement elem= ClasspathModifier.getListElement(javaProject.getPath(), existingEntries);
84 if (elem != null) {
85 existingEntries.remove(elem);
86 result.removeEntry(elem);
87 }
88 }
89
90 if (outputPath != null)
91 exclude(outputPath, cpProject.getCPListElements(), new ArrayList<CPListElement>(), cpProject.getJavaProject(), null);
92
93 IPath oldOutputLocation= (IPath)elementToChange.getAttribute(CPListElement.OUTPUT);
94 if (oldOutputLocation != null && oldOutputLocation.segmentCount() > 1 && !oldOutputLocation.equals(cpProject.getDefaultOutputLocation())) {
95 include(cpProject, oldOutputLocation);
96 result.addDeletedResource(workspace.getRoot().getFolder(oldOutputLocation));
97 }
98 elementToChange.setAttribute(CPListElement.OUTPUT, outputPath);
99
100 result.setDefaultOutputLocation(cpProject.getDefaultOutputLocation());
101 result.setNewEntries(cpProject.getCPListElements().toArray(new CPListElement[cpProject.getCPListElements().size()]));
102 if (outputPath != null && outputPath.segmentCount() > 1) {
103 result.addCreatedResource(workspace.getRoot().getFolder(outputPath));
104 }
105
106 return result;
107 }
108
109 public static IStatus checkSetOutputLocationPrecondition(CPListElement elementToChange, IPath outputPath, boolean allowInvalidCP, CPJavaProject cpProject) throws CoreException {
110 IJavaProject javaProject= cpProject.getJavaProject();
111 IProject project= javaProject.getProject();
112 IWorkspace workspace= project.getWorkspace();
113
114 IPath projectPath= project.getFullPath();
115
116 if (outputPath == null)
117 outputPath= cpProject.getDefaultOutputLocation();
118
119 IStatus pathValidation= workspace.validatePath(outputPath.toString(), IResource.PROJECT | IResource.FOLDER);
120 if (!pathValidation.isOK())
121 return new StatusInfo(IStatus.ERROR, Messages.format(NewWizardMessages.OutputLocationDialog_error_invalidpath, pathValidation.getMessage()));
122
123 IWorkspaceRoot root= workspace.getRoot();
124 IResource res= root.findMember(outputPath);
125 if (res != null) {
126 // if exists, must be a folder or project
127 if (res.getType() == IResource.FILE)
128 return new StatusInfo(IStatus.ERROR, NewWizardMessages.OutputLocationDialog_error_existingisfile);
129 }
130
131 IStatus result= StatusInfo.OK_STATUS;
132
133 int index= cpProject.indexOf(elementToChange);
134 cpProject= cpProject.createWorkingCopy();
135 elementToChange= cpProject.get(index);
136
137 if (!allowInvalidCP && cpProject.getDefaultOutputLocation().segmentCount() == 1 && !projectPath.equals(elementToChange.getPath())) {
138 String outputFolderName= PreferenceConstants.getPreferenceStore().getString(PreferenceConstants.SRCBIN_BINNAME);
139 cpProject.setDefaultOutputLocation(cpProject.getDefaultOutputLocation().append(outputFolderName));
140 ClasspathModifier.removeFromClasspath(javaProject, cpProject.getCPListElements(), null);
141 result= new StatusInfo(IStatus.INFO, Messages.format(NewWizardMessages.OutputLocationDialog_removeProjectFromBP, BasicElementLabels.getPathLabel(cpProject.getDefaultOutputLocation(), false)));
142 }
143
144 exclude(outputPath, cpProject.getCPListElements(), new ArrayList<CPListElement>(), cpProject.getJavaProject(), null);
145
146 IPath oldOutputLocation= (IPath)elementToChange.getAttribute(CPListElement.OUTPUT);
147 if (oldOutputLocation != null && oldOutputLocation.segmentCount() > 1 && !oldOutputLocation.equals(cpProject.getDefaultOutputLocation())) {
148 include(cpProject, oldOutputLocation);
149 }
150 elementToChange.setAttribute(CPListElement.OUTPUT, outputPath);
151
152 IJavaModelStatus status= JavaConventions.validateClasspath(javaProject, cpProject.getClasspathEntries(), cpProject.getDefaultOutputLocation());
153 if (!status.isOK()) {
154 if (allowInvalidCP) {
155 return new StatusInfo(IStatus.WARNING, status.getMessage());
156 } else {
157 return new StatusInfo(IStatus.ERROR, status.getMessage());
158 }
159 }
160
161 if (outputPath.segmentCount() - projectPath.segmentCount() < 1)
162 return result;
163
164 String lastSegment= outputPath.lastSegment();
165 if (lastSegment == null)
166 return result;
167
168 if (lastSegment.equals(".settings") && outputPath.segmentCount() - projectPath.segmentCount() == 1) { //$NON-NLS-1$
169
170 StatusInfo statusInfo= new StatusInfo(IStatus.WARNING, NewWizardMessages.OutputLocation_SettingsAsLocation);
171 if (result.isOK()) {
172 return statusInfo;
173 } else {
174 MultiStatus ms= new MultiStatus(result.getPlugin(), result.getCode(), new IStatus[] {result, statusInfo}, statusInfo.getMessage(), null);
175 return ms;
176 }
177 }
178
179 if (lastSegment.length() > 1 && lastSegment.charAt(0) == '.') {
180 StatusInfo statusInfo= new StatusInfo(IStatus.WARNING, Messages.format(NewWizardMessages.OutputLocation_DotAsLocation, BasicElementLabels.getPathLabel(outputPath, false)));
181 if (result.isOK()) {
182 return statusInfo;
183 } else {
184 MultiStatus ms= new MultiStatus(result.getPlugin(), result.getCode(), new IStatus[] {result, statusInfo}, statusInfo.getMessage(), null);
185 return ms;
186 }
187 }
188
189 return result;
190 }
191
192 public static IStatus checkAddExternalJarsPrecondition(IPath[] absolutePaths, CPJavaProject cpProject) {
193 IStatus result= StatusInfo.OK_STATUS;
194
195 IJavaProject javaProject= cpProject.getJavaProject();
196
197 List<CPListElement> newEntries= new ArrayList<CPListElement>();
198 List<CPListElement> duplicateEntries= new ArrayList<CPListElement>();
199 List<CPListElement> existingEntries= cpProject.getCPListElements();
200 for (int i= 0; i < absolutePaths.length; i++) {
201 CPListElement newEntry= new CPListElement(javaProject, IClasspathEntry.CPE_LIBRARY, absolutePaths[i], null);
202 if (existingEntries.contains(newEntry)) {
203 duplicateEntries.add(newEntry);
204 } else {
205 newEntries.add(newEntry);
206 }
207 }
208
209 if (duplicateEntries.size() > 0) {
210 String message;
211 if (duplicateEntries.size() > 1) {
212 StringBuffer buf= new StringBuffer();
213 for (Iterator<CPListElement> iterator= duplicateEntries.iterator(); iterator.hasNext();) {
214 CPListElement dup= iterator.next();
215 buf.append('\n').append(BasicElementLabels.getResourceName(dup.getPath().lastSegment()));
216 }
217 message= Messages.format(NewWizardMessages.AddArchiveToBuildpathAction_DuplicateArchivesInfo_message, buf.toString());
218 } else {
219 message= Messages.format(NewWizardMessages.AddArchiveToBuildpathAction_DuplicateArchiveInfo_message, BasicElementLabels.getResourceName(duplicateEntries.get(0).getPath().lastSegment()));
220 }
221 result= new StatusInfo(IStatus.INFO, message);
222 }
223
224 if (newEntries.size() == 0)
225 return result;
226
227 cpProject= cpProject.createWorkingCopy();
228 existingEntries= cpProject.getCPListElements();
229
230 for (Iterator<CPListElement> iterator= newEntries.iterator(); iterator.hasNext();) {
231 CPListElement newEntry= iterator.next();
232 insertAtEndOfCategory(newEntry, existingEntries);
233 }
234
235 IJavaModelStatus cpStatus= JavaConventions.validateClasspath(javaProject, cpProject.getClasspathEntries(), cpProject.getDefaultOutputLocation());
236 if (!cpStatus.isOK())
237 return cpStatus;
238
239 return result;
240 }
241
242 public static BuildpathDelta addExternalJars(IPath[] absolutePaths, CPJavaProject cpProject) {
243 BuildpathDelta result= new BuildpathDelta(NewWizardMessages.NewSourceContainerWorkbookPage_ToolBar_AddJarCP_tooltip);
244
245 IJavaProject javaProject= cpProject.getJavaProject();
246
247 List<CPListElement> existingEntries= cpProject.getCPListElements();
248 for (int i= 0; i < absolutePaths.length; i++) {
249 CPListElement newEntry= new CPListElement(javaProject, IClasspathEntry.CPE_LIBRARY, absolutePaths[i], null);
250 if (!existingEntries.contains(newEntry)) {
251 insertAtEndOfCategory(newEntry, existingEntries);
252 result.addEntry(newEntry);
253 }
254 }
255
256 result.setNewEntries(existingEntries.toArray(new CPListElement[existingEntries.size()]));
257 result.setDefaultOutputLocation(cpProject.getDefaultOutputLocation());
258 return result;
259 }
260
261 public static BuildpathDelta removeFromBuildpath(CPListElement[] toRemove, CPJavaProject cpProject) {
262
263 IJavaProject javaProject= cpProject.getJavaProject();
264 IPath projectPath= javaProject.getPath();
265 IWorkspaceRoot workspaceRoot= javaProject.getProject().getWorkspace().getRoot();
266
267 List<CPListElement> existingEntries= cpProject.getCPListElements();
268 BuildpathDelta result= new BuildpathDelta(NewWizardMessages.NewSourceContainerWorkbookPage_ToolBar_RemoveFromCP_tooltip);
269
270 for (int i= 0; i < toRemove.length; i++) {
271 CPListElement element= toRemove[i];
272 existingEntries.remove(element);
273 result.removeEntry(element);
274 IPath path= element.getPath();
275 removeFilters(path, javaProject, existingEntries);
276 if (!path.equals(projectPath)) {
277 IResource member= workspaceRoot.findMember(path);
278 if (member != null)
279 result.addDeletedResource(member);
280 } else if (cpProject.getDefaultOutputLocation().equals(projectPath) && containsSourceFolders(cpProject)) {
281 String outputFolderName= PreferenceConstants.getPreferenceStore().getString(PreferenceConstants.SRCBIN_BINNAME);
282 cpProject.setDefaultOutputLocation(cpProject.getDefaultOutputLocation().append(outputFolderName));
283 }
284 }
285
286 result.setDefaultOutputLocation(cpProject.getDefaultOutputLocation());
287 result.setNewEntries(existingEntries.toArray(new CPListElement[existingEntries.size()]));
288
289 return result;
290 }
291
292 private static boolean containsSourceFolders(CPJavaProject cpProject) {
293 List<CPListElement> elements= cpProject.getCPListElements();
294 for (Iterator<CPListElement> iterator= elements.iterator(); iterator.hasNext();) {
295 CPListElement element= iterator.next();
296 if (element.getEntryKind() == IClasspathEntry.CPE_SOURCE)
297 return true;
298 }
299 return false;
300 }
301
302 private static void include(CPJavaProject cpProject, IPath path) {
303 List<CPListElement> elements= cpProject.getCPListElements();
304 for (Iterator<CPListElement> iterator= elements.iterator(); iterator.hasNext();) {
305 CPListElement element= iterator.next();
306 element.removeFromExclusions(path);
307 }
308 }
309
310 /**
311 * Get the <code>IClasspathEntry</code> from the project and
312 * convert it into a list of <code>CPListElement</code>s.
313 *
314 * @param project the Java project to get it's build path entries from
315 * @return a list of <code>CPListElement</code>s corresponding to the
316 * build path entries of the project
317 * @throws JavaModelException
318 */
319 public static List<CPListElement> getExistingEntries(IJavaProject project) throws JavaModelException {
320 IClasspathEntry[] classpathEntries= project.getRawClasspath();
321 ArrayList<CPListElement> newClassPath= new ArrayList<CPListElement>();
322 for (int i= 0; i < classpathEntries.length; i++) {
323 IClasspathEntry curr= classpathEntries[i];
324 newClassPath.add(CPListElement.createFromExisting(curr, project));
325 }
326 return newClassPath;
327 }
328
329 /**
330 * Try to find the corresponding and modified <code>CPListElement</code> for the root
331 * in the list of elements and return it.
332 * If no one can be found, the roots <code>ClasspathEntry</code> is converted to a
333 * <code>CPListElement</code> and returned.
334 *
335 * @param elements a list of <code>CPListElements</code>
336 * @param root the root to find the <code>ClasspathEntry</code> for represented by
337 * a <code>CPListElement</code>
338 * @return the <code>CPListElement</code> found in the list (matching by using the path) or
339 * the roots own <code>IClasspathEntry</code> converted to a <code>CPListElement</code>.
340 * @throws JavaModelException
341 */
342 public static CPListElement getClasspathEntry(List<CPListElement> elements, IPackageFragmentRoot root) throws JavaModelException {
343 IClasspathEntry entry= root.getRawClasspathEntry();
344 for (int i= 0; i < elements.size(); i++) {
345 CPListElement element= elements.get(i);
346 if (element.getPath().equals(root.getPath()) && element.getEntryKind() == entry.getEntryKind())
347 return elements.get(i);
348 }
349 CPListElement newElement= CPListElement.createFromExisting(entry, root.getJavaProject());
350 elements.add(newElement);
351 return newElement;
352 }
353
354 /**
355 * For a given <code>IResource</code>, try to
356 * convert it into a <code>IPackageFragmentRoot</code>
357 * if possible or return <code>null</code> if no
358 * fragment root could be created.
359 *
360 * @param resource the resource to be converted
361 * @return the <code>resource<code> as
362 * <code>IPackageFragment</code>,or <code>null</code>
363 * if failed to convert
364 */
365 public static IPackageFragment getFragment(IResource resource) {
366 IJavaElement elem= JavaCore.create(resource);
367 if (elem instanceof IPackageFragment)
368 return (IPackageFragment) elem;
369 return null;
370 }
371
372 /**
373 * Get the source folder of a given <code>IResource</code> element,
374 * starting with the resource's parent.
375 *
376 * @param resource the resource to get the fragment root from
377 * @param project the Java project
378 * @param monitor progress monitor, can be <code>null</code>
379 * @return resolved fragment root, or <code>null</code> the resource is not (in) a source folder
380 * @throws JavaModelException
381 */
382 public static IPackageFragmentRoot getFragmentRoot(IResource resource, IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
383 if (monitor == null)
384 monitor= new NullProgressMonitor();
385 IJavaElement javaElem= null;
386 if (resource.getFullPath().equals(project.getPath()))
387 return project.getPackageFragmentRoot(resource);
388 IContainer container= resource.getParent();
389 do {
390 if (container instanceof IFolder)
391 javaElem= JavaCore.create((IFolder) container);
392 if (container.getFullPath().equals(project.getPath())) {
393 javaElem= project;
394 break;
395 }
396 container= container.getParent();
397 if (container == null)
398 return null;
399 } while (javaElem == null || !(javaElem instanceof IPackageFragmentRoot));
400 if (javaElem instanceof IJavaProject) {
401 if (!isSourceFolder((IJavaProject)javaElem))
402 return null;
403 javaElem= project.getPackageFragmentRoot(project.getResource());
404 }
405 return (IPackageFragmentRoot) javaElem;
406 }
407
408 /**
409 * Get the <code>IClasspathEntry</code> for the
410 * given path by looking up all
411 * build path entries on the project
412 *
413 * @param path the path to find a build path entry for
414 * @param project the Java project
415 * @param entryKind
416 * @return the <code>IClasspathEntry</code> corresponding
417 * to the <code>path</code> or <code>null</code> if there
418 * is no such entry
419 * @throws JavaModelException
420 */
421 public static IClasspathEntry getClasspathEntryFor(IPath path, IJavaProject project, int entryKind) throws JavaModelException {
422 IClasspathEntry[] entries= project.getRawClasspath();
423 for (int i= 0; i < entries.length; i++) {
424 IClasspathEntry entry= entries[i];
425 if (entry.getPath().equals(path) && equalEntryKind(entry, entryKind))
426 return entry;
427 }
428 return null;
429 }
430
431 /**
432 * Check whether the current selection is the project's
433 * default output folder or not
434 *
435 * @param attrib the attribute to be checked
436 * @return <code>true</code> if is the default output folder,
437 * <code>false</code> otherwise.
438 */
439 public static boolean isDefaultOutputFolder(CPListElementAttribute attrib) {
440 return attrib.getValue() == null;
441 }
442
443 /**
444 * Determines whether the current selection (of type
445 * <code>ICompilationUnit</code> or <code>IPackageFragment</code>)
446 * is on the inclusion filter of it's parent source folder.
447 *
448 * @param selection the current Java element
449 * @param project the Java project
450 * @param monitor progress monitor, can be <code>null</code>
451 * @return <code>true</code> if the current selection is included,
452 * <code>false</code> otherwise.
453 * @throws JavaModelException
454 */
455 public static boolean isIncluded(IJavaElement selection, IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
456 if (monitor == null)
457 monitor= new NullProgressMonitor();
458 try {
459 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_ContainsPath, 4);
460 IPackageFragmentRoot root= (IPackageFragmentRoot) selection.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
461 IClasspathEntry entry= root.getRawClasspathEntry();
462 if (entry == null)
463 return false;
464 return contains(selection.getPath().removeFirstSegments(root.getPath().segmentCount()), entry.getInclusionPatterns(), new SubProgressMonitor(monitor, 2));
465 } finally {
466 monitor.done();
467 }
468 }
469
470 /**
471 * Find out whether the <code>IResource</code> excluded or not.
472 *
473 * @param resource the resource to be checked
474 * @param project the Java project
475 * @return <code>true</code> if the resource is excluded, <code>
476 * false</code> otherwise
477 * @throws JavaModelException
478 */
479 public static boolean isExcluded(IResource resource, IJavaProject project) throws JavaModelException {
480 IPackageFragmentRoot root= getFragmentRoot(resource, project, null);
481 if (root == null)
482 return false;
483 String fragmentName= getName(resource.getFullPath(), root.getPath());
484 fragmentName= completeName(fragmentName);
485 IClasspathEntry entry= root.getRawClasspathEntry();
486 return entry != null && contains(new Path(fragmentName), entry.getExclusionPatterns(), null);
487 }
488
489 /**
490 * Find out whether one of the <code>IResource</code>'s parents
491 * is excluded.
492 *
493 * @param resource check the resources parents whether they are
494 * excluded or not
495 * @param project the Java project
496 * @return <code>true</code> if there is an excluded parent,
497 * <code>false</code> otherwise
498 * @throws JavaModelException
499 */
500 public static boolean parentExcluded(IResource resource, IJavaProject project) throws JavaModelException {
501 if (resource.getFullPath().equals(project.getPath()))
502 return false;
503 IPackageFragmentRoot root= getFragmentRoot(resource, project, null);
504 if (root == null) {
505 return true;
506 }
507 IPath path= resource.getFullPath().removeFirstSegments(root.getPath().segmentCount());
508 IClasspathEntry entry= root.getRawClasspathEntry();
509 if (entry == null)
510 return true; // there is no build path entry, this is equal to the fact that the parent is excluded
511 while (path.segmentCount() > 0) {
512 if (contains(path, entry.getExclusionPatterns(), null))
513 return true;
514 path= path.removeLastSegments(1);
515 }
516 return false;
517 }
518
519 /**
520 * Check whether the output location of the <code>IPackageFragmentRoot</code>
521 * is <code>null</code>. If this holds, then the root
522 * does use the default output folder.
523 *
524 * @param root the root to examine the output location for
525 * @return <code>true</code> if the root uses the default output folder, <code>false
526 * </code> otherwise.
527 * @throws JavaModelException
528 */
529 public static boolean hasDefaultOutputFolder(IPackageFragmentRoot root) throws JavaModelException {
530 return root.getRawClasspathEntry().getOutputLocation() == null;
531 }
532
533 /**
534 * Check whether at least one source folder of the given
535 * Java project has an output folder set.
536 *
537 * @param project the Java project
538 * @param monitor progress monitor, can be <code>null</code>
539 * @return <code>true</code> if at least one outputfolder
540 * is set, <code>false</code> otherwise
541 * @throws JavaModelException
542 */
543 public static boolean hasOutputFolders(IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
544 if (monitor == null)
545 monitor= new NullProgressMonitor();
546 try {
547 IPackageFragmentRoot[] roots= project.getPackageFragmentRoots();
548 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_CheckOutputFolders, roots.length);
549 for (int i= 0; i < roots.length; i++) {
550 if (roots[i].getRawClasspathEntry().getOutputLocation() != null)
551 return true;
552 monitor.worked(1);
553 }
554 } finally {
555 monitor.done();
556 }
557 return false;
558 }
559
560 public static String escapeSpecialChars(String value) {
561 StringBuffer buf = new StringBuffer();
562 for (int i = 0; i < value.length(); i++) {
563 char c = value.charAt(i);
564
565 switch (c) {
566 case '&':
567 buf.append("&amp;"); //$NON-NLS-1$
568 break;
569 case '<':
570 buf.append("&lt;"); //$NON-NLS-1$
571 break;
572 case '>':
573 buf.append("&gt;"); //$NON-NLS-1$
574 break;
575 case '\'':
576 buf.append("&apos;"); //$NON-NLS-1$
577 break;
578 case '\"':
579 buf.append("&quot;"); //$NON-NLS-1$
580 break;
581 case 160:
582 buf.append(" "); //$NON-NLS-1$
583 break;
584 default:
585 buf.append(c);
586 break;
587 }
588 }
589 return buf.toString();
590 }
591
592
593 /**
594 * Check whether the <code>IJavaProject</code>
595 * is a source folder
596 *
597 * @param project the project to test
598 * @return <code>true</code> if <code>project</code> is a source folder
599 * <code>false</code> otherwise.
600 * @throws JavaModelException
601 */
602 public static boolean isSourceFolder(IJavaProject project) throws JavaModelException {
603 return ClasspathModifier.getClasspathEntryFor(project.getPath(), project, IClasspathEntry.CPE_SOURCE) != null;
604 }
605
606 /**
607 * Check whether the <code>IPackageFragment</code>
608 * corresponds to the project's default fragment.
609 *
610 * @param fragment the package fragment to be checked
611 * @return <code>true</code> if is the default package fragment,
612 * <code>false</code> otherwise.
613 */
614 public static boolean isDefaultFragment(IPackageFragment fragment) {
615 return fragment.isDefaultPackage();
616 }
617
618 /**
619 * Determines whether the inclusion filter of the element's source folder is empty
620 * or not
621 * @param resource
622 * @param project
623 * @param monitor
624 * @return <code>true</code> if the inclusion filter is empty,
625 * <code>false</code> otherwise.
626 * @throws JavaModelException
627 */
628 public static boolean includeFiltersEmpty(IResource resource, IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
629 if (monitor == null)
630 monitor= new NullProgressMonitor();
631 try {
632 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_ExamineInputFilters, 4);
633 IPackageFragmentRoot root= getFragmentRoot(resource, project, new SubProgressMonitor(monitor, 4));
634 if (root != null) {
635 IClasspathEntry entry= root.getRawClasspathEntry();
636 return entry.getInclusionPatterns().length == 0;
637 }
638 return true;
639 } finally {
640 monitor.done();
641 }
642 }
643
644 /**
645 * Check whether the input parameter of type <code>
646 * IPackageFragmentRoot</code> has either it's inclusion or
647 * exclusion filter or both set (that means they are
648 * not empty).
649 *
650 * @param root the fragment root to be inspected
651 * @return <code>true</code> inclusion or exclusion filter set,
652 * <code>false</code> otherwise.
653 * @throws JavaModelException
654 */
655 public static boolean filtersSet(IPackageFragmentRoot root) throws JavaModelException {
656 if (root == null)
657 return false;
658 IClasspathEntry entry= root.getRawClasspathEntry();
659 IPath[] inclusions= entry.getInclusionPatterns();
660 IPath[] exclusions= entry.getExclusionPatterns();
661 if (inclusions != null && inclusions.length > 0)
662 return true;
663 if (exclusions != null && exclusions.length > 0)
664 return true;
665 return false;
666 }
667
668 /**
669 * Add a resource to the build path.
670 *
671 * @param resource the resource to be added to the build path
672 * @param existingEntries
673 * @param newEntries
674 * @param project the Java project
675 * @param monitor progress monitor, can be <code>null</code>
676 * @return returns the new element of type <code>IPackageFragmentRoot</code> that has been added to the build path
677 * @throws CoreException
678 * @throws OperationCanceledException
679 */
680 public static CPListElement addToClasspath(IResource resource, List<CPListElement> existingEntries, List<CPListElement> newEntries, IJavaProject project, IProgressMonitor monitor) throws OperationCanceledException, CoreException {
681 if (monitor == null)
682 monitor= new NullProgressMonitor();
683 try {
684 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_AddToBuildpath, 2);
685 exclude(resource.getFullPath(), existingEntries, newEntries, project, new SubProgressMonitor(monitor, 1));
686 CPListElement entry= new CPListElement(project, IClasspathEntry.CPE_SOURCE, resource.getFullPath(), resource);
687 return entry;
688 } finally {
689 monitor.done();
690 }
691 }
692
693 /**
694 * Check whether the provided file is an archive (.jar or .zip).
695 *
696 * @param file the file to be checked
697 * @param project the Java project
698 * @return <code>true</code> if the file is an archive, <code>false</code>
699 * otherwise
700 * @throws JavaModelException
701 */
702 public static boolean isArchive(IFile file, IJavaProject project) throws JavaModelException {
703 if (!ArchiveFileFilter.isArchivePath(file.getFullPath(), true))
704 return false;
705 if (project != null && project.exists() && (project.findPackageFragmentRoot(file.getFullPath()) == null))
706 return true;
707 return false;
708 }
709
710 /**
711 * Add a Java element to the build path.
712 *
713 * @param javaElement element to be added to the build path
714 * @param existingEntries
715 * @param newEntries
716 * @param project the Java project
717 * @param monitor progress monitor, can be <code>null</code>
718 * @return returns the new element of type <code>IPackageFragmentRoot</code> that has been added to the build path
719 * @throws CoreException
720 * @throws OperationCanceledException
721 */
722 public static CPListElement addToClasspath(IJavaElement javaElement, List<CPListElement> existingEntries, List<CPListElement> newEntries, IJavaProject project, IProgressMonitor monitor) throws OperationCanceledException, CoreException {
723 if (monitor == null)
724 monitor= new NullProgressMonitor();
725 try {
726 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_AddToBuildpath, 10);
727 CPListElement entry= new CPListElement(project, IClasspathEntry.CPE_SOURCE, javaElement.getPath(), javaElement.getResource());
728 return entry;
729 } finally {
730 monitor.done();
731 }
732 }
733
734 /**
735 * Remove the Java project from the build path
736 *
737 * @param project the project to be removed
738 * @param existingEntries a list of existing <code>CPListElement</code>. This list
739 * will be traversed and the entry for the project will be removed.
740 * @param monitor progress monitor, can be <code>null</code>
741 * @return returns the Java project
742 */
743 public static IJavaProject removeFromClasspath(IJavaProject project, List<CPListElement> existingEntries, IProgressMonitor monitor) {
744 CPListElement elem= getListElement(project.getPath(), existingEntries);
745 if (elem != null) {
746 existingEntries.remove(elem);
747 }
748 return project;
749 }
750
751 /**
752 * Remove <code>path</code> from inclusion/exlusion filters in all <code>existingEntries</code>
753 *
754 * @param path the path to remove
755 * @param project the Java project
756 * @param existingEntries a list of <code>CPListElement</code> representing the build path
757 * entries of the project.
758 * @return returns a <code>List</code> of <code>CPListElement</code> of modified elements, not null.
759 */
760 public static List<CPListElement> removeFilters(IPath path, IJavaProject project, List<CPListElement> existingEntries) {
761 if (path == null)
762 return Collections.emptyList();
763
764 IPath projPath= project.getPath();
765 if (projPath.isPrefixOf(path)) {
766 path= path.removeFirstSegments(projPath.segmentCount()).addTrailingSeparator();
767 }
768
769 List<CPListElement> result= new ArrayList<CPListElement>();
770 for (Iterator<CPListElement> iter= existingEntries.iterator(); iter.hasNext();) {
771 CPListElement element= iter.next();
772 boolean hasChange= false;
773 IPath[] exlusions= (IPath[])element.getAttribute(CPListElement.EXCLUSION);
774 if (exlusions != null) {
775 List<IPath> exlusionList= new ArrayList<IPath>(exlusions.length);
776 for (int i= 0; i < exlusions.length; i++) {
777 if (!exlusions[i].equals(path)) {
778 exlusionList.add(exlusions[i]);
779 } else {
780 hasChange= true;
781 }
782 }
783 element.setAttribute(CPListElement.EXCLUSION, exlusionList.toArray(new IPath[exlusionList.size()]));
784 }
785
786 IPath[] inclusion= (IPath[])element.getAttribute(CPListElement.INCLUSION);
787 if (inclusion != null) {
788 List<IPath> inclusionList= new ArrayList<IPath>(inclusion.length);
789 for (int i= 0; i < inclusion.length; i++) {
790 if (!inclusion[i].equals(path)) {
791 inclusionList.add(inclusion[i]);
792 } else {
793 hasChange= true;
794 }
795 }
796 element.setAttribute(CPListElement.INCLUSION, inclusionList.toArray(new IPath[inclusionList.size()]));
797 }
798 if (hasChange) {
799 result.add(element);
800 }
801 }
802 return result;
803 }
804
805 /**
806 * Exclude an element with a given name and absolute path
807 * from the build path.
808 *
809 * @param name the name of the element to be excluded
810 * @param fullPath the absolute path of the element
811 * @param entry the build path entry to be modified
812 * @param project the Java project
813 * @param monitor progress monitor, can be <code>null</code>
814 * @return a <code>IResource</code> corresponding to the excluded element
815 * @throws JavaModelException
816 */
817 private static IResource exclude(String name, IPath fullPath, CPListElement entry, IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
818 if (monitor == null)
819 monitor= new NullProgressMonitor();
820 IResource result;
821 try {
822 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_Excluding, 6);
823 IPath[] excludedPath= (IPath[]) entry.getAttribute(CPListElement.EXCLUSION);
824 IPath[] newExcludedPath= new IPath[excludedPath.length + 1];
825 name= completeName(name);
826 IPath path= new Path(name);
827 if (!contains(path, excludedPath, new SubProgressMonitor(monitor, 2))) {
828 System.arraycopy(excludedPath, 0, newExcludedPath, 0, excludedPath.length);
829 newExcludedPath[excludedPath.length]= path;
830 entry.setAttribute(CPListElement.EXCLUSION, newExcludedPath);
831 entry.setAttribute(CPListElement.INCLUSION, remove(path, (IPath[]) entry.getAttribute(CPListElement.INCLUSION), new SubProgressMonitor(monitor, 4)));
832 }
833 result= fullPath == null ? null : getResource(fullPath, project);
834 } finally {
835 monitor.done();
836 }
837 return result;
838 }
839
840 /**
841 * Exclude an object at a given path.
842 * This means that the exclusion filter for the
843 * corresponding <code>IPackageFragmentRoot</code> needs to be modified.
844 *
845 * First, the fragment root needs to be found. To do so, the new entries
846 * are and the existing entries are traversed for a match and the entry
847 * with the path is removed from one of those lists.
848 *
849 * Note: the <code>IJavaElement</code>'s fragment (if there is one)
850 * is not allowed to be excluded! However, inclusion (or simply no
851 * filter) on the parent fragment is allowed.
852 *
853 * @param path absolute path of an object to be excluded
854 * @param existingEntries a list of existing build path entries
855 * @param newEntries a list of new build path entries
856 * @param project the Java project
857 * @param monitor progress monitor, can be <code>null</code>
858 * @throws JavaModelException
859 */
860 public static void exclude(IPath path, List<CPListElement> existingEntries, List<CPListElement> newEntries, IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
861 if (monitor == null)
862 monitor= new NullProgressMonitor();
863 try {
864 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_Excluding, 1);
865 CPListElement elem= null;
866 CPListElement existingElem= null;
867 int i= 0;
868 do {
869 i++;
870 IPath rootPath= path.removeLastSegments(i);
871
872 if (rootPath.segmentCount() == 0)
873 return;
874
875 elem= getListElement(rootPath, newEntries);
876 existingElem= getListElement(rootPath, existingEntries);
877 } while (existingElem == null && elem == null);
878 if (elem == null) {
879 elem= existingElem;
880 }
881 exclude(path.removeFirstSegments(path.segmentCount() - i).toString(), null, elem, project, new SubProgressMonitor(monitor, 1));
882 } finally {
883 monitor.done();
884 }
885 }
886
887 /**
888 * Exclude a <code>IJavaElement</code>. This means that the exclusion filter for the
889 * corresponding <code>IPackageFragmentRoot</code>s need to be modified.
890 *
891 * Note: the <code>IJavaElement</code>'s fragment (if there is one)
892 * is not allowed to be excluded! However, inclusion (or simply no
893 * filter) on the parent fragment is allowed.
894 *
895 * @param javaElement the Java element to be excluded
896 * @param entry the <code>CPListElement</code> representing the
897 * <code>IClasspathEntry</code> of the Java element's root.
898 * @param project the Java project
899 * @param monitor progress monitor, can be <code>null</code>
900 *
901 * @return the resulting <code>IResource<code>
902 * @throws JavaModelException
903 */
904 public static IResource exclude(IJavaElement javaElement, CPListElement entry, IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
905 if (monitor == null)
906 monitor= new NullProgressMonitor();
907 try {
908 String name= getName(javaElement.getPath(), entry.getPath());
909 return exclude(name, javaElement.getPath(), entry, project, new SubProgressMonitor(monitor, 1));
910 } finally {
911 monitor.done();
912 }
913 }
914
915 /**
916 * Inverse operation to <code>exclude</code>.
917 * The resource removed from it's fragment roots exlusion filter.
918 *
919 * Note: the <code>IJavaElement</code>'s fragment (if there is one)
920 * is not allowed to be excluded! However, inclusion (or simply no
921 * filter) on the parent fragment is allowed.
922 *
923 * @param resource the resource to be unexcluded
924 * @param entry the <code>CPListElement</code> representing the
925 * <code>IClasspathEntry</code> of the resource's root.
926 * @param project the Java project
927 * @param monitor progress monitor, can be <code>null</code>
928 * @throws JavaModelException
929 *
930 */
931 public static void unExclude(IResource resource, CPListElement entry, IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
932 if (monitor == null)
933 monitor= new NullProgressMonitor();
934 try {
935 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_RemoveExclusion, 10);
936 String name= getName(resource.getFullPath(), entry.getPath());
937 IPath[] excludedPath= (IPath[]) entry.getAttribute(CPListElement.EXCLUSION);
938 IPath[] newExcludedPath= remove(new Path(completeName(name)), excludedPath, new SubProgressMonitor(monitor, 3));
939 entry.setAttribute(CPListElement.EXCLUSION, newExcludedPath);
940 } finally {
941 monitor.done();
942 }
943 }
944
945 /**
946 * Resets inclusion and exclusion filters for the given
947 * <code>IJavaElement</code>
948 *
949 * @param element element to reset it's filters
950 * @param entry the <code>CPListElement</code> to reset its filters for
951 * @param project the Java project
952 * @param monitor progress monitor, can be <code>null</code>
953 * @throws JavaModelException
954 */
955 public static void resetFilters(IJavaElement element, CPListElement entry, IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
956 if (monitor == null)
957 monitor= new NullProgressMonitor();
958 try {
959 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_ResetFilters, 3);
960
961 List<Path> exclusionList= getFoldersOnCP(element.getPath(), project, new SubProgressMonitor(monitor, 2));
962 IPath outputLocation= (IPath) entry.getAttribute(CPListElement.OUTPUT);
963 if (outputLocation != null) {
964 IPath[] exclusionPatterns= (IPath[]) entry.getAttribute(CPListElement.EXCLUSION);
965 if (contains(new Path(completeName(outputLocation.lastSegment())), exclusionPatterns, null)) {
966 exclusionList.add(new Path(completeName(outputLocation.lastSegment())));
967 }
968 }
969 IPath[] exclusions= exclusionList.toArray(new IPath[exclusionList.size()]);
970
971 entry.setAttribute(CPListElement.INCLUSION, new IPath[0]);
972 entry.setAttribute(CPListElement.EXCLUSION, exclusions);
973 } finally {
974 monitor.done();
975 }
976 }
977
978 /**
979 * Reset the output folder for the given entry to the default output folder
980 *
981 * @param entry the <code>CPListElement</code> to be edited
982 * @param project the Java project
983 * @return an attribute representing the modified output folder
984 * @throws JavaModelException
985 */
986 public static CPListElementAttribute resetOutputFolder(CPListElement entry, IJavaProject project) throws JavaModelException {
987 entry.setAttribute(CPListElement.OUTPUT, null);
988 CPListElementAttribute outputFolder= new CPListElementAttribute(entry, CPListElement.OUTPUT, entry.getAttribute(CPListElement.OUTPUT), true);
989 return outputFolder;
990 }
991
992 /**
993 * Try to find the corresponding and modified <code>CPListElement</code> for the provided
994 * <code>CPListElement</code> in the list of elements and return it.
995 * If no one can be found, the provided <code>CPListElement</code> is returned.
996 *
997 * @param elements a list of <code>CPListElements</code>
998 * @param cpElement the <code>CPListElement</code> to find the corresponding entry in
999 * the list
1000 * @return the <code>CPListElement</code> found in the list (matching by using the path) or
1001 * the second <code>CPListElement</code> parameter itself if there is no match.
1002 */
1003 public static CPListElement getClasspathEntry(List<CPListElement> elements, CPListElement cpElement) {
1004 for (int i= 0; i < elements.size(); i++) {
1005 if (elements.get(i).getPath().equals(cpElement.getPath()))
1006 return elements.get(i);
1007 }
1008 elements.add(cpElement);
1009 return cpElement;
1010 }
1011
1012 /**
1013 * For a given path, find the corresponding element in the list.
1014 *
1015 * @param path the path to found an entry for
1016 * @param elements a list of <code>CPListElement</code>s
1017 * @return the matched <code>CPListElement</code> or <code>null</code> if
1018 * no match could be found
1019 */
1020 public static CPListElement getListElement(IPath path, List<CPListElement> elements) {
1021 for (int i= 0; i < elements.size(); i++) {
1022 CPListElement element= elements.get(i);
1023 if (element.getEntryKind() == IClasspathEntry.CPE_SOURCE && element.getPath().equals(path)) {
1024 return element;
1025 }
1026 }
1027 return null;
1028 }
1029
1030 public static void commitClassPath(List<CPListElement> newEntries, IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
1031 if (monitor == null)
1032 monitor= new NullProgressMonitor();
1033
1034 monitor.beginTask("", 2); //$NON-NLS-1$
1035
1036 try {
1037 IClasspathEntry[] entries= convert(newEntries);
1038 IPath outputLocation= project.getOutputLocation();
1039
1040 IJavaModelStatus status= JavaConventions.validateClasspath(project, entries, outputLocation);
1041 if (!status.isOK())
1042 throw new JavaModelException(status);
1043
1044 BuildPathSupport.setEEComplianceOptions(project, newEntries);
1045 project.setRawClasspath(entries, outputLocation, new SubProgressMonitor(monitor, 2));
1046 } finally {
1047 monitor.done();
1048 }
1049 }
1050
1051 public static void commitClassPath(CPJavaProject cpProject, IProgressMonitor monitor) throws JavaModelException {
1052 if (monitor == null)
1053 monitor= new NullProgressMonitor();
1054
1055 monitor.beginTask("", 2); //$NON-NLS-1$
1056
1057 try {
1058 List<CPListElement> cpListElements= cpProject.getCPListElements();
1059 IClasspathEntry[] entries= convert(cpListElements);
1060 IPath outputLocation= cpProject.getDefaultOutputLocation();
1061
1062 IJavaProject javaProject= cpProject.getJavaProject();
1063 IJavaModelStatus status= JavaConventions.validateClasspath(javaProject, entries, outputLocation);
1064 if (!status.isOK())
1065 throw new JavaModelException(status);
1066
1067 BuildPathSupport.setEEComplianceOptions(javaProject, cpListElements);
1068 javaProject.setRawClasspath(entries, outputLocation, new SubProgressMonitor(monitor, 2));
1069 } finally {
1070 monitor.done();
1071 }
1072 }
1073
1074 /**
1075 * For a given list of entries, find out what representation they
1076 * will have in the project and return a list with corresponding
1077 * elements.
1078 *
1079 * @param entries a list of entries to find an appropriate representation
1080 * for. The list can contain elements of two types:
1081 * <li><code>IResource</code></li>
1082 * <li><code>IJavaElement</code></li>
1083 * @param project the Java project
1084 * @return a list of elements corresponding to the passed entries.
1085 */
1086 public static List<?> getCorrespondingElements(List<?> entries, IJavaProject project) {
1087 List<IAdaptable> result= new ArrayList<IAdaptable>();
1088 for (int i= 0; i < entries.size(); i++) {
1089 Object element= entries.get(i);
1090 IPath path;
1091 if (element instanceof IResource)
1092 path= ((IResource) element).getFullPath();
1093 else
1094 path= ((IJavaElement) element).getPath();
1095 IResource resource= getResource(path, project);
1096 if (resource != null) {
1097 IJavaElement elem= JavaCore.create(resource);
1098 if (elem != null && project.isOnClasspath(elem))
1099 result.add(elem);
1100 else
1101 result.add(resource);
1102 }
1103
1104 }
1105 return result;
1106 }
1107
1108 /**
1109 * Returns for the given absolute path the corresponding
1110 * resource, this is either element of type <code>IFile</code>
1111 * or <code>IFolder</code>.
1112 *
1113 * @param path an absolute path to a resource
1114 * @param project the Java project
1115 * @return the resource matching to the path. Can be
1116 * either an <code>IFile</code> or an <code>IFolder</code>.
1117 */
1118 private static IResource getResource(IPath path, IJavaProject project) {
1119 return project.getProject().getWorkspace().getRoot().findMember(path);
1120 }
1121
1122 /**
1123 * Find out whether the provided path equals to one
1124 * in the array.
1125 *
1126 * @param path path to find an equivalent for
1127 * @param paths set of paths to compare with
1128 * @param monitor progress monitor, can be <code>null</code>
1129 * @return <code>true</code> if there is an occurrence, <code>
1130 * false</code> otherwise
1131 */
1132 private static boolean contains(IPath path, IPath[] paths, IProgressMonitor monitor) {
1133 if (monitor == null)
1134 monitor= new NullProgressMonitor();
1135 if (path == null)
1136 return false;
1137 try {
1138 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_ComparePaths, paths.length);
1139 if (path.getFileExtension() == null)
1140 path= new Path(completeName(path.toString()));
1141 for (int i= 0; i < paths.length; i++) {
1142 if (paths[i].equals(path))
1143 return true;
1144 monitor.worked(1);
1145 }
1146 } finally {
1147 monitor.done();
1148 }
1149 return false;
1150 }
1151
1152 /**
1153 * Add a '/' at the end of the name if
1154 * it does not end with '.java', or other Java-like extension.
1155 *
1156 * @param name append '/' at the end if
1157 * necessary
1158 * @return modified string
1159 */
1160 private static String completeName(String name) {
1161 if (!JavaCore.isJavaLikeFileName(name)) {
1162 name= name + "/"; //$NON-NLS-1$
1163 name= name.replace('.', '/');
1164 return name;
1165 }
1166 return name;
1167 }
1168
1169 /**
1170 * Removes <code>path</code> out of the set of given <code>
1171 * paths</code>. If the path is not contained, then the
1172 * initially provided array of paths is returned.
1173 *
1174 * Only the first occurrence will be removed.
1175 *
1176 * @param path path to be removed
1177 * @param paths array of path to apply the removal on
1178 * @param monitor progress monitor, can be <code>null</code>
1179 * @return array which does not contain <code>path</code>
1180 */
1181 private static IPath[] remove(IPath path, IPath[] paths, IProgressMonitor monitor) {
1182 if (monitor == null)
1183 monitor= new NullProgressMonitor();
1184 try {
1185 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_RemovePath, paths.length + 5);
1186 if (!contains(path, paths, new SubProgressMonitor(monitor, 5)))
1187 return paths;
1188
1189 ArrayList<IPath> newPaths= new ArrayList<IPath>();
1190 for (int i= 0; i < paths.length; i++) {
1191 monitor.worked(1);
1192 if (!paths[i].equals(path))
1193 newPaths.add(paths[i]);
1194 }
1195
1196 return newPaths.toArray(new IPath[newPaths.size()]);
1197 } finally {
1198 monitor.done();
1199 }
1200
1201 }
1202
1203 /**
1204 * Find all folders that are on the build path and
1205 * <code>path</code> is a prefix of those folders
1206 * path entry, that is, all folders which are a
1207 * subfolder of <code>path</code>.
1208 *
1209 * For example, if <code>path</code>=/MyProject/src
1210 * then all folders having a path like /MyProject/src/*,
1211 * where * can be any valid string are returned if
1212 * they are also on the project's build path.
1213 *
1214 * @param path absolute path
1215 * @param project the Java project
1216 * @param monitor progress monitor, can be <code>null</code>
1217 * @return an array of paths which belong to subfolders
1218 * of <code>path</code> and which are on the build path
1219 * @throws JavaModelException
1220 */
1221 private static List<Path> getFoldersOnCP(IPath path, IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
1222 if (monitor == null)
1223 monitor= new NullProgressMonitor();
1224 List<Path> srcFolders= new ArrayList<Path>();
1225 IClasspathEntry[] cpEntries= project.getRawClasspath();
1226 for (int i= 0; i < cpEntries.length; i++) {
1227 IPath cpPath= cpEntries[i].getPath();
1228 if (path.isPrefixOf(cpPath) && path.segmentCount() + 1 == cpPath.segmentCount())
1229 srcFolders.add(new Path(completeName(cpPath.lastSegment())));
1230 }
1231 return srcFolders;
1232 }
1233
1234 /**
1235 * Returns a string corresponding to the <code>path</code>
1236 * with the <code>rootPath<code>'s number of segments
1237 * removed
1238 *
1239 * @param path path to remove segments
1240 * @param rootPath provides the number of segments to
1241 * be removed
1242 * @return a string corresponding to the mentioned
1243 * action
1244 */
1245 private static String getName(IPath path, IPath rootPath) {
1246 return path.removeFirstSegments(rootPath.segmentCount()).toString();
1247 }
1248
1249 /**
1250 * Sets and validates the new entries. Note that the elements of
1251 * the list containing the new entries will be added to the list of
1252 * existing entries (therefore, there is no return list for this method).
1253 *
1254 * @param existingEntries a list of existing classpath entries
1255 * @param newEntries a list of entries to be added to the existing ones
1256 * @param project the Java project
1257 * @param monitor a progress monitor, can be <code>null</code>
1258 * @throws CoreException in case that validation on one of the new entries fails
1259 */
1260 public static void setNewEntry(List<CPListElement> existingEntries, List<CPListElement> newEntries, IJavaProject project, IProgressMonitor monitor) throws CoreException {
1261 try {
1262 monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_SetNewEntry, existingEntries.size());
1263 for (int i= 0; i < newEntries.size(); i++) {
1264 CPListElement entry= newEntries.get(i);
1265 validateAndAddEntry(entry, existingEntries, project);
1266 monitor.worked(1);
1267 }
1268 } finally {
1269 monitor.done();
1270 }
1271 }
1272
1273 /**
1274 * Convert a list of <code>CPListElement</code>s to
1275 * an array of <code>IClasspathEntry</code>.
1276 *
1277 * @param list the list to be converted
1278 * @return an array containing build path entries
1279 * corresponding to the list
1280 */
1281 private static IClasspathEntry[] convert(List<CPListElement> list) {
1282 IClasspathEntry[] entries= new IClasspathEntry[list.size()];
1283 for (int i= 0; i < list.size(); i++) {
1284 CPListElement element= list.get(i);
1285 entries[i]= element.getClasspathEntry();
1286 }
1287 return entries;
1288 }
1289
1290 /**
1291 * Validate the new entry in the context of the existing entries. Furthermore,
1292 * check if exclusion filters need to be applied and do so if necessary.
1293 *
1294 * If validation was successful, add the new entry to the list of existing entries.
1295 *
1296 * @param entry the entry to be validated and added to the list of existing entries.
1297 * @param existingEntries a list of existing entries representing the build path
1298 * @param project the Java project
1299 * @throws CoreException in case that validation fails
1300 */
1301 private static void validateAndAddEntry(CPListElement entry, List<CPListElement> existingEntries, IJavaProject project) throws CoreException {
1302 IPath path= entry.getPath();
1303 IPath projPath= project.getProject().getFullPath();
1304 IWorkspaceRoot workspaceRoot= ResourcesPlugin.getWorkspace().getRoot();
1305 IStatus validate= workspaceRoot.getWorkspace().validatePath(path.toString(), IResource.FOLDER);
1306 StatusInfo rootStatus= new StatusInfo();
1307 rootStatus.setOK();
1308 boolean isExternal= isExternalArchiveOrLibrary(entry);
1309 if (!isExternal && validate.matches(IStatus.ERROR) && !project.getPath().equals(path)) {
1310 rootStatus.setError(Messages.format(NewWizardMessages.NewSourceFolderWizardPage_error_InvalidRootName, validate.getMessage()));
1311 throw new CoreException(rootStatus);
1312 } else {
1313 if (!isExternal && !project.getPath().equals(path)) {
1314 IResource res= workspaceRoot.findMember(path);
1315 if (res != null) {
1316 if (res.getType() != IResource.FOLDER && res.getType() != IResource.FILE) {
1317 rootStatus.setError(NewWizardMessages.NewSourceFolderWizardPage_error_NotAFolder);
1318 throw new CoreException(rootStatus);
1319 }
1320 } else {
1321 URI projLocation= project.getProject().getLocationURI();
1322 if (projLocation != null) {
1323 IFileStore store= EFS.getStore(projLocation).getFileStore(path);
1324 if (store.fetchInfo().exists()) {
1325 rootStatus.setError(NewWizardMessages.NewSourceFolderWizardPage_error_AlreadyExistingDifferentCase);
1326 throw new CoreException(rootStatus);
1327 }
1328 }
1329 }
1330 }
1331
1332 for (int i= 0; i < existingEntries.size(); i++) {
1333 CPListElement curr= existingEntries.get(i);
1334 if (curr.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
1335 if (path.equals(curr.getPath()) && !project.getPath().equals(path)) {
1336 rootStatus.setError(NewWizardMessages.NewSourceFolderWizardPage_error_AlreadyExisting);
1337 throw new CoreException(rootStatus);
1338 }
1339 }
1340 }
1341
1342 if (!isExternal && !entry.getPath().equals(project.getPath()))
1343 exclude(entry.getPath(), existingEntries, new ArrayList<CPListElement>(), project, null);
1344
1345 IPath outputLocation= project.getOutputLocation();
1346 insertAtEndOfCategory(entry, existingEntries);
1347
1348 IClasspathEntry[] entries= convert(existingEntries);
1349
1350 IJavaModelStatus status= JavaConventions.validateClasspath(project, entries, outputLocation);
1351 if (!status.isOK()) {
1352 if (outputLocation.equals(projPath)) {
1353 IStatus status2= JavaConventions.validateClasspath(project, entries, outputLocation);
1354 if (status2.isOK()) {
1355 if (project.isOnClasspath(project)) {
1356 rootStatus.setInfo(Messages.format(NewWizardMessages.NewSourceFolderWizardPage_warning_ReplaceSFandOL, BasicElementLabels.getPathLabel(outputLocation, false)));
1357 } else {
1358 rootStatus.setInfo(Messages.format(NewWizardMessages.NewSourceFolderWizardPage_warning_ReplaceOL, BasicElementLabels.getPathLabel(outputLocation, false)));
1359 }
1360 return;
1361 }
1362 }
1363 rootStatus.setError(status.getMessage());
1364 throw new CoreException(rootStatus);
1365 }
1366
1367 if (isSourceFolder(project) || project.getPath().equals(path)) {
1368 rootStatus.setWarning(NewWizardMessages.NewSourceFolderWizardPage_warning_ReplaceSF);
1369 return;
1370 }
1371
1372 rootStatus.setOK();
1373 return;
1374 }
1375 }
1376
1377 private static void insertAtEndOfCategory(CPListElement entry, List<CPListElement> existingEntries) {
1378 int length= existingEntries.size();
1379 CPListElement[] elements= existingEntries.toArray(new CPListElement[length]);
1380 int i= 0;
1381 while (i < length && elements[i].getClasspathEntry().getEntryKind() != entry.getClasspathEntry().getEntryKind()) {
1382 i++;
1383 }
1384 if (i < length) {
1385 i++;
1386 while (i < length && elements[i].getClasspathEntry().getEntryKind() == entry.getClasspathEntry().getEntryKind()) {
1387 i++;
1388 }
1389 existingEntries.add(i, entry);
1390 return;
1391 }
1392
1393 switch (entry.getClasspathEntry().getEntryKind()) {
1394 case IClasspathEntry.CPE_SOURCE:
1395 existingEntries.add(0, entry);
1396 break;
1397 case IClasspathEntry.CPE_CONTAINER:
1398 case IClasspathEntry.CPE_LIBRARY:
1399 case IClasspathEntry.CPE_PROJECT:
1400 case IClasspathEntry.CPE_VARIABLE:
1401 default:
1402 existingEntries.add(entry);
1403 break;
1404 }
1405 }
1406
1407 private static boolean isExternalArchiveOrLibrary(CPListElement entry) {
1408 if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY || entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
1409 if (entry.getResource() instanceof IFolder) {
1410 return false;
1411 }
1412 return true;
1413 }
1414 return false;
1415 }
1416
1417 public static boolean isInExternalOrArchive(IJavaElement element) {
1418 IPackageFragmentRoot root= (IPackageFragmentRoot) element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
1419 return root != null && (root.isArchive() || root.isExternal());
1420 }
1421
1422 /**
1423 * Test if the provided kind is of type
1424 * <code>IClasspathEntry.CPE_SOURCE</code>
1425 *
1426 * @param entry the classpath entry to be compared with the provided type
1427 * @param kind the kind to be checked
1428 * @return <code>true</code> if kind equals
1429 * <code>IClasspathEntry.CPE_SOURCE</code>,
1430 * <code>false</code> otherwise
1431 */
1432 private static boolean equalEntryKind(IClasspathEntry entry, int kind) {
1433 return entry.getEntryKind() == kind;
1434 }
1435
1436 public static OutputFolderValidator getValidator(final List<?> newElements, final IJavaProject project) throws JavaModelException {
1437 return new OutputFolderValidator(newElements, project) {
1438
1439 @Override
1440 public boolean validate(IPath outputLocation) {
1441 for (int i= 0; i < newElements.size(); i++) {
1442 if (isInvalid(newElements.get(i), outputLocation))
1443 return false;
1444 }
1445
1446 for (int i= 0; i < fEntries.length; i++) {
1447 if (isInvalid(fEntries[i], outputLocation))
1448 return false;
1449 }
1450 return true;
1451 }
1452
1453 /**
1454 * Check if the output location for the given object is valid
1455 *
1456 * @param object the object to retrieve its path from and compare it
1457 * to the output location
1458 * @param outputLocation the output location
1459 * @return <code>true</code> if the output location is invalid, that is,
1460 * if it is a subfolder of the provided object.
1461 */
1462 private boolean isInvalid(Object object, IPath outputLocation) {
1463 IPath path= null;
1464 if (object instanceof IFolder)
1465 path= getFolderPath(object);
1466 else
1467 if (object instanceof IJavaElement)
1468 path= getJavaElementPath(object);
1469 else
1470 if (object instanceof IClasspathEntry)
1471 path= getCPEntryPath(object);
1472 return isSubFolderOf(path, outputLocation);
1473 }
1474
1475 /**
1476 * Get an <code>IFolder</code>'s path
1477 *
1478 * @param element an element which is of type <code>IFolder</code>
1479 * @return the path of the folder
1480 */
1481 private IPath getFolderPath(Object element) {
1482 return ((IFolder) element).getFullPath();
1483 }
1484
1485 /**
1486 * Get an <code>IJavaElement</code>'s path
1487 *
1488 * @param element an element which is of type <code>IJavaElement</code>
1489 * @return the path of the Java element
1490 */
1491 private IPath getJavaElementPath(Object element) {
1492 return ((IJavaElement) element).getPath();
1493 }
1494
1495 /**
1496 * Get an <code>IClasspathEntry</code>'s path
1497 *
1498 * @param entry an element which is of type <code>IClasspathEntry</code>
1499 * @return the path of the classpath entry
1500 */
1501 private IPath getCPEntryPath(Object entry) {
1502 return ((IClasspathEntry) entry).getPath();
1503 }
1504
1505 /**
1506 *
1507 * @param path1 the first path
1508 * @param path2 the second path
1509 * @return <code>true</code> if path1 is a subfolder of
1510 * path2, <code>false</code> otherwise
1511 */
1512 private boolean isSubFolderOf(IPath path1, IPath path2) {
1513 if (path1 == null || path2 == null) {
1514 if (path1 == null && path2 == null)
1515 return true;
1516 return false;
1517 }
1518 return path2.matchingFirstSegments(path1) == path2.segmentCount();
1519 }
1520
1521 };
1522 }
1523
1524}