* @param recurseInContainers flag indicating whether validation should be applied to container entries recursively
* @return a java model status describing the problem related to this classpath entry if any, a status object with code <code>IStatus.OK</code> if the entry is fine
*/
public static IJavaModelStatus validateClasspathEntry(IJavaProject project, IClasspathEntry entry, boolean checkSourceAttachment, boolean recurseInContainers){
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IPath path = entry.getPath();
// Build some common strings for status message
String projectName = project.getElementName();
boolean pathStartsWithProject = projectName.equals(path.segment(0));
String entryPathMsg = pathStartsWithProject ? path.removeFirstSegments(1).makeRelative().toString() : path.toString();
switch(entry.getEntryKind()){
// container entry check
case IClasspathEntry.CPE_CONTAINER :
if (path.segmentCount() >= 1){
try {
IClasspathContainer container = JavaModelManager.getJavaModelManager().getClasspathContainer(path, project);
// container retrieval is performing validation check on container entry kinds.
if (container == null){
return new JavaModelStatus(IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND, project, path);
} else if (container == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) {
// Validate extra attributes
IClasspathAttribute[] extraAttributes = entry.getExtraAttributes();
if (extraAttributes != null) {
int length = extraAttributes.length;
HashSet set = new HashSet(length);
for (int i=0; i<length; i++) {
String attName = extraAttributes[i].getName();
if (!set.add(attName)) {
return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Messages.bind(Messages.classpath_duplicateEntryExtraAttribute, new String[] {attName, entryPathMsg, projectName}));
}
}
}
// don't create a marker if initialization is in progress (case of cp initialization batching)
return JavaModelStatus.VERIFIED_OK;
}
IClasspathEntry[] containerEntries = container.getClasspathEntries();
if (containerEntries != null){
for (int i = 0, length = containerEntries.length; i < length; i++){
IClasspathEntry containerEntry = containerEntries[i];
int kind = containerEntry == null ? 0 : containerEntry.getEntryKind();
if (containerEntry == null
|| kind == IClasspathEntry.CPE_SOURCE
|| kind == IClasspathEntry.CPE_VARIABLE
|| kind == IClasspathEntry.CPE_CONTAINER){
String description = container.getDescription();
if (description == null) description = path.makeRelative().toString();
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CP_CONTAINER_ENTRY, project, path);
}
if (recurseInContainers) {
IJavaModelStatus containerEntryStatus = validateClasspathEntry(project, containerEntry, checkSourceAttachment, recurseInContainers);
if (!containerEntryStatus.isOK()){
return containerEntryStatus;
}
}
}
}
} catch(JavaModelException e){
return new JavaModelStatus(e);
}
} else {
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalContainerPath, new String[] {entryPathMsg, projectName}));
}
break;
// variable entry check
case IClasspathEntry.CPE_VARIABLE :
if (path.segmentCount() >= 1){
try {
entry = JavaCore.getResolvedClasspathEntry(entry);
} catch (AssertionFailedException e) {
// Catch the assertion failure and throw java model exception instead
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
}
if (entry == null){
return new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, project, path);
}
// get validation status
IJavaModelStatus status = validateClasspathEntry(project, entry, checkSourceAttachment, recurseInContainers);
if (!status.isOK()) return status;
// return deprecation status if any
String variableName = path.segment(0);
String deprecatedMessage = JavaCore.getClasspathVariableDeprecationMessage(variableName);
if (deprecatedMessage != null) {
return new JavaModelStatus(IStatus.WARNING, IJavaModelStatusConstants.DEPRECATED_VARIABLE, project, path, deprecatedMessage);
}
return status;
} else {
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalVariablePath, new String[] {entryPathMsg, projectName}));
}
// library entry check
case IClasspathEntry.CPE_LIBRARY :
if (path.isAbsolute() && !path.isEmpty()) {
IPath sourceAttachment = entry.getSourceAttachmentPath();
Object target = JavaModel.getTarget(workspaceRoot, path, true);
if (target != null && !JavaCore.IGNORE.equals(project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true))) {
long projectTargetJDK = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
long libraryJDK = Util.getJdkLevel(target);
if (libraryJDK != 0 && libraryJDK > projectTargetJDK) {
return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(libraryJDK));
}
}
if (target instanceof IResource){
IResource resolvedResource = (IResource) target;
switch(resolvedResource.getType()){
case IResource.FILE :
if (org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resolvedResource.getName())) {
if (checkSourceAttachment
&& sourceAttachment != null
&& !sourceAttachment.isEmpty()
&& JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toString(), projectName}));
}
} else {
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryArchive, new String[] {entryPathMsg, projectName}));
}
break;
case IResource.FOLDER : // internal binary folder
if (checkSourceAttachment
&& sourceAttachment != null
&& !sourceAttachment.isEmpty()
&& JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toString(), projectName}));
}
}
} else if (target instanceof File){
File file = JavaModel.getFile(target);
if (file == null) {
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalExternalFolder, new String[] {path.toOSString(), projectName}));
} else if (!org.aspectj.org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())) {
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryArchive, (new String[] {path.toOSString(), projectName})));
} else if (checkSourceAttachment
&& sourceAttachment != null
&& !sourceAttachment.isEmpty()
&& JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toOSString(), projectName}));
}
} else {
boolean isExternal = path.getDevice() != null || !workspaceRoot.getProject(path.segment(0)).exists();
if (isExternal) {
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {path.toOSString(), projectName}));
} else {
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {entryPathMsg, projectName}));
}
}
} else {
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryPath, new String[] {entryPathMsg, projectName}));
}
break;
// project entry check
case IClasspathEntry.CPE_PROJECT :
if (path.isAbsolute() && path.segmentCount() == 1) {
IProject prereqProjectRsc = workspaceRoot.getProject(path.segment(0));
IJavaProject prereqProject = JavaCore.create(prereqProjectRsc);
try {
if (!prereqProjectRsc.exists() || !prereqProjectRsc.hasNature(JavaCore.NATURE_ID)){
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundProject, new String[] {path.segment(0), projectName}));
}