/******************************************************************************* * Copyright © 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.ide.core.model; import java.util.HashMap; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.edt.compiler.internal.core.utils.CharOperation; import org.eclipse.edt.ide.core.internal.model.EGLModel; import org.eclipse.edt.ide.core.internal.model.EGLModelResources; import org.eclipse.edt.ide.core.internal.model.EGLModelStatus; import org.eclipse.edt.ide.core.internal.model.EGLPathEntry; import org.eclipse.edt.ide.core.internal.model.EGLProject; import org.eclipse.edt.ide.core.internal.model.Util; import com.ibm.icu.util.StringTokenizer; /** * Provides methods for checking EGL-specific conventions such as name syntax. * <p> * This class provides static methods and constants only; it is not intended to be * instantiated or subclassed by clients. * </p> */ public final class EGLConventions { private final static char fgDot= '.'; /** * Not instantiable. */ private EGLConventions() {} /* * Returns the index of the first argument paths which is strictly enclosing the path to check */ private static int indexOfEnclosingPath(IPath checkedPath, IPath[] paths, int pathCount) { for (int i = 0; i < pathCount; i++){ if (paths[i].equals(checkedPath)) continue; if (paths[i].isPrefixOf(checkedPath)) return i; } return -1; } /* * Returns the index of the first argument paths which is equal to the path to check */ private static int indexOfMatchingPath(IPath checkedPath, IPath[] paths, int pathCount) { for (int i = 0; i < pathCount; i++){ if (paths[i].equals(checkedPath)) return i; } return -1; } /* * Returns the index of the first argument paths which is strictly nested inside the path to check */ private static int indexOfNestedPath(IPath checkedPath, IPath[] paths, int pathCount) { for (int i = 0; i < pathCount; i++){ if (checkedPath.equals(paths[i])) continue; if (checkedPath.isPrefixOf(paths[i])) return i; } return -1; } /** * Returns whether the given package fragment root paths are considered * to overlap. * <p> * Two root paths overlap if one is a prefix of the other, or they point to * the same location. However, a JAR is allowed to be nested in a root. * * @param rootPath1 the first root path * @param rootPath2 the second root path * @return true if the given package fragment root paths are considered to overlap, false otherwise * @deprecated Overlapping roots are allowed in 2.1 */ public static boolean isOverlappingRoots(IPath rootPath1, IPath rootPath2) { if (rootPath1 == null || rootPath2 == null) { return false; } String extension1 = rootPath1.getFileExtension(); String extension2 = rootPath2.getFileExtension(); String jarExtension = "JAR"; //$NON-NLS-1$ String zipExtension = "ZIP"; //$NON-NLS-1$ if (extension1 != null && (extension1.equalsIgnoreCase(jarExtension) || extension1.equalsIgnoreCase(zipExtension))) { return false; } if (extension2 != null && (extension2.equalsIgnoreCase(jarExtension) || extension2.equalsIgnoreCase(zipExtension))) { return false; } return rootPath1.isPrefixOf(rootPath2) || rootPath2.isPrefixOf(rootPath1); } /** * Returns the current identifier extracted by the scanner (without unicode * escapes) from the given id. * Returns <code>null</code> if the id was not valid */ private static synchronized char[] scannedIdentifier(String id) { return id.toCharArray(); /* TODO handle checking id if (id == null) { return null; } String trimmed = id.trim(); if (!trimmed.equals(id)) { return null; } try { SCANNER.setSource(id.toCharArray()); int token = SCANNER.getNextToken(); char[] currentIdentifier; try { currentIdentifier = SCANNER.getCurrentIdentifierSource(); } catch (ArrayIndexOutOfBoundsException e) { return null; } int nextToken= SCANNER.getNextToken(); if (token == TerminalTokens.TokenNameIdentifier && nextToken == TerminalTokens.TokenNameEOF && SCANNER.startPosition == SCANNER.source.length) { // to handle case where we had an ArrayIndexOutOfBoundsException // while reading the last token return currentIdentifier; } else { return null; } } catch (InvalidInputException e) { return null; } */ } /** * Validate the given compilation unit name. * A compilation unit name must obey the following rules: * <ul> * <li> it must not be null * <li> it must include the <code>".java"</code> suffix * <li> its prefix must be a valid identifier * <li> it must not contain any characters or substrings that are not valid * on the file system on which workspace root is located. * </ul> * </p> * @param name the name of a compilation unit * @return a status object with code <code>IStatus.OK</code> if * the given name is valid as a compilation unit name, otherwise a status * object indicating what is wrong with the name */ public static IStatus validateEGLFileName(String name) { if (name == null) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionUnitNullName, null); } if (!Util.isEGLFileName(name)) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionUnitNotEGLName, null); } String identifier; int index; index = name.lastIndexOf('.'); if (index == -1) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionUnitNotEGLName, null); } identifier = name.substring(0, index); IStatus status = validateIdentifier(identifier); if (!status.isOK()) { return status; } status = ResourcesPlugin.getWorkspace().validateName(name, IResource.FILE); if (!status.isOK()) { return status; } return EGLModelStatus.VERIFIED_OK; } /** * Validate the given field name. * <p> * Syntax of a field name corresponds to VariableDeclaratorId (JLS2 8.3). * For example, <code>"x"</code>. * * @param name the name of a field * @return a status object with code <code>IStatus.OK</code> if * the given name is valid as a field name, otherwise a status * object indicating what is wrong with the name */ public static IStatus validateFieldName(String name) { return validateIdentifier(name); } /** * Validate the given EGL identifier. * The identifier must not have the same spelling as a EGL keyword, * boolean literal (<code>"true"</code>, <code>"false"</code>), or null literal (<code>"null"</code>). * See section 3.8 of the <em>EGL Language Specification, Second Edition</em> (JLS2). * A valid identifier can act as a simple type name, method name or field name. * * @param id the EGL identifier * @return a status object with code <code>IStatus.OK</code> if * the given identifier is a valid EGL identifier, otherwise a status * object indicating what is wrong with the identifier */ public static IStatus validateIdentifier(String id) { if (scannedIdentifier(id) != null) { return EGLModelStatus.VERIFIED_OK; } else { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.bind(EGLModelResources.conventionIllegalIdentifier, id), null); //$NON-NLS-1$ } } /** * Validate the given import declaration name. * <p> * The name of an import corresponds to a fully qualified type name * or an on-demand package name as defined by ImportDeclaration (JLS2 7.5). * For example, <code>"java.EGLModelResources.*"</code> or <code>"java.EGLModelResources.Hashtable"</code>. * * @param name the import declaration * @return a status object with code <code>IStatus.OK</code> if * the given name is valid as an import declaration, otherwise a status * object indicating what is wrong with the name */ public static IStatus validateImportDeclaration(String name) { if (name == null || name.length() == 0) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionImportNullImport, null); } if (name.charAt(name.length() - 1) == '*') { if (name.charAt(name.length() - 2) == '.') { return validatePackageName(name.substring(0, name.length() - 2)); } else { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionImportUnqualifiedImport, null); } } return validatePackageName(name); } /** * Validate the given EGL type name, either simple or qualified. * For example, <code>"java.lang.Object"</code>, or <code>"Object"</code>. * <p> * * @param name the name of a type * @return a status object with code <code>IStatus.OK</code> if * the given name is valid as a EGL type name, * a status with code <code>IStatus.WARNING</code> * indicating why the given name is discouraged, * otherwise a status object indicating what is wrong with * the name */ public static IStatus validateEGLTypeName(String name) { if (name == null) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionTypeNullName, null); } String trimmed = name.trim(); if (!name.equals(trimmed)) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionTypeNameWithBlanks, null); } int index = name.lastIndexOf('.'); char[] scannedID; if (index == -1) { // simple name scannedID = scannedIdentifier(name); } else { // qualified name String pkg = name.substring(0, index).trim(); IStatus status = validatePackageName(pkg); if (!status.isOK()) { return status; } String type = name.substring(index + 1).trim(); scannedID = scannedIdentifier(type); } if (scannedID != null) { IStatus status = ResourcesPlugin.getWorkspace().validateName(new String(scannedID), IResource.FILE); if (!status.isOK()) { return status; } if (CharOperation.contains('$', scannedID)) { return new Status(IStatus.WARNING, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionTypeDollarName, null); } if ((scannedID.length > 0 && Character.isLowerCase(scannedID[0]))) { return new Status(IStatus.WARNING, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionTypeLowercaseName, null); } return EGLModelStatus.VERIFIED_OK; } else { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.bind(EGLModelResources.conventionTypeInvalidName, name), null); } } /** * Validate the given method name. * The special names "<init>" and "<clinit>" are not valid. * <p> * The syntax for a method name is defined by Identifier * of MethodDeclarator (JLS2 8.4). For example "println". * * @param name the name of a method * @return a status object with code <code>IStatus.OK</code> if * the given name is valid as a method name, otherwise a status * object indicating what is wrong with the name */ public static IStatus validateMethodName(String name) { return validateIdentifier(name); } /** * Validate the given package name. * <p> * The syntax of a package name corresponds to PackageName as * defined by PackageDeclaration (JLS2 7.4). For example, <code>"java.lang"</code>. * <p> * Note that the given name must be a non-empty package name (that is, attempting to * validate the default package will return an error status.) * Also it must not contain any characters or substrings that are not valid * on the file system on which workspace root is located. * * @param name the name of a package * @return a status object with code <code>IStatus.OK</code> if * the given name is valid as a package name, otherwise a status * object indicating what is wrong with the name */ public static IStatus validatePackageName(String name) { if (name == null) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionPackageNullName, null); } int length; if ((length = name.length()) == 0) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionPackageEmptyName, null); } if (name.charAt(0) == fgDot || name.charAt(length-1) == fgDot) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionPackageDotName, null); } if (CharOperation.isWhitespace(name.charAt(0)) || CharOperation.isWhitespace(name.charAt(name.length() - 1))) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionPackageNameWithBlanks, null); } int dot = 0; while (dot != -1 && dot < length-1) { if ((dot = name.indexOf(fgDot, dot+1)) != -1 && dot < length-1 && name.charAt(dot+1) == fgDot) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionPackageConsecutiveDotsName, null); } } IWorkspace workspace = ResourcesPlugin.getWorkspace(); StringTokenizer st = new StringTokenizer(name, new String(new char[] {fgDot})); boolean firstToken = true; while (st.hasMoreTokens()) { String typeName = st.nextToken(); typeName = typeName.trim(); // grammar allows spaces char[] scannedID = scannedIdentifier(typeName); if (scannedID == null) { return new Status(IStatus.ERROR, EGLCore.PLUGIN_ID, -1, EGLModelResources.bind(EGLModelResources.conventionIllegalIdentifier, typeName), null); } IStatus status = workspace.validateName(new String(scannedID), IResource.FOLDER); if (!status.isOK()) { return status; } if (firstToken && scannedID.length > 0 && Character.isUpperCase(scannedID[0])) { return new Status(IStatus.WARNING, EGLCore.PLUGIN_ID, -1, EGLModelResources.conventionPackageUppercaseName, null); } firstToken = false; } return EGLModelStatus.VERIFIED_OK; } /** * Validate a given eglpath and output location for a project, using the following rules: * <ul> * <li> EGLPath entries cannot collide with each other; that is, all entry paths must be unique. * <li> The project output location path cannot be null, must be absolute and located inside the project. * <li> Specific output locations (specified on source entries) can be null, if not they must be located inside the project, * <li> A project entry cannot refer to itself directly (that is, a project cannot prerequisite itself). * <li> EGLPath entries or output locations cannot coincidate or be nested in each other, except for the following scenarii listed below: * <ul><li> A source folder can coincidate with its own output location, in which case this output can then contain library archives. * However, a specific output location cannot coincidate with any library or a distinct source folder than the one referring to it. </li> * <li> A source/library folder can be nested in any source folder as long as the nested folder is excluded from the enclosing one. </li> * <li> An output location can be nested in a source folder, if the source folder coincidates with the project itself. </li> * </ul> * </ul> * * Note that the eglpath entries are not validated automatically. Only bound variables or containers are considered * in the checking process (this allows to perform a consistency check on a eglpath which has references to * yet non existing projects, folders, ...). * <p> * This validation is intended to anticipate eglpath issues prior to assigning it to a project. In particular, it will automatically * be performed during the eglpath setting operation (if validation fails, the eglpath setting will not complete). * <p> * @param javaProject the given java project * @param eglpath a given eglpath * @param outputLocation a given output location * @return a status object with code <code>IStatus.OK</code> if * the given eglpath and output location are compatible, otherwise a status * object indicating what is wrong with the eglpath or output location * @since 2.0 */ public static IEGLModelStatus validateEGLPath(IEGLProject javaProject, IEGLPathEntry[] rawEGLPath, IPath projectOutputLocation) { IProject project = javaProject.getProject(); IPath projectPath= project.getFullPath(); // EGLTODO: Don't need to validate output location? /* validate output location */ if (projectOutputLocation == null) { return new EGLModelStatus(IEGLModelStatusConstants.NULL_PATH); } if (projectOutputLocation.isAbsolute()) { if (!projectPath.isPrefixOf(projectOutputLocation)) { return new EGLModelStatus(IEGLModelStatusConstants.PATH_OUTSIDE_PROJECT, javaProject, projectOutputLocation.toString()); } } else { return new EGLModelStatus(IEGLModelStatusConstants.RELATIVE_PATH, projectOutputLocation); } boolean hasSource = false; boolean hasLibFolder = false; // tolerate null path, it will be reset to default if (rawEGLPath == null) return EGLModelStatus.VERIFIED_OK; // retrieve resolved eglpath IEGLPathEntry[] eglpath; try { eglpath = ((EGLProject)javaProject).getResolvedEGLPath(rawEGLPath, null /*output*/, true/*ignore pb*/, false/*no marker*/, null /*no reverse map*/); } catch(EGLModelException e){ return e.getEGLModelStatus(); } int length = eglpath.length; int outputCount = 1; IPath[] outputLocations = new IPath[length+1]; boolean[] allowNestingInOutputLocations = new boolean[length+1]; outputLocations[0] = projectOutputLocation; // retrieve and check output locations IPath potentialNestedOutput = null; int sourceEntryCount = 0; for (int i = 0 ; i < length; i++) { IEGLPathEntry resolvedEntry = eglpath[i]; switch(resolvedEntry.getEntryKind()){ case IEGLPathEntry.CPE_SOURCE : sourceEntryCount++; // EGLTODO: Exclustion patterns? // if (resolvedEntry.getExclusionPatterns() != null && resolvedEntry.getExclusionPatterns().length > 0 // && EGLCore.DISABLED.equals(javaProject.getOption(EGLCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true))) { // return new EGLModelStatus(IEGLModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, resolvedEntry.getPath()); // } IPath customOutput; if ((customOutput = resolvedEntry.getOutputLocation()) != null) { // EGLTODO: Mutliple output locations? // if (EGLCore.DISABLED.equals(javaProject.getOption(EGLCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true))) { // return new EGLModelStatus(IEGLModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS, resolvedEntry.getPath()); // } // ensure custom output is in project if (customOutput.isAbsolute()) { if (!javaProject.getPath().isPrefixOf(customOutput)) { return new EGLModelStatus(IEGLModelStatusConstants.PATH_OUTSIDE_PROJECT, javaProject, customOutput.toString()); } } else { return new EGLModelStatus(IEGLModelStatusConstants.RELATIVE_PATH, customOutput); } // ensure custom output doesn't conflict with other outputs int index; if ((index = indexOfMatchingPath(customOutput, outputLocations, outputCount)) != -1) { continue; // already found } if ((index = indexOfEnclosingPath(customOutput, outputLocations, outputCount)) != -1) { if (index == 0) { // custom output is nested in project's output: need to check if all source entries have a custom // output before complaining if (potentialNestedOutput == null) potentialNestedOutput = customOutput; } else { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathCannotNestOutputInOutput, customOutput.makeRelative().toString(), outputLocations[index].makeRelative().toString())); } } outputLocations[outputCount++] = resolvedEntry.getOutputLocation(); } } } // allow custom output nesting in project's output if all source entries have a custom output if (potentialNestedOutput != null && sourceEntryCount > outputCount-1) { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathCannotNestOutputInOutput, potentialNestedOutput.makeRelative().toString(), outputLocations[0].makeRelative().toString())); } for (int i = 0 ; i < length; i++) { IEGLPathEntry resolvedEntry = eglpath[i]; IPath path = resolvedEntry.getPath(); int index; switch(resolvedEntry.getEntryKind()){ case IEGLPathEntry.CPE_SOURCE : hasSource = true; if ((index = indexOfMatchingPath(path, outputLocations, outputCount)) != -1){ allowNestingInOutputLocations[index] = true; } break; // EGLTODO: Not supporting library yet - remove? case IEGLPathEntry.CPE_LIBRARY: hasLibFolder |= !Util.isArchiveFileName(path.lastSegment()); if ((index = indexOfMatchingPath(path, outputLocations, outputCount)) != -1){ allowNestingInOutputLocations[index] = true; } break; } } if (!hasSource && !hasLibFolder) { // if no source and no lib folder, then allowed for (int i = 0; i < outputCount; i++) allowNestingInOutputLocations[i] = true; } HashMap<IPath, IEGLPathEntry> pathEntry = new HashMap<IPath, IEGLPathEntry>(length); // check all entries for (int i = 0 ; i < length; i++) { IEGLPathEntry entry = eglpath[i]; if (entry == null) continue; IPath entryPath = entry.getPath(); int kind = entry.getEntryKind(); IEGLPathEntry oldEntry = pathEntry.put(entryPath, entry); // complain if duplicate path if (oldEntry != null){ if((oldEntry.isBinaryProject() && entry.isBinaryProject()) || ((!oldEntry.isBinaryProject() && (!entry.isBinaryProject())))) { return new EGLModelStatus(IEGLModelStatusConstants.NAME_COLLISION, EGLModelResources.bind(EGLModelResources.eglpathDuplicateEntryPath, entryPath.makeRelative().toString())); } } // no further check if entry coincidates with project or output location if (entryPath.equals(projectPath)){ // complain if self-referring project entry if (kind == IEGLPathEntry.CPE_PROJECT){ return new EGLModelStatus(IEGLModelStatusConstants.INVALID_PATH, EGLModelResources.bind(EGLModelResources.eglpathCannotReferToItself, entryPath.makeRelative().toString())); } // tolerate nesting output in src if src==prj continue; } // allow nesting source entries in each other as long as the outer entry excludes the inner one if (kind == IEGLPathEntry.CPE_SOURCE || (kind == IEGLPathEntry.CPE_LIBRARY && !Util.isArchiveFileName(entryPath.lastSegment()))){ for (int j = 0; j < eglpath.length; j++){ IEGLPathEntry otherEntry = eglpath[j]; if (otherEntry == null) continue; int otherKind = otherEntry.getEntryKind(); IPath otherPath = otherEntry.getPath(); if (entry != otherEntry && (otherKind == IEGLPathEntry.CPE_SOURCE || (otherKind == IEGLPathEntry.CPE_LIBRARY && !Util.isArchiveFileName(otherPath.lastSegment())))){ char[][] exclusionPatterns; if (otherPath.isPrefixOf(entryPath) && !otherPath.equals(entryPath) && !Util.isExcluded(entryPath.append("*"), exclusionPatterns = ((EGLPathEntry)otherEntry).fullExclusionPatternChars())) { //$NON-NLS-1$ String exclusionPattern = entryPath.removeFirstSegments(otherPath.segmentCount()).segment(0); if (Util.isExcluded(entryPath, exclusionPatterns)) { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathMustEndWithSlash, exclusionPattern, entryPath.makeRelative().toString())); } else { if (otherKind == IEGLPathEntry.CPE_SOURCE) { exclusionPattern += '/'; return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathCannotNestEntryInEntry, new String[] {entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString(), exclusionPattern})); } else { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathCannotNestEntryInLibrary, new String[] {entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString()})); } } } } } } // prevent nesting output location inside entry int index; if ((index = indexOfNestedPath(entryPath, outputLocations, outputCount)) != -1) { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathCannotNestOutputInEntry, outputLocations[index].makeRelative().toString(), entryPath.makeRelative().toString())); } // prevent nesting entry inside output location - when distinct from project or a source folder if ((index = indexOfEnclosingPath(entryPath, outputLocations, outputCount)) != -1) { if (!allowNestingInOutputLocations[index]) { // allow nesting in project's output if all source entries have a custom output if (index != 0 || sourceEntryCount > outputCount - 1) { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathCannotNestEntryInOutput, entryPath.makeRelative().toString(), outputLocations[index].makeRelative().toString())); } } } } // ensure that no specific output is coincidating with another source folder (only allowed if matching current source folder) // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate) // perform one separate iteration so as to not take precedence over previously checked scenarii (in particular should // diagnose nesting source folder issue before this one, for example, [src]"Project/", [src]"Project/source/" and output="Project/" should // first complain about missing exclusion pattern for (int i = 0 ; i < length; i++) { IEGLPathEntry entry = eglpath[i]; if (entry == null) continue; IPath entryPath = entry.getPath(); int kind = entry.getEntryKind(); if (kind == IEGLPathEntry.CPE_SOURCE) { IPath output = entry.getOutputLocation(); if (output == null) continue; // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate) // if (output == null) output = projectOutputLocation; // if no specific output, still need to check using default output (this line would check default output) for (int j = 0; j < length; j++) { IEGLPathEntry otherEntry = eglpath[j]; if (otherEntry == entry) continue; switch (otherEntry.getEntryKind()) { case IEGLPathEntry.CPE_SOURCE : if (otherEntry.getPath().equals(output)) { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathCannotUseDistinctSourceFolderAsOutput, entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString())); } break; case IEGLPathEntry.CPE_LIBRARY : if (otherEntry.getPath().equals(output)) { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathCannotUseLibraryAsOutput, entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString())); } } } } } return EGLModelStatus.VERIFIED_OK; } /** * Returns a EGL model status describing the problem related to this eglpath entry if any, * a status object with code <code>IStatus.OK</code> if the entry is fine (that is, if the * given eglpath entry denotes a valid element to be referenced onto a eglpath). * * @param javaProject the given java project * @param entry the given eglpath entry * @param checkSourceAttachment a flag to determine if source attachement should be checked * @return a java model status describing the problem related to this eglpath entry if any, a status object with code <code>IStatus.OK</code> if the entry is fine * @since 2.0 */ public static IEGLModelStatus validateEGLPathEntry(IEGLProject javaProject, IEGLPathEntry entry, boolean checkSourceAttachment){ IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); IPath path = entry.getPath(); switch(entry.getEntryKind()){ // EGLTODO: Containers not supported - remove? // container entry check case IEGLPathEntry.CPE_CONTAINER : if (path != null && path.segmentCount() >= 1){ try { IEGLPathContainer container = EGLCore.getEGLPathContainer(path, javaProject); // container retrieval is performing validation check on container entry kinds. if (container == null){ return new EGLModelStatus(IEGLModelStatusConstants.CP_CONTAINER_PATH_UNBOUND, javaProject, path); } IEGLPathEntry[] containerEntries = container.getEGLPathEntries(); if (containerEntries != null){ for (int i = 0, length = containerEntries.length; i < length; i++){ IEGLPathEntry containerEntry = containerEntries[i]; int kind = containerEntry == null ? 0 : containerEntry.getEntryKind(); if (containerEntry == null || kind == IEGLPathEntry.CPE_SOURCE || kind == IEGLPathEntry.CPE_VARIABLE || kind == IEGLPathEntry.CPE_CONTAINER){ String description = container.getDescription(); if (description == null) description = path.makeRelative().toString(); return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CP_CONTAINER_ENTRY, javaProject, path); } IEGLModelStatus containerEntryStatus = validateEGLPathEntry(javaProject, containerEntry, checkSourceAttachment); if (!containerEntryStatus.isOK()){ return containerEntryStatus; } } } } catch(EGLModelException e){ return new EGLModelStatus(e); } } else { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathIllegalContainerPath, path.makeRelative().toString())); } break; // EGLTODO Variables not supported - remove? // variable entry check case IEGLPathEntry.CPE_VARIABLE : if (path != null && path.segmentCount() >= 1){ entry = EGLCore.getResolvedEGLPathEntry(entry); if (entry == null){ return new EGLModelStatus(IEGLModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, javaProject, path); } return validateEGLPathEntry(javaProject, entry, checkSourceAttachment); } else { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathIllegalVariablePath, path.makeRelative().toString())); } case IEGLPathEntry.CPE_LIBRARY : if (path != null && path.isAbsolute() && !path.isEmpty()) { if (EGLModel.getTarget(workspaceRoot, path, true) == null){ return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathIllegalEGLARPath, path.toString())); } } //EGLTODO: // // if (path != null && path.isAbsolute() && !path.isEmpty()) { // IPath sourceAttachment = entry.getSourceAttachmentPath(); // Object target = EGLModel.getTarget(workspaceRoot, path, true); // if (target instanceof IResource){ // IResource resolvedResource = (IResource) target; // switch(resolvedResource.getType()){ // case IResource.FILE : // if (EGLModelResources.isArchiveFileName(resolvedResource.getFileExtension())) { // if (checkSourceAttachment // && sourceAttachment != null // && !sourceAttachment.isEmpty() // && EGLModel.getTarget(workspaceRoot, sourceAttachment, true) == null){ // return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathunboundSourceAttachment, sourceAttachment.makeRelative().toString(), path.makeRelative().toString())); // } // } // break; // case IResource.FOLDER : // internal binary folder // if (checkSourceAttachment // && sourceAttachment != null // && !sourceAttachment.isEmpty() // && EGLModel.getTarget(workspaceRoot, sourceAttachment, true) == null){ // return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathunboundSourceAttachment, sourceAttachment.makeRelative().toString(), path.makeRelative().toString())); // } // } // } else if (target instanceof File){ // if (checkSourceAttachment // && sourceAttachment != null // && !sourceAttachment.isEmpty() // && EGLModel.getTarget(workspaceRoot, sourceAttachment, true) == null){ // return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathunboundSourceAttachment, sourceAttachment.toString(), path.makeRelative().toString())); // } // } else { // return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathunboundLibrary, path.makeRelative().toString())); // } // } else { // return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathillegalLibraryPath, path.makeRelative().toString())); // } break; // project entry check case IEGLPathEntry.CPE_PROJECT : if (path != null && path.isAbsolute() && !path.isEmpty()) { IProject project = workspaceRoot.getProject(path.segment(0)); try { if (!project.exists() || !project.hasNature(EGLCore.NATURE_ID)){ return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathUnboundProject, path.makeRelative().segment(0).toString())); } if (!project.isOpen()){ return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathClosedProject, path.segment(0).toString())); } } catch (CoreException e){ return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathUnboundProject, path.segment(0).toString())); } } else { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathIllegalProjectPath, path.segment(0).toString())); } break; // project source folder case IEGLPathEntry.CPE_SOURCE : // EGLTODO: Exclusion patterns? // if (entry.getExclusionPatterns() != null // && entry.getExclusionPatterns().length > 0 // && EGLCore.DISABLED.equals(javaProject.getOption(EGLCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true))) { // return new EGLModelStatus(IEGLModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, path); // } // EGLTODO: Multiple output locations? // if (entry.getOutputLocation() != null && EGLCore.DISABLED.equals(javaProject.getOption(EGLCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true))) { // return new EGLModelStatus(IEGLModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS, path); // } if (path != null && path.isAbsolute() && !path.isEmpty()) { IPath projectPath= javaProject.getProject().getFullPath(); if (!projectPath.isPrefixOf(path) || EGLModel.getTarget(workspaceRoot, path, true) == null){ return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathUnboundSourceFolder, path.makeRelative().toString())); } } else { return new EGLModelStatus(IEGLModelStatusConstants.INVALID_CLASSPATH, EGLModelResources.bind(EGLModelResources.eglpathIllegalSourceFolderPath, path.makeRelative().toString())); } break; } return EGLModelStatus.VERIFIED_OK; } }