0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: * Matt Chapman, mpchapman@gmail.com - 89977 Make JDT .java agnostic
0011: *******************************************************************************/package org.eclipse.jdt.internal.corext.buildpath;
0012:
0013: import java.net.URI;
0014: import java.util.ArrayList;
0015: import java.util.Collections;
0016: import java.util.Iterator;
0017: import java.util.List;
0018:
0019: import org.eclipse.core.filesystem.EFS;
0020: import org.eclipse.core.filesystem.IFileStore;
0021:
0022: import org.eclipse.core.runtime.CoreException;
0023: import org.eclipse.core.runtime.IPath;
0024: import org.eclipse.core.runtime.IProgressMonitor;
0025: import org.eclipse.core.runtime.IStatus;
0026: import org.eclipse.core.runtime.MultiStatus;
0027: import org.eclipse.core.runtime.NullProgressMonitor;
0028: import org.eclipse.core.runtime.OperationCanceledException;
0029: import org.eclipse.core.runtime.Path;
0030: import org.eclipse.core.runtime.SubProgressMonitor;
0031:
0032: import org.eclipse.core.resources.IContainer;
0033: import org.eclipse.core.resources.IFile;
0034: import org.eclipse.core.resources.IFolder;
0035: import org.eclipse.core.resources.IProject;
0036: import org.eclipse.core.resources.IResource;
0037: import org.eclipse.core.resources.IWorkspace;
0038: import org.eclipse.core.resources.IWorkspaceRoot;
0039: import org.eclipse.core.resources.ResourcesPlugin;
0040:
0041: import org.eclipse.jdt.core.IClasspathEntry;
0042: import org.eclipse.jdt.core.IJavaElement;
0043: import org.eclipse.jdt.core.IJavaModelStatus;
0044: import org.eclipse.jdt.core.IJavaProject;
0045: import org.eclipse.jdt.core.IPackageFragment;
0046: import org.eclipse.jdt.core.IPackageFragmentRoot;
0047: import org.eclipse.jdt.core.JavaConventions;
0048: import org.eclipse.jdt.core.JavaCore;
0049: import org.eclipse.jdt.core.JavaModelException;
0050:
0051: import org.eclipse.jdt.internal.corext.util.Messages;
0052:
0053: import org.eclipse.jdt.ui.PreferenceConstants;
0054:
0055: import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
0056: import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
0057: import org.eclipse.jdt.internal.ui.wizards.buildpaths.ArchiveFileFilter;
0058: import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListElement;
0059: import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListElementAttribute;
0060: import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.ClasspathModifierQueries.OutputFolderValidator;
0061:
0062: public class ClasspathModifier {
0063:
0064: private ClasspathModifier() {
0065: }
0066:
0067: public static BuildpathDelta setOutputLocation(
0068: CPListElement elementToChange, IPath outputPath,
0069: boolean allowInvalidCP, CPJavaProject cpProject)
0070: throws CoreException {
0071: BuildpathDelta result = new BuildpathDelta(
0072: NewWizardMessages.NewSourceContainerWorkbookPage_ToolBar_EditOutput_tooltip);
0073:
0074: IJavaProject javaProject = cpProject.getJavaProject();
0075: IProject project = javaProject.getProject();
0076: IWorkspace workspace = project.getWorkspace();
0077:
0078: IPath projectPath = project.getFullPath();
0079:
0080: if (!allowInvalidCP
0081: && cpProject.getDefaultOutputLocation().segmentCount() == 1
0082: && !projectPath.equals(elementToChange.getPath())) {
0083: String outputFolderName = PreferenceConstants
0084: .getPreferenceStore().getString(
0085: PreferenceConstants.SRCBIN_BINNAME);
0086: cpProject.setDefaultOutputLocation(cpProject
0087: .getDefaultOutputLocation()
0088: .append(outputFolderName));
0089: List existingEntries = cpProject.getCPListElements();
0090: CPListElement elem = ClasspathModifier.getListElement(
0091: javaProject.getPath(), existingEntries);
0092: if (elem != null) {
0093: existingEntries.remove(elem);
0094: result.removeEntry(elem);
0095: }
0096: }
0097:
0098: if (outputPath != null)
0099: exclude(outputPath, cpProject.getCPListElements(),
0100: new ArrayList(), cpProject.getJavaProject(), null);
0101:
0102: IPath oldOutputLocation = (IPath) elementToChange
0103: .getAttribute(CPListElement.OUTPUT);
0104: if (oldOutputLocation != null
0105: && oldOutputLocation.segmentCount() > 1
0106: && !oldOutputLocation.equals(cpProject
0107: .getDefaultOutputLocation())) {
0108: include(cpProject, oldOutputLocation);
0109: result.addDeletedResource(workspace.getRoot().getFolder(
0110: oldOutputLocation));
0111: }
0112: elementToChange.setAttribute(CPListElement.OUTPUT, outputPath);
0113:
0114: result.setDefaultOutputLocation(cpProject
0115: .getDefaultOutputLocation());
0116: result.setNewEntries((CPListElement[]) cpProject
0117: .getCPListElements().toArray(
0118: new CPListElement[cpProject.getCPListElements()
0119: .size()]));
0120: if (outputPath != null && outputPath.segmentCount() > 1) {
0121: result.addCreatedResource(workspace.getRoot().getFolder(
0122: outputPath));
0123: }
0124:
0125: return result;
0126: }
0127:
0128: public static IStatus checkSetOutputLocationPrecondition(
0129: CPListElement elementToChange, IPath outputPath,
0130: boolean allowInvalidCP, CPJavaProject cpProject)
0131: throws CoreException {
0132: IJavaProject javaProject = cpProject.getJavaProject();
0133: IProject project = javaProject.getProject();
0134: IWorkspace workspace = project.getWorkspace();
0135:
0136: IPath projectPath = project.getFullPath();
0137:
0138: if (outputPath == null)
0139: outputPath = cpProject.getDefaultOutputLocation();
0140:
0141: IStatus pathValidation = workspace.validatePath(outputPath
0142: .toString(), IResource.PROJECT | IResource.FOLDER);
0143: if (!pathValidation.isOK())
0144: return new StatusInfo(
0145: IStatus.ERROR,
0146: Messages
0147: .format(
0148: NewWizardMessages.OutputLocationDialog_error_invalidpath,
0149: pathValidation.getMessage()));
0150:
0151: IWorkspaceRoot root = workspace.getRoot();
0152: IResource res = root.findMember(outputPath);
0153: if (res != null) {
0154: // if exists, must be a folder or project
0155: if (res.getType() == IResource.FILE)
0156: return new StatusInfo(
0157: IStatus.ERROR,
0158: NewWizardMessages.OutputLocationDialog_error_existingisfile);
0159: }
0160:
0161: IStatus result = StatusInfo.OK_STATUS;
0162:
0163: int index = cpProject.indexOf(elementToChange);
0164: cpProject = cpProject.createWorkingCopy();
0165: elementToChange = cpProject.get(index);
0166:
0167: if (!allowInvalidCP
0168: && cpProject.getDefaultOutputLocation().segmentCount() == 1
0169: && !projectPath.equals(elementToChange.getPath())) {
0170: String outputFolderName = PreferenceConstants
0171: .getPreferenceStore().getString(
0172: PreferenceConstants.SRCBIN_BINNAME);
0173: cpProject.setDefaultOutputLocation(cpProject
0174: .getDefaultOutputLocation()
0175: .append(outputFolderName));
0176: ClasspathModifier.removeFromClasspath(javaProject,
0177: cpProject.getCPListElements(), null);
0178: result = new StatusInfo(
0179: IStatus.INFO,
0180: Messages
0181: .format(
0182: NewWizardMessages.OutputLocationDialog_removeProjectFromBP,
0183: cpProject
0184: .getDefaultOutputLocation()));
0185: }
0186:
0187: exclude(outputPath, cpProject.getCPListElements(),
0188: new ArrayList(), cpProject.getJavaProject(), null);
0189:
0190: IPath oldOutputLocation = (IPath) elementToChange
0191: .getAttribute(CPListElement.OUTPUT);
0192: if (oldOutputLocation != null
0193: && oldOutputLocation.segmentCount() > 1
0194: && !oldOutputLocation.equals(cpProject
0195: .getDefaultOutputLocation())) {
0196: include(cpProject, oldOutputLocation);
0197: }
0198: elementToChange.setAttribute(CPListElement.OUTPUT, outputPath);
0199:
0200: IJavaModelStatus status = JavaConventions.validateClasspath(
0201: javaProject, cpProject.getClasspathEntries(), cpProject
0202: .getDefaultOutputLocation());
0203: if (!status.isOK()) {
0204: if (allowInvalidCP) {
0205: return new StatusInfo(IStatus.WARNING, status
0206: .getMessage());
0207: } else {
0208: return new StatusInfo(IStatus.ERROR, status
0209: .getMessage());
0210: }
0211: }
0212:
0213: if (outputPath.segmentCount() - projectPath.segmentCount() < 1)
0214: return result;
0215:
0216: String lastSegment = outputPath.lastSegment();
0217: if (lastSegment == null)
0218: return result;
0219:
0220: if (lastSegment.equals(".settings") && outputPath.segmentCount() - projectPath.segmentCount() == 1) { //$NON-NLS-1$
0221:
0222: StatusInfo statusInfo = new StatusInfo(IStatus.WARNING,
0223: NewWizardMessages.OutputLocation_SettingsAsLocation);
0224: if (result.isOK()) {
0225: return statusInfo;
0226: } else {
0227: MultiStatus ms = new MultiStatus(result.getPlugin(),
0228: result.getCode(), new IStatus[] { result,
0229: statusInfo }, statusInfo.getMessage(),
0230: null);
0231: return ms;
0232: }
0233: }
0234:
0235: if (lastSegment.length() > 1 && lastSegment.charAt(0) == '.') {
0236: StatusInfo statusInfo = new StatusInfo(
0237: IStatus.WARNING,
0238: Messages
0239: .format(
0240: NewWizardMessages.OutputLocation_DotAsLocation,
0241: outputPath.toString()));
0242: if (result.isOK()) {
0243: return statusInfo;
0244: } else {
0245: MultiStatus ms = new MultiStatus(result.getPlugin(),
0246: result.getCode(), new IStatus[] { result,
0247: statusInfo }, statusInfo.getMessage(),
0248: null);
0249: return ms;
0250: }
0251: }
0252:
0253: return result;
0254: }
0255:
0256: public static IStatus checkAddExternalJarsPrecondition(
0257: IPath[] absolutePaths, CPJavaProject cpProject)
0258: throws CoreException {
0259: IStatus result = StatusInfo.OK_STATUS;
0260:
0261: IJavaProject javaProject = cpProject.getJavaProject();
0262:
0263: List newEntries = new ArrayList();
0264: List duplicateEntries = new ArrayList();
0265: List existingEntries = cpProject.getCPListElements();
0266: for (int i = 0; i < absolutePaths.length; i++) {
0267: CPListElement newEntry = new CPListElement(javaProject,
0268: IClasspathEntry.CPE_LIBRARY, absolutePaths[i], null);
0269: if (existingEntries.contains(newEntry)) {
0270: duplicateEntries.add(newEntry);
0271: } else {
0272: newEntries.add(newEntry);
0273: }
0274: }
0275:
0276: if (duplicateEntries.size() > 0) {
0277: String message;
0278: if (duplicateEntries.size() > 1) {
0279: StringBuffer buf = new StringBuffer();
0280: for (Iterator iterator = duplicateEntries.iterator(); iterator
0281: .hasNext();) {
0282: CPListElement dup = (CPListElement) iterator.next();
0283: buf.append('\n')
0284: .append(dup.getPath().lastSegment());
0285: }
0286: message = Messages
0287: .format(
0288: NewWizardMessages.AddArchiveToBuildpathAction_DuplicateArchivesInfo_message,
0289: buf.toString());
0290: } else {
0291: message = Messages
0292: .format(
0293: NewWizardMessages.AddArchiveToBuildpathAction_DuplicateArchiveInfo_message,
0294: ((CPListElement) duplicateEntries
0295: .get(0)).getPath()
0296: .lastSegment());
0297: }
0298: result = new StatusInfo(IStatus.INFO, message);
0299: }
0300:
0301: if (newEntries.size() == 0)
0302: return result;
0303:
0304: cpProject = cpProject.createWorkingCopy();
0305: existingEntries = cpProject.getCPListElements();
0306:
0307: for (Iterator iterator = newEntries.iterator(); iterator
0308: .hasNext();) {
0309: CPListElement newEntry = (CPListElement) iterator.next();
0310: insertAtEndOfCategory(newEntry, existingEntries);
0311: }
0312:
0313: IJavaModelStatus cpStatus = JavaConventions.validateClasspath(
0314: javaProject, cpProject.getClasspathEntries(), cpProject
0315: .getDefaultOutputLocation());
0316: if (!cpStatus.isOK())
0317: return cpStatus;
0318:
0319: return result;
0320: }
0321:
0322: public static BuildpathDelta addExternalJars(IPath[] absolutePaths,
0323: CPJavaProject cpProject) throws CoreException {
0324: BuildpathDelta result = new BuildpathDelta(
0325: NewWizardMessages.NewSourceContainerWorkbookPage_ToolBar_AddJarCP_tooltip);
0326:
0327: IJavaProject javaProject = cpProject.getJavaProject();
0328:
0329: List existingEntries = cpProject.getCPListElements();
0330: for (int i = 0; i < absolutePaths.length; i++) {
0331: CPListElement newEntry = new CPListElement(javaProject,
0332: IClasspathEntry.CPE_LIBRARY, absolutePaths[i], null);
0333: if (!existingEntries.contains(newEntry)) {
0334: insertAtEndOfCategory(newEntry, existingEntries);
0335: result.addEntry(newEntry);
0336: }
0337: }
0338:
0339: result.setNewEntries((CPListElement[]) existingEntries
0340: .toArray(new CPListElement[existingEntries.size()]));
0341: result.setDefaultOutputLocation(cpProject
0342: .getDefaultOutputLocation());
0343: return result;
0344: }
0345:
0346: public static BuildpathDelta removeFromBuildpath(
0347: CPListElement[] toRemove, CPJavaProject cpProject) {
0348:
0349: IJavaProject javaProject = cpProject.getJavaProject();
0350: IPath projectPath = javaProject.getPath();
0351: IWorkspaceRoot workspaceRoot = javaProject.getProject()
0352: .getWorkspace().getRoot();
0353:
0354: List existingEntries = cpProject.getCPListElements();
0355: BuildpathDelta result = new BuildpathDelta(
0356: NewWizardMessages.NewSourceContainerWorkbookPage_ToolBar_RemoveFromCP_tooltip);
0357:
0358: for (int i = 0; i < toRemove.length; i++) {
0359: CPListElement element = toRemove[i];
0360: existingEntries.remove(element);
0361: result.removeEntry(element);
0362: IPath path = element.getPath();
0363: removeFilters(path, javaProject, existingEntries);
0364: if (!path.equals(projectPath)) {
0365: IResource member = workspaceRoot.findMember(path);
0366: if (member != null)
0367: result.addDeletedResource(member);
0368: } else if (cpProject.getDefaultOutputLocation().equals(
0369: projectPath)
0370: && containsSourceFolders(cpProject)) {
0371: String outputFolderName = PreferenceConstants
0372: .getPreferenceStore().getString(
0373: PreferenceConstants.SRCBIN_BINNAME);
0374: cpProject.setDefaultOutputLocation(cpProject
0375: .getDefaultOutputLocation().append(
0376: outputFolderName));
0377: }
0378: }
0379:
0380: result.setDefaultOutputLocation(cpProject
0381: .getDefaultOutputLocation());
0382: result.setNewEntries((CPListElement[]) existingEntries
0383: .toArray(new CPListElement[existingEntries.size()]));
0384:
0385: return result;
0386: }
0387:
0388: private static boolean containsSourceFolders(CPJavaProject cpProject) {
0389: List elements = cpProject.getCPListElements();
0390: for (Iterator iterator = elements.iterator(); iterator
0391: .hasNext();) {
0392: CPListElement element = (CPListElement) iterator.next();
0393: if (element.getEntryKind() == IClasspathEntry.CPE_SOURCE)
0394: return true;
0395: }
0396: return false;
0397: }
0398:
0399: private static void include(CPJavaProject cpProject, IPath path) {
0400: List elements = cpProject.getCPListElements();
0401: for (Iterator iterator = elements.iterator(); iterator
0402: .hasNext();) {
0403: CPListElement element = (CPListElement) iterator.next();
0404: element.removeFromExclusions(path);
0405: }
0406: }
0407:
0408: /**
0409: * Get the <code>IClasspathEntry</code> from the project and
0410: * convert it into a list of <code>CPListElement</code>s.
0411: *
0412: * @param project the Java project to get it's build path entries from
0413: * @return a list of <code>CPListElement</code>s corresponding to the
0414: * build path entries of the project
0415: * @throws JavaModelException
0416: */
0417: public static List getExistingEntries(IJavaProject project)
0418: throws JavaModelException {
0419: IClasspathEntry[] classpathEntries = project.getRawClasspath();
0420: ArrayList newClassPath = new ArrayList();
0421: for (int i = 0; i < classpathEntries.length; i++) {
0422: IClasspathEntry curr = classpathEntries[i];
0423: newClassPath.add(CPListElement.createFromExisting(curr,
0424: project));
0425: }
0426: return newClassPath;
0427: }
0428:
0429: /**
0430: * Try to find the corresponding and modified <code>CPListElement</code> for the root
0431: * in the list of elements and return it.
0432: * If no one can be found, the roots <code>ClasspathEntry</code> is converted to a
0433: * <code>CPListElement</code> and returned.
0434: *
0435: * @param elements a list of <code>CPListElements</code>
0436: * @param root the root to find the <code>ClasspathEntry</code> for represented by
0437: * a <code>CPListElement</code>
0438: * @return the <code>CPListElement</code> found in the list (matching by using the path) or
0439: * the roots own <code>IClasspathEntry</code> converted to a <code>CPListElement</code>.
0440: * @throws JavaModelException
0441: */
0442: public static CPListElement getClasspathEntry(List elements,
0443: IPackageFragmentRoot root) throws JavaModelException {
0444: IClasspathEntry entry = root.getRawClasspathEntry();
0445: for (int i = 0; i < elements.size(); i++) {
0446: CPListElement element = (CPListElement) elements.get(i);
0447: if (element.getPath().equals(root.getPath())
0448: && element.getEntryKind() == entry.getEntryKind())
0449: return (CPListElement) elements.get(i);
0450: }
0451: CPListElement newElement = CPListElement.createFromExisting(
0452: entry, root.getJavaProject());
0453: elements.add(newElement);
0454: return newElement;
0455: }
0456:
0457: /**
0458: * For a given <code>IResource</code>, try to
0459: * convert it into a <code>IPackageFragmentRoot</code>
0460: * if possible or return <code>null</code> if no
0461: * fragment root could be created.
0462: *
0463: * @param resource the resource to be converted
0464: * @return the <code>resource<code> as
0465: * <code>IPackageFragment</code>,or <code>null</code>
0466: * if failed to convert
0467: */
0468: public static IPackageFragment getFragment(IResource resource) {
0469: IJavaElement elem = JavaCore.create(resource);
0470: if (elem instanceof IPackageFragment)
0471: return (IPackageFragment) elem;
0472: return null;
0473: }
0474:
0475: /**
0476: * Get the source folder of a given <code>IResource</code> element,
0477: * starting with the resource's parent.
0478: *
0479: * @param resource the resource to get the fragment root from
0480: * @param project the Java project
0481: * @param monitor progress monitor, can be <code>null</code>
0482: * @return resolved fragment root, or <code>null</code> the resource is not (in) a source folder
0483: * @throws JavaModelException
0484: */
0485: public static IPackageFragmentRoot getFragmentRoot(
0486: IResource resource, IJavaProject project,
0487: IProgressMonitor monitor) throws JavaModelException {
0488: if (monitor == null)
0489: monitor = new NullProgressMonitor();
0490: IJavaElement javaElem = null;
0491: if (resource.getFullPath().equals(project.getPath()))
0492: return project.getPackageFragmentRoot(resource);
0493: IContainer container = resource.getParent();
0494: do {
0495: if (container instanceof IFolder)
0496: javaElem = JavaCore.create((IFolder) container);
0497: if (container.getFullPath().equals(project.getPath())) {
0498: javaElem = project;
0499: break;
0500: }
0501: container = container.getParent();
0502: if (container == null)
0503: return null;
0504: } while (javaElem == null
0505: || !(javaElem instanceof IPackageFragmentRoot));
0506: if (javaElem instanceof IJavaProject) {
0507: if (!isSourceFolder((IJavaProject) javaElem))
0508: return null;
0509: javaElem = project.getPackageFragmentRoot(project
0510: .getResource());
0511: }
0512: return (IPackageFragmentRoot) javaElem;
0513: }
0514:
0515: /**
0516: * Get the <code>IClasspathEntry</code> for the
0517: * given path by looking up all
0518: * build path entries on the project
0519: *
0520: * @param path the path to find a build path entry for
0521: * @param project the Java project
0522: * @return the <code>IClasspathEntry</code> corresponding
0523: * to the <code>path</code> or <code>null</code> if there
0524: * is no such entry
0525: * @throws JavaModelException
0526: */
0527: public static IClasspathEntry getClasspathEntryFor(IPath path,
0528: IJavaProject project, int entryKind)
0529: throws JavaModelException {
0530: IClasspathEntry[] entries = project.getRawClasspath();
0531: for (int i = 0; i < entries.length; i++) {
0532: IClasspathEntry entry = entries[i];
0533: if (entry.getPath().equals(path)
0534: && equalEntryKind(entry, entryKind))
0535: return entry;
0536: }
0537: return null;
0538: }
0539:
0540: /**
0541: * Check whether the current selection is the project's
0542: * default output folder or not
0543: *
0544: * @param attrib the attribute to be checked
0545: * @return <code>true</code> if is the default output folder,
0546: * <code>false</code> otherwise.
0547: */
0548: public static boolean isDefaultOutputFolder(
0549: CPListElementAttribute attrib) {
0550: return attrib.getValue() == null;
0551: }
0552:
0553: /**
0554: * Determines whether the current selection (of type
0555: * <code>ICompilationUnit</code> or <code>IPackageFragment</code>)
0556: * is on the inclusion filter of it's parent source folder.
0557: *
0558: * @param selection the current Java element
0559: * @param project the Java project
0560: * @param monitor progress monitor, can be <code>null</code>
0561: * @return <code>true</code> if the current selection is included,
0562: * <code>false</code> otherwise.
0563: * @throws JavaModelException
0564: */
0565: public static boolean isIncluded(IJavaElement selection,
0566: IJavaProject project, IProgressMonitor monitor)
0567: throws JavaModelException {
0568: if (monitor == null)
0569: monitor = new NullProgressMonitor();
0570: try {
0571: monitor
0572: .beginTask(
0573: NewWizardMessages.ClasspathModifier_Monitor_ContainsPath,
0574: 4);
0575: IPackageFragmentRoot root = (IPackageFragmentRoot) selection
0576: .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
0577: IClasspathEntry entry = root.getRawClasspathEntry();
0578: if (entry == null)
0579: return false;
0580: return contains(selection.getPath().removeFirstSegments(
0581: root.getPath().segmentCount()), entry
0582: .getInclusionPatterns(), new SubProgressMonitor(
0583: monitor, 2));
0584: } finally {
0585: monitor.done();
0586: }
0587: }
0588:
0589: /**
0590: * Find out whether the <code>IResource</code> excluded or not.
0591: *
0592: * @param resource the resource to be checked
0593: * @param project the Java project
0594: * @return <code>true</code> if the resource is excluded, <code>
0595: * false</code> otherwise
0596: * @throws JavaModelException
0597: */
0598: public static boolean isExcluded(IResource resource,
0599: IJavaProject project) throws JavaModelException {
0600: IPackageFragmentRoot root = getFragmentRoot(resource, project,
0601: null);
0602: if (root == null)
0603: return false;
0604: String fragmentName = getName(resource.getFullPath(), root
0605: .getPath());
0606: fragmentName = completeName(fragmentName);
0607: IClasspathEntry entry = root.getRawClasspathEntry();
0608: return entry != null
0609: && contains(new Path(fragmentName), entry
0610: .getExclusionPatterns(), null);
0611: }
0612:
0613: /**
0614: * Find out whether one of the <code>IResource</code>'s parents
0615: * is excluded.
0616: *
0617: * @param resource check the resources parents whether they are
0618: * excluded or not
0619: * @param project the Java project
0620: * @return <code>true</code> if there is an excluded parent,
0621: * <code>false</code> otherwise
0622: * @throws JavaModelException
0623: */
0624: public static boolean parentExcluded(IResource resource,
0625: IJavaProject project) throws JavaModelException {
0626: if (resource.getFullPath().equals(project.getPath()))
0627: return false;
0628: IPackageFragmentRoot root = getFragmentRoot(resource, project,
0629: null);
0630: if (root == null) {
0631: return true;
0632: }
0633: IPath path = resource.getFullPath().removeFirstSegments(
0634: root.getPath().segmentCount());
0635: IClasspathEntry entry = root.getRawClasspathEntry();
0636: if (entry == null)
0637: return true; // there is no build path entry, this is equal to the fact that the parent is excluded
0638: while (path.segmentCount() > 0) {
0639: if (contains(path, entry.getExclusionPatterns(), null))
0640: return true;
0641: path = path.removeLastSegments(1);
0642: }
0643: return false;
0644: }
0645:
0646: /**
0647: * Check wheter the output location of the <code>IPackageFragmentRoot</code>
0648: * is <code>null</code>. If this holds, then the root
0649: * does use the default output folder.
0650: *
0651: * @param root the root to examine the output location for
0652: * @return <code>true</code> if the root uses the default output folder, <code>false
0653: * </code> otherwise.
0654: * @throws JavaModelException
0655: */
0656: public static boolean hasDefaultOutputFolder(
0657: IPackageFragmentRoot root) throws JavaModelException {
0658: return root.getRawClasspathEntry().getOutputLocation() == null;
0659: }
0660:
0661: /**
0662: * Check whether at least one source folder of the given
0663: * Java project has an output folder set.
0664: *
0665: * @param project the Java project
0666: * @param monitor progress monitor, can be <code>null</code>
0667: * @return <code>true</code> if at least one outputfolder
0668: * is set, <code>false</code> otherwise
0669: * @throws JavaModelException
0670: */
0671: public static boolean hasOutputFolders(IJavaProject project,
0672: IProgressMonitor monitor) throws JavaModelException {
0673: if (monitor == null)
0674: monitor = new NullProgressMonitor();
0675: try {
0676: IPackageFragmentRoot[] roots = project
0677: .getPackageFragmentRoots();
0678: monitor
0679: .beginTask(
0680: NewWizardMessages.ClasspathModifier_Monitor_CheckOutputFolders,
0681: roots.length);
0682: for (int i = 0; i < roots.length; i++) {
0683: if (roots[i].getRawClasspathEntry().getOutputLocation() != null)
0684: return true;
0685: monitor.worked(1);
0686: }
0687: } finally {
0688: monitor.done();
0689: }
0690: return false;
0691: }
0692:
0693: public static String escapeSpecialChars(String value) {
0694: StringBuffer buf = new StringBuffer();
0695: for (int i = 0; i < value.length(); i++) {
0696: char c = value.charAt(i);
0697:
0698: switch (c) {
0699: case '&':
0700: buf.append("&"); //$NON-NLS-1$
0701: break;
0702: case '<':
0703: buf.append("<"); //$NON-NLS-1$
0704: break;
0705: case '>':
0706: buf.append(">"); //$NON-NLS-1$
0707: break;
0708: case '\'':
0709: buf.append("'"); //$NON-NLS-1$
0710: break;
0711: case '\"':
0712: buf.append("""); //$NON-NLS-1$
0713: break;
0714: case 160:
0715: buf.append(" "); //$NON-NLS-1$
0716: break;
0717: default:
0718: buf.append(c);
0719: break;
0720: }
0721: }
0722: return buf.toString();
0723: }
0724:
0725: /**
0726: * Check whether the <code>IJavaProject</code>
0727: * is a source folder
0728: *
0729: * @param project the project to test
0730: * @return <code>true</code> if <code>project</code> is a source folder
0731: * <code>false</code> otherwise.
0732: */
0733: public static boolean isSourceFolder(IJavaProject project)
0734: throws JavaModelException {
0735: return ClasspathModifier.getClasspathEntryFor(
0736: project.getPath(), project, IClasspathEntry.CPE_SOURCE) != null;
0737: }
0738:
0739: /**
0740: * Check whether the <code>IPackageFragment</code>
0741: * corresponds to the project's default fragment.
0742: *
0743: * @param fragment the package fragment to be checked
0744: * @return <code>true</code> if is the default package fragment,
0745: * <code>false</code> otherwise.
0746: */
0747: public static boolean isDefaultFragment(IPackageFragment fragment) {
0748: return fragment.getElementName().length() == 0;
0749: }
0750:
0751: /**
0752: * Determines whether the inclusion filter of the element's source folder is empty
0753: * or not
0754: * @return <code>true</code> if the inclusion filter is empty,
0755: * <code>false</code> otherwise.
0756: * @throws JavaModelException
0757: */
0758: public static boolean includeFiltersEmpty(IResource resource,
0759: IJavaProject project, IProgressMonitor monitor)
0760: throws JavaModelException {
0761: if (monitor == null)
0762: monitor = new NullProgressMonitor();
0763: try {
0764: monitor
0765: .beginTask(
0766: NewWizardMessages.ClasspathModifier_Monitor_ExamineInputFilters,
0767: 4);
0768: IPackageFragmentRoot root = getFragmentRoot(resource,
0769: project, new SubProgressMonitor(monitor, 4));
0770: if (root != null) {
0771: IClasspathEntry entry = root.getRawClasspathEntry();
0772: return entry.getInclusionPatterns().length == 0;
0773: }
0774: return true;
0775: } finally {
0776: monitor.done();
0777: }
0778: }
0779:
0780: /**
0781: * Check whether the input paramenter of type <code>
0782: * IPackageFragmentRoot</code> has either it's inclusion or
0783: * exclusion filter or both set (that means they are
0784: * not empty).
0785: *
0786: * @param root the fragment root to be inspected
0787: * @return <code>true</code> inclusion or exclusion filter set,
0788: * <code>false</code> otherwise.
0789: */
0790: public static boolean filtersSet(IPackageFragmentRoot root)
0791: throws JavaModelException {
0792: if (root == null)
0793: return false;
0794: IClasspathEntry entry = root.getRawClasspathEntry();
0795: IPath[] inclusions = entry.getInclusionPatterns();
0796: IPath[] exclusions = entry.getExclusionPatterns();
0797: if (inclusions != null && inclusions.length > 0)
0798: return true;
0799: if (exclusions != null && exclusions.length > 0)
0800: return true;
0801: return false;
0802: }
0803:
0804: /**
0805: * Add a resource to the build path.
0806: *
0807: * @param resource the resource to be added to the build path
0808: * @param project the Java project
0809: * @param monitor progress monitor, can be <code>null</code>
0810: * @return returns the new element of type <code>IPackageFragmentRoot</code> that has been added to the build path
0811: * @throws CoreException
0812: * @throws OperationCanceledException
0813: */
0814: public static CPListElement addToClasspath(IResource resource,
0815: List existingEntries, List newEntries,
0816: IJavaProject project, IProgressMonitor monitor)
0817: throws OperationCanceledException, CoreException {
0818: if (monitor == null)
0819: monitor = new NullProgressMonitor();
0820: try {
0821: monitor
0822: .beginTask(
0823: NewWizardMessages.ClasspathModifier_Monitor_AddToBuildpath,
0824: 2);
0825: exclude(resource.getFullPath(), existingEntries,
0826: newEntries, project, new SubProgressMonitor(
0827: monitor, 1));
0828: CPListElement entry = new CPListElement(project,
0829: IClasspathEntry.CPE_SOURCE, resource.getFullPath(),
0830: resource);
0831: return entry;
0832: } finally {
0833: monitor.done();
0834: }
0835: }
0836:
0837: /**
0838: * Check whether the provided file is an archive (.jar or .zip).
0839: *
0840: * @param file the file to be checked
0841: * @param project the Java project
0842: * @return <code>true</code> if the file is an archive, <code>false</code>
0843: * otherwise
0844: * @throws JavaModelException
0845: */
0846: public static boolean isArchive(IFile file, IJavaProject project)
0847: throws JavaModelException {
0848: if (!ArchiveFileFilter.isArchivePath(file.getFullPath()))
0849: return false;
0850: if (project != null
0851: && project.exists()
0852: && (project.findPackageFragmentRoot(file.getFullPath()) == null))
0853: return true;
0854: return false;
0855: }
0856:
0857: /**
0858: * Add a Java element to the build path.
0859: *
0860: * @param javaElement element to be added to the build path
0861: * @param project the Java project
0862: * @param monitor progress monitor, can be <code>null</code>
0863: * @return returns the new element of type <code>IPackageFragmentRoot</code> that has been added to the build path
0864: * @throws CoreException
0865: * @throws OperationCanceledException
0866: */
0867: public static CPListElement addToClasspath(
0868: IJavaElement javaElement, List existingEntries,
0869: List newEntries, IJavaProject project,
0870: IProgressMonitor monitor)
0871: throws OperationCanceledException, CoreException {
0872: if (monitor == null)
0873: monitor = new NullProgressMonitor();
0874: try {
0875: monitor
0876: .beginTask(
0877: NewWizardMessages.ClasspathModifier_Monitor_AddToBuildpath,
0878: 10);
0879: CPListElement entry = new CPListElement(project,
0880: IClasspathEntry.CPE_SOURCE, javaElement.getPath(),
0881: javaElement.getResource());
0882: return entry;
0883: } finally {
0884: monitor.done();
0885: }
0886: }
0887:
0888: /**
0889: * Remove the Java project from the build path
0890: *
0891: * @param project the project to be removed
0892: * @param existingEntries a list of existing <code>CPListElement</code>. This list
0893: * will be traversed and the entry for the project will be removed.
0894: * @param monitor progress monitor, can be <code>null</code>
0895: * @return returns the Java project
0896: */
0897: public static IJavaProject removeFromClasspath(
0898: IJavaProject project, List existingEntries,
0899: IProgressMonitor monitor) {
0900: CPListElement elem = getListElement(project.getPath(),
0901: existingEntries);
0902: if (elem != null) {
0903: existingEntries.remove(elem);
0904: }
0905: return project;
0906: }
0907:
0908: /**
0909: * Remove <code>path</code> from inclusion/exlusion filters in all <code>existingEntries</code>
0910: *
0911: * @param path the path to remove
0912: * @param project the Java project
0913: * @param existingEntries a list of <code>CPListElement</code> representing the build path
0914: * entries of the project.
0915: * @return returns a <code>List</code> of <code>CPListElement</code> of modified elements, not null.
0916: */
0917: public static List removeFilters(IPath path, IJavaProject project,
0918: List existingEntries) {
0919: if (path == null)
0920: return Collections.EMPTY_LIST;
0921:
0922: IPath projPath = project.getPath();
0923: if (projPath.isPrefixOf(path)) {
0924: path = path.removeFirstSegments(projPath.segmentCount())
0925: .addTrailingSeparator();
0926: }
0927:
0928: List result = new ArrayList();
0929: for (Iterator iter = existingEntries.iterator(); iter.hasNext();) {
0930: CPListElement element = (CPListElement) iter.next();
0931: boolean hasChange = false;
0932: IPath[] exlusions = (IPath[]) element
0933: .getAttribute(CPListElement.EXCLUSION);
0934: if (exlusions != null) {
0935: List exlusionList = new ArrayList(exlusions.length);
0936: for (int i = 0; i < exlusions.length; i++) {
0937: if (!exlusions[i].equals(path)) {
0938: exlusionList.add(exlusions[i]);
0939: } else {
0940: hasChange = true;
0941: }
0942: }
0943: element.setAttribute(CPListElement.EXCLUSION,
0944: exlusionList.toArray(new IPath[exlusionList
0945: .size()]));
0946: }
0947:
0948: IPath[] inclusion = (IPath[]) element
0949: .getAttribute(CPListElement.INCLUSION);
0950: if (inclusion != null) {
0951: List inclusionList = new ArrayList(inclusion.length);
0952: for (int i = 0; i < inclusion.length; i++) {
0953: if (!inclusion[i].equals(path)) {
0954: inclusionList.add(inclusion[i]);
0955: } else {
0956: hasChange = true;
0957: }
0958: }
0959: element.setAttribute(CPListElement.INCLUSION,
0960: inclusionList.toArray(new IPath[inclusionList
0961: .size()]));
0962: }
0963: if (hasChange) {
0964: result.add(element);
0965: }
0966: }
0967: return result;
0968: }
0969:
0970: /**
0971: * Exclude an element with a given name and absolute path
0972: * from the build path.
0973: *
0974: * @param name the name of the element to be excluded
0975: * @param fullPath the absolute path of the element
0976: * @param entry the build path entry to be modified
0977: * @param project the Java project
0978: * @param monitor progress monitor, can be <code>null</code>
0979: * @return a <code>IResource</code> corresponding to the excluded element
0980: * @throws JavaModelException
0981: */
0982: private static IResource exclude(String name, IPath fullPath,
0983: CPListElement entry, IJavaProject project,
0984: IProgressMonitor monitor) throws JavaModelException {
0985: if (monitor == null)
0986: monitor = new NullProgressMonitor();
0987: IResource result;
0988: try {
0989: monitor
0990: .beginTask(
0991: NewWizardMessages.ClasspathModifier_Monitor_Excluding,
0992: 6);
0993: IPath[] excludedPath = (IPath[]) entry
0994: .getAttribute(CPListElement.EXCLUSION);
0995: IPath[] newExcludedPath = new IPath[excludedPath.length + 1];
0996: name = completeName(name);
0997: IPath path = new Path(name);
0998: if (!contains(path, excludedPath, new SubProgressMonitor(
0999: monitor, 2))) {
1000: System.arraycopy(excludedPath, 0, newExcludedPath, 0,
1001: excludedPath.length);
1002: newExcludedPath[excludedPath.length] = path;
1003: entry.setAttribute(CPListElement.EXCLUSION,
1004: newExcludedPath);
1005: entry.setAttribute(CPListElement.INCLUSION, remove(
1006: path, (IPath[]) entry
1007: .getAttribute(CPListElement.INCLUSION),
1008: new SubProgressMonitor(monitor, 4)));
1009: }
1010: result = fullPath == null ? null : getResource(fullPath,
1011: project);
1012: } finally {
1013: monitor.done();
1014: }
1015: return result;
1016: }
1017:
1018: /**
1019: * Exclude an object at a given path.
1020: * This means that the exclusion filter for the
1021: * corresponding <code>IPackageFragmentRoot</code> needs to be modified.
1022: *
1023: * First, the fragment root needs to be found. To do so, the new entries
1024: * are and the existing entries are traversed for a match and the entry
1025: * with the path is removed from one of those lists.
1026: *
1027: * Note: the <code>IJavaElement</code>'s fragment (if there is one)
1028: * is not allowed to be excluded! However, inclusion (or simply no
1029: * filter) on the parent fragment is allowed.
1030: *
1031: * @param path absolute path of an object to be excluded
1032: * @param existingEntries a list of existing build path entries
1033: * @param newEntries a list of new build path entries
1034: * @param project the Java project
1035: * @param monitor progress monitor, can be <code>null</code>
1036: */
1037: public static void exclude(IPath path, List existingEntries,
1038: List newEntries, IJavaProject project,
1039: IProgressMonitor monitor) throws JavaModelException {
1040: if (monitor == null)
1041: monitor = new NullProgressMonitor();
1042: try {
1043: monitor
1044: .beginTask(
1045: NewWizardMessages.ClasspathModifier_Monitor_Excluding,
1046: 1);
1047: CPListElement elem = null;
1048: CPListElement existingElem = null;
1049: int i = 0;
1050: do {
1051: i++;
1052: IPath rootPath = path.removeLastSegments(i);
1053:
1054: if (rootPath.segmentCount() == 0)
1055: return;
1056:
1057: elem = getListElement(rootPath, newEntries);
1058: existingElem = getListElement(rootPath, existingEntries);
1059: } while (existingElem == null && elem == null);
1060: if (elem == null) {
1061: elem = existingElem;
1062: }
1063: exclude(path.removeFirstSegments(path.segmentCount() - i)
1064: .toString(), null, elem, project,
1065: new SubProgressMonitor(monitor, 1));
1066: } finally {
1067: monitor.done();
1068: }
1069: }
1070:
1071: /**
1072: * Exclude a <code>IJavaElement</code>. This means that the exclusion filter for the
1073: * corresponding <code>IPackageFragmentRoot</code>s need to be modified.
1074: *
1075: * Note: the <code>IJavaElement</code>'s fragment (if there is one)
1076: * is not allowed to be excluded! However, inclusion (or simply no
1077: * filter) on the parent fragment is allowed.
1078: *
1079: * @param javaElement the Java element to be excluded
1080: * @param entry the <code>CPListElement</code> representing the
1081: * <code>IClasspathEntry</code> of the Java element's root.
1082: * @param project the Java project
1083: * @param monitor progress monitor, can be <code>null</code>
1084: *
1085: * @return the resulting <code>IResource<code>
1086: * @throws JavaModelException
1087: */
1088: public static IResource exclude(IJavaElement javaElement,
1089: CPListElement entry, IJavaProject project,
1090: IProgressMonitor monitor) throws JavaModelException {
1091: if (monitor == null)
1092: monitor = new NullProgressMonitor();
1093: try {
1094: String name = getName(javaElement.getPath(), entry
1095: .getPath());
1096: return exclude(name, javaElement.getPath(), entry, project,
1097: new SubProgressMonitor(monitor, 1));
1098: } finally {
1099: monitor.done();
1100: }
1101: }
1102:
1103: /**
1104: * Inverse operation to <code>exclude</code>.
1105: * The resource removed from it's fragment roots exlusion filter.
1106: *
1107: * Note: the <code>IJavaElement</code>'s fragment (if there is one)
1108: * is not allowed to be excluded! However, inclusion (or simply no
1109: * filter) on the parent fragment is allowed.
1110: *
1111: * @param resource the resource to be unexcluded
1112: * @param entry the <code>CPListElement</code> representing the
1113: * <code>IClasspathEntry</code> of the resource's root.
1114: * @param project the Java project
1115: * @param monitor progress monitor, can be <code>null</code>
1116: * @throws JavaModelException
1117: *
1118: */
1119: public static void unExclude(IResource resource,
1120: CPListElement entry, IJavaProject project,
1121: IProgressMonitor monitor) throws JavaModelException {
1122: if (monitor == null)
1123: monitor = new NullProgressMonitor();
1124: try {
1125: monitor
1126: .beginTask(
1127: NewWizardMessages.ClasspathModifier_Monitor_RemoveExclusion,
1128: 10);
1129: String name = getName(resource.getFullPath(), entry
1130: .getPath());
1131: IPath[] excludedPath = (IPath[]) entry
1132: .getAttribute(CPListElement.EXCLUSION);
1133: IPath[] newExcludedPath = remove(new Path(
1134: completeName(name)), excludedPath,
1135: new SubProgressMonitor(monitor, 3));
1136: entry
1137: .setAttribute(CPListElement.EXCLUSION,
1138: newExcludedPath);
1139: } finally {
1140: monitor.done();
1141: }
1142: }
1143:
1144: /**
1145: * Resets inclusion and exclusion filters for the given
1146: * <code>IJavaElement</code>
1147: *
1148: * @param element element to reset it's filters
1149: * @param entry the <code>CPListElement</code> to reset its filters for
1150: * @param project the Java project
1151: * @param monitor progress monitor, can be <code>null</code>
1152: * @throws JavaModelException
1153: */
1154: public static void resetFilters(IJavaElement element,
1155: CPListElement entry, IJavaProject project,
1156: IProgressMonitor monitor) throws JavaModelException {
1157: if (monitor == null)
1158: monitor = new NullProgressMonitor();
1159: try {
1160: monitor
1161: .beginTask(
1162: NewWizardMessages.ClasspathModifier_Monitor_ResetFilters,
1163: 3);
1164:
1165: List exclusionList = getFoldersOnCP(element.getPath(),
1166: project, new SubProgressMonitor(monitor, 2));
1167: IPath outputLocation = (IPath) entry
1168: .getAttribute(CPListElement.OUTPUT);
1169: if (outputLocation != null) {
1170: IPath[] exclusionPatterns = (IPath[]) entry
1171: .getAttribute(CPListElement.EXCLUSION);
1172: if (contains(new Path(completeName(outputLocation
1173: .lastSegment())), exclusionPatterns, null)) {
1174: exclusionList
1175: .add(new Path(completeName(outputLocation
1176: .lastSegment())));
1177: }
1178: }
1179: IPath[] exclusions = (IPath[]) exclusionList
1180: .toArray(new IPath[exclusionList.size()]);
1181:
1182: entry.setAttribute(CPListElement.INCLUSION, new IPath[0]);
1183: entry.setAttribute(CPListElement.EXCLUSION, exclusions);
1184: } finally {
1185: monitor.done();
1186: }
1187: }
1188:
1189: /**
1190: * Reset the output folder for the given entry to the default output folder
1191: *
1192: * @param entry the <code>CPListElement</code> to be edited
1193: * @param project the Java project
1194: * @return an attribute representing the modified output folder
1195: * @throws JavaModelException
1196: */
1197: public static CPListElementAttribute resetOutputFolder(
1198: CPListElement entry, IJavaProject project)
1199: throws JavaModelException {
1200: entry.setAttribute(CPListElement.OUTPUT, null);
1201: CPListElementAttribute outputFolder = new CPListElementAttribute(
1202: entry, CPListElement.OUTPUT, entry
1203: .getAttribute(CPListElement.OUTPUT), true);
1204: return outputFolder;
1205: }
1206:
1207: /**
1208: * Try to find the corresponding and modified <code>CPListElement</code> for the provided
1209: * <code>CPListElement</code> in the list of elements and return it.
1210: * If no one can be found, the provided <code>CPListElement</code> is returned.
1211: *
1212: * @param elements a list of <code>CPListElements</code>
1213: * @param cpElement the <code>CPListElement</code> to find the corresponding entry in
1214: * the list
1215: * @return the <code>CPListElement</code> found in the list (matching by using the path) or
1216: * the second <code>CPListElement</code> parameter itself if there is no match.
1217: */
1218: public static CPListElement getClasspathEntry(List elements,
1219: CPListElement cpElement) {
1220: for (int i = 0; i < elements.size(); i++) {
1221: if (((CPListElement) elements.get(i)).getPath().equals(
1222: cpElement.getPath()))
1223: return (CPListElement) elements.get(i);
1224: }
1225: elements.add(cpElement);
1226: return cpElement;
1227: }
1228:
1229: /**
1230: * For a given path, find the corresponding element in the list.
1231: *
1232: * @param path the path to found an entry for
1233: * @param elements a list of <code>CPListElement</code>s
1234: * @return the mathed <code>CPListElement</code> or <code>null</code> if
1235: * no match could be found
1236: */
1237: public static CPListElement getListElement(IPath path, List elements) {
1238: for (int i = 0; i < elements.size(); i++) {
1239: CPListElement element = (CPListElement) elements.get(i);
1240: if (element.getEntryKind() == IClasspathEntry.CPE_SOURCE
1241: && element.getPath().equals(path)) {
1242: return element;
1243: }
1244: }
1245: return null;
1246: }
1247:
1248: public static void commitClassPath(List newEntries,
1249: IJavaProject project, IProgressMonitor monitor)
1250: throws JavaModelException {
1251: if (monitor == null)
1252: monitor = new NullProgressMonitor();
1253:
1254: monitor.beginTask("", 2); //$NON-NLS-1$
1255:
1256: try {
1257: IClasspathEntry[] entries = convert(newEntries);
1258: IPath outputLocation = project.getOutputLocation();
1259:
1260: IJavaModelStatus status = JavaConventions
1261: .validateClasspath(project, entries, outputLocation);
1262: if (!status.isOK())
1263: throw new JavaModelException(status);
1264:
1265: project.setRawClasspath(entries, outputLocation,
1266: new SubProgressMonitor(monitor, 2));
1267: } finally {
1268: monitor.done();
1269: }
1270: }
1271:
1272: public static void commitClassPath(CPJavaProject cpProject,
1273: IProgressMonitor monitor) throws JavaModelException {
1274: if (monitor == null)
1275: monitor = new NullProgressMonitor();
1276:
1277: monitor.beginTask("", 2); //$NON-NLS-1$
1278:
1279: try {
1280: IClasspathEntry[] entries = convert(cpProject
1281: .getCPListElements());
1282: IPath outputLocation = cpProject.getDefaultOutputLocation();
1283:
1284: IJavaModelStatus status = JavaConventions
1285: .validateClasspath(cpProject.getJavaProject(),
1286: entries, outputLocation);
1287: if (!status.isOK())
1288: throw new JavaModelException(status);
1289:
1290: cpProject.getJavaProject().setRawClasspath(entries,
1291: outputLocation, new SubProgressMonitor(monitor, 2));
1292: } finally {
1293: monitor.done();
1294: }
1295: }
1296:
1297: /**
1298: * For a given list of entries, find out what representation they
1299: * will have in the project and return a list with corresponding
1300: * elements.
1301: *
1302: * @param entries a list of entries to find an appropriate representation
1303: * for. The list can contain elements of two types:
1304: * <li><code>IResource</code></li>
1305: * <li><code>IJavaElement</code></li>
1306: * @param project the Java project
1307: * @return a list of elements corresponding to the passed entries.
1308: */
1309: public static List getCorrespondingElements(List entries,
1310: IJavaProject project) {
1311: List result = new ArrayList();
1312: for (int i = 0; i < entries.size(); i++) {
1313: Object element = entries.get(i);
1314: IPath path;
1315: if (element instanceof IResource)
1316: path = ((IResource) element).getFullPath();
1317: else
1318: path = ((IJavaElement) element).getPath();
1319: IResource resource = getResource(path, project);
1320: if (resource != null) {
1321: IJavaElement elem = JavaCore.create(resource);
1322: if (elem != null && project.isOnClasspath(elem))
1323: result.add(elem);
1324: else
1325: result.add(resource);
1326: }
1327:
1328: }
1329: return result;
1330: }
1331:
1332: /**
1333: * Returns for the given absolute path the corresponding
1334: * resource, this is either element of type <code>IFile</code>
1335: * or <code>IFolder</code>.
1336: *
1337: * @param path an absolute path to a resource
1338: * @param project the Java project
1339: * @return the resource matching to the path. Can be
1340: * either an <code>IFile</code> or an <code>IFolder</code>.
1341: */
1342: private static IResource getResource(IPath path,
1343: IJavaProject project) {
1344: return project.getProject().getWorkspace().getRoot()
1345: .findMember(path);
1346: }
1347:
1348: /**
1349: * Find out whether the provided path equals to one
1350: * in the array.
1351: *
1352: * @param path path to find an equivalent for
1353: * @param paths set of paths to compare with
1354: * @param monitor progress monitor, can be <code>null</code>
1355: * @return <code>true</code> if there is an occurrence, <code>
1356: * false</code> otherwise
1357: */
1358: private static boolean contains(IPath path, IPath[] paths,
1359: IProgressMonitor monitor) {
1360: if (monitor == null)
1361: monitor = new NullProgressMonitor();
1362: if (path == null)
1363: return false;
1364: try {
1365: monitor
1366: .beginTask(
1367: NewWizardMessages.ClasspathModifier_Monitor_ComparePaths,
1368: paths.length);
1369: if (path.getFileExtension() == null)
1370: path = new Path(completeName(path.toString()));
1371: for (int i = 0; i < paths.length; i++) {
1372: if (paths[i].equals(path))
1373: return true;
1374: monitor.worked(1);
1375: }
1376: } finally {
1377: monitor.done();
1378: }
1379: return false;
1380: }
1381:
1382: /**
1383: * Add a '/' at the end of the name if
1384: * it does not end with '.java', or other Java-like extension.
1385: *
1386: * @param name append '/' at the end if
1387: * necessary
1388: * @return modified string
1389: */
1390: private static String completeName(String name) {
1391: if (!JavaCore.isJavaLikeFileName(name)) {
1392: name = name + "/"; //$NON-NLS-1$
1393: name = name.replace('.', '/');
1394: return name;
1395: }
1396: return name;
1397: }
1398:
1399: /**
1400: * Removes <code>path</code> out of the set of given <code>
1401: * paths</code>. If the path is not contained, then the
1402: * initially provided array of paths is returned.
1403: *
1404: * Only the first occurrence will be removed.
1405: *
1406: * @param path path to be removed
1407: * @param paths array of path to apply the removal on
1408: * @param monitor progress monitor, can be <code>null</code>
1409: * @return array which does not contain <code>path</code>
1410: */
1411: private static IPath[] remove(IPath path, IPath[] paths,
1412: IProgressMonitor monitor) {
1413: if (monitor == null)
1414: monitor = new NullProgressMonitor();
1415: try {
1416: monitor
1417: .beginTask(
1418: NewWizardMessages.ClasspathModifier_Monitor_RemovePath,
1419: paths.length + 5);
1420: if (!contains(path, paths, new SubProgressMonitor(monitor,
1421: 5)))
1422: return paths;
1423:
1424: ArrayList newPaths = new ArrayList();
1425: for (int i = 0; i < paths.length; i++) {
1426: monitor.worked(1);
1427: if (!paths[i].equals(path))
1428: newPaths.add(paths[i]);
1429: }
1430:
1431: return (IPath[]) newPaths
1432: .toArray(new IPath[newPaths.size()]);
1433: } finally {
1434: monitor.done();
1435: }
1436:
1437: }
1438:
1439: /**
1440: * Find all folders that are on the build path and
1441: * <code>path</code> is a prefix of those folders
1442: * path entry, that is, all folders which are a
1443: * subfolder of <code>path</code>.
1444: *
1445: * For example, if <code>path</code>=/MyProject/src
1446: * then all folders having a path like /MyProject/src/*,
1447: * where * can be any valid string are returned if
1448: * they are also on the project's build path.
1449: *
1450: * @param path absolute path
1451: * @param project the Java project
1452: * @param monitor progress monitor, can be <code>null</code>
1453: * @return an array of paths which belong to subfolders
1454: * of <code>path</code> and which are on the build path
1455: * @throws JavaModelException
1456: */
1457: private static List getFoldersOnCP(IPath path,
1458: IJavaProject project, IProgressMonitor monitor)
1459: throws JavaModelException {
1460: if (monitor == null)
1461: monitor = new NullProgressMonitor();
1462: List srcFolders = new ArrayList();
1463: IClasspathEntry[] cpEntries = project.getRawClasspath();
1464: for (int i = 0; i < cpEntries.length; i++) {
1465: IPath cpPath = cpEntries[i].getPath();
1466: if (path.isPrefixOf(cpPath)
1467: && path.segmentCount() + 1 == cpPath.segmentCount())
1468: srcFolders.add(new Path(completeName(cpPath
1469: .lastSegment())));
1470: }
1471: return srcFolders;
1472: }
1473:
1474: /**
1475: * Returns a string corresponding to the <code>path</code>
1476: * with the <code>rootPath<code>'s number of segments
1477: * removed
1478: *
1479: * @param path path to remove segments
1480: * @param rootPath provides the number of segments to
1481: * be removed
1482: * @return a string corresponding to the mentioned
1483: * action
1484: */
1485: private static String getName(IPath path, IPath rootPath) {
1486: return path.removeFirstSegments(rootPath.segmentCount())
1487: .toString();
1488: }
1489:
1490: /**
1491: * Sets and validates the new entries. Note that the elments of
1492: * the list containing the new entries will be added to the list of
1493: * existing entries (therefore, there is no return list for this method).
1494: *
1495: * @param existingEntries a list of existing classpath entries
1496: * @param newEntries a list of entries to be added to the existing ones
1497: * @param project the Java project
1498: * @param monitor a progress monitor, can be <code>null</code>
1499: * @throws CoreException in case that validation on one of the new entries fails
1500: */
1501: public static void setNewEntry(List existingEntries,
1502: List newEntries, IJavaProject project,
1503: IProgressMonitor monitor) throws CoreException {
1504: try {
1505: monitor
1506: .beginTask(
1507: NewWizardMessages.ClasspathModifier_Monitor_SetNewEntry,
1508: existingEntries.size());
1509: for (int i = 0; i < newEntries.size(); i++) {
1510: CPListElement entry = (CPListElement) newEntries.get(i);
1511: validateAndAddEntry(entry, existingEntries, project);
1512: monitor.worked(1);
1513: }
1514: } finally {
1515: monitor.done();
1516: }
1517: }
1518:
1519: /**
1520: * Convert a list of <code>CPListElement</code>s to
1521: * an array of <code>IClasspathEntry</code>.
1522: *
1523: * @param list the list to be converted
1524: * @return an array containing build path entries
1525: * corresponding to the list
1526: */
1527: private static IClasspathEntry[] convert(List list) {
1528: IClasspathEntry[] entries = new IClasspathEntry[list.size()];
1529: for (int i = 0; i < list.size(); i++) {
1530: CPListElement element = (CPListElement) list.get(i);
1531: entries[i] = element.getClasspathEntry();
1532: }
1533: return entries;
1534: }
1535:
1536: /**
1537: * Validate the new entry in the context of the existing entries. Furthermore,
1538: * check if exclusion filters need to be applied and do so if necessary.
1539: *
1540: * If validation was successfull, add the new entry to the list of existing entries.
1541: *
1542: * @param entry the entry to be validated and added to the list of existing entries.
1543: * @param existingEntries a list of existing entries representing the build path
1544: * @param project the Java project
1545: * @throws CoreException in case that validation fails
1546: */
1547: private static void validateAndAddEntry(CPListElement entry,
1548: List existingEntries, IJavaProject project)
1549: throws CoreException {
1550: IPath path = entry.getPath();
1551: IPath projPath = project.getProject().getFullPath();
1552: IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace()
1553: .getRoot();
1554: IStatus validate = workspaceRoot.getWorkspace().validatePath(
1555: path.toString(), IResource.FOLDER);
1556: StatusInfo rootStatus = new StatusInfo();
1557: rootStatus.setOK();
1558: boolean isExternal = isExternalArchiveOrLibrary(entry, project);
1559: if (!isExternal && validate.matches(IStatus.ERROR)
1560: && !project.getPath().equals(path)) {
1561: rootStatus
1562: .setError(Messages
1563: .format(
1564: NewWizardMessages.NewSourceFolderWizardPage_error_InvalidRootName,
1565: validate.getMessage()));
1566: throw new CoreException(rootStatus);
1567: } else {
1568: if (!isExternal && !project.getPath().equals(path)) {
1569: IResource res = workspaceRoot.findMember(path);
1570: if (res != null) {
1571: if (res.getType() != IResource.FOLDER
1572: && res.getType() != IResource.FILE) {
1573: rootStatus
1574: .setError(NewWizardMessages.NewSourceFolderWizardPage_error_NotAFolder);
1575: throw new CoreException(rootStatus);
1576: }
1577: } else {
1578: URI projLocation = project.getProject()
1579: .getLocationURI();
1580: if (projLocation != null) {
1581: IFileStore store = EFS.getStore(projLocation)
1582: .getChild(path);
1583: if (store.fetchInfo().exists()) {
1584: rootStatus
1585: .setError(NewWizardMessages.NewSourceFolderWizardPage_error_AlreadyExistingDifferentCase);
1586: throw new CoreException(rootStatus);
1587: }
1588: }
1589: }
1590: }
1591:
1592: for (int i = 0; i < existingEntries.size(); i++) {
1593: CPListElement curr = (CPListElement) existingEntries
1594: .get(i);
1595: if (curr.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
1596: if (path.equals(curr.getPath())
1597: && !project.getPath().equals(path)) {
1598: rootStatus
1599: .setError(NewWizardMessages.NewSourceFolderWizardPage_error_AlreadyExisting);
1600: throw new CoreException(rootStatus);
1601: }
1602: }
1603: }
1604:
1605: if (!isExternal
1606: && !entry.getPath().equals(project.getPath()))
1607: exclude(entry.getPath(), existingEntries,
1608: new ArrayList(), project, null);
1609:
1610: IPath outputLocation = project.getOutputLocation();
1611: insertAtEndOfCategory(entry, existingEntries);
1612:
1613: IClasspathEntry[] entries = convert(existingEntries);
1614:
1615: IJavaModelStatus status = JavaConventions
1616: .validateClasspath(project, entries, outputLocation);
1617: if (!status.isOK()) {
1618: if (outputLocation.equals(projPath)) {
1619: IStatus status2 = JavaConventions
1620: .validateClasspath(project, entries,
1621: outputLocation);
1622: if (status2.isOK()) {
1623: if (project.isOnClasspath(project)) {
1624: rootStatus
1625: .setInfo(Messages
1626: .format(
1627: NewWizardMessages.NewSourceFolderWizardPage_warning_ReplaceSFandOL,
1628: outputLocation
1629: .makeRelative()
1630: .toString()));
1631: } else {
1632: rootStatus
1633: .setInfo(Messages
1634: .format(
1635: NewWizardMessages.NewSourceFolderWizardPage_warning_ReplaceOL,
1636: outputLocation
1637: .makeRelative()
1638: .toString()));
1639: }
1640: return;
1641: }
1642: }
1643: rootStatus.setError(status.getMessage());
1644: throw new CoreException(rootStatus);
1645: }
1646:
1647: if (isSourceFolder(project)
1648: || project.getPath().equals(path)) {
1649: rootStatus
1650: .setWarning(NewWizardMessages.NewSourceFolderWizardPage_warning_ReplaceSF);
1651: return;
1652: }
1653:
1654: rootStatus.setOK();
1655: return;
1656: }
1657: }
1658:
1659: private static void insertAtEndOfCategory(CPListElement entry,
1660: List existingEntries) {
1661: int length = existingEntries.size();
1662: CPListElement[] elements = (CPListElement[]) existingEntries
1663: .toArray(new CPListElement[length]);
1664: int i = 0;
1665: while (i < length
1666: && elements[i].getClasspathEntry().getEntryKind() != entry
1667: .getClasspathEntry().getEntryKind()) {
1668: i++;
1669: }
1670: if (i < length) {
1671: i++;
1672: while (i < length
1673: && elements[i].getClasspathEntry().getEntryKind() == entry
1674: .getClasspathEntry().getEntryKind()) {
1675: i++;
1676: }
1677: existingEntries.add(i, entry);
1678: return;
1679: }
1680:
1681: switch (entry.getClasspathEntry().getEntryKind()) {
1682: case IClasspathEntry.CPE_SOURCE:
1683: existingEntries.add(0, entry);
1684: break;
1685: case IClasspathEntry.CPE_CONTAINER:
1686: case IClasspathEntry.CPE_LIBRARY:
1687: case IClasspathEntry.CPE_PROJECT:
1688: case IClasspathEntry.CPE_VARIABLE:
1689: default:
1690: existingEntries.add(entry);
1691: break;
1692: }
1693: }
1694:
1695: private static boolean isExternalArchiveOrLibrary(
1696: CPListElement entry, IJavaProject project) {
1697: if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY
1698: || entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
1699: if (entry.getResource() instanceof IFolder) {
1700: return false;
1701: }
1702: return true;
1703: }
1704: return false;
1705: }
1706:
1707: /**
1708: * Test if the provided kind is of type
1709: * <code>IClasspathEntry.CPE_SOURCE</code>
1710: *
1711: * @param entry the classpath entry to be compared with the provided type
1712: * @param kind the kind to be checked
1713: * @return <code>true</code> if kind equals
1714: * <code>IClasspathEntry.CPE_SOURCE</code>,
1715: * <code>false</code> otherwise
1716: */
1717: private static boolean equalEntryKind(IClasspathEntry entry,
1718: int kind) {
1719: return entry.getEntryKind() == kind;
1720: }
1721:
1722: public static OutputFolderValidator getValidator(
1723: final List newElements, final IJavaProject project)
1724: throws JavaModelException {
1725: return new OutputFolderValidator(newElements, project) {
1726:
1727: public boolean validate(IPath outputLocation) {
1728: for (int i = 0; i < newElements.size(); i++) {
1729: if (isInvalid(newElements.get(i), outputLocation))
1730: return false;
1731: }
1732:
1733: for (int i = 0; i < fEntries.length; i++) {
1734: if (isInvalid(fEntries[i], outputLocation))
1735: return false;
1736: }
1737: return true;
1738: }
1739:
1740: /**
1741: * Check if the output location for the given object is valid
1742: *
1743: * @param object the object to retrieve its path from and compare it
1744: * to the output location
1745: * @param outputLocation the output location
1746: * @return <code>true</code> if the output location is invalid, that is,
1747: * if it is a subfolder of the provided object.
1748: */
1749: private boolean isInvalid(Object object,
1750: IPath outputLocation) {
1751: IPath path = null;
1752: if (object instanceof IFolder)
1753: path = getFolderPath(object);
1754: else if (object instanceof IJavaElement)
1755: path = getJavaElementPath(object);
1756: else if (object instanceof IClasspathEntry)
1757: path = getCPEntryPath(object);
1758: return isSubFolderOf(path, outputLocation);
1759: }
1760:
1761: /**
1762: * Get an <code>IFolder</code>'s path
1763: *
1764: * @param element an element which is of type <code>IFolder</code>
1765: * @return the path of the folder
1766: */
1767: private IPath getFolderPath(Object element) {
1768: return ((IFolder) element).getFullPath();
1769: }
1770:
1771: /**
1772: * Get an <code>IJavaElement</code>'s path
1773: *
1774: * @param element an element which is of type <code>IJavaElement</code>
1775: * @return the path of the Java element
1776: */
1777: private IPath getJavaElementPath(Object element) {
1778: return ((IJavaElement) element).getPath();
1779: }
1780:
1781: /**
1782: * Get an <code>IClasspathEntry</code>'s path
1783: *
1784: * @param entry an element which is of type <code>IClasspathEntry</code>
1785: * @return the path of the classpath entry
1786: */
1787: private IPath getCPEntryPath(Object entry) {
1788: return ((IClasspathEntry) entry).getPath();
1789: }
1790:
1791: /**
1792: *
1793: * @param path1 the first path
1794: * @param path2 the second path
1795: * @return <code>true</code> if path1 is a subfolder of
1796: * path2, <code>false</code> otherwise
1797: */
1798: private boolean isSubFolderOf(IPath path1, IPath path2) {
1799: if (path1 == null || path2 == null) {
1800: if (path1 == null && path2 == null)
1801: return true;
1802: return false;
1803: }
1804: return path2.matchingFirstSegments(path1) == path2
1805: .segmentCount();
1806: }
1807:
1808: };
1809: }
1810:
1811: }
|