Lines 10-25
Link Here
|
10 |
*******************************************************************************/ |
10 |
*******************************************************************************/ |
11 |
package org.eclipse.jdt.internal.core; |
11 |
package org.eclipse.jdt.internal.core; |
12 |
|
12 |
|
|
|
13 |
import java.io.BufferedReader; |
13 |
import java.io.ByteArrayOutputStream; |
14 |
import java.io.ByteArrayOutputStream; |
14 |
import java.io.File; |
15 |
import java.io.File; |
|
|
16 |
import java.io.IOException; |
17 |
import java.io.InputStreamReader; |
15 |
import java.io.OutputStreamWriter; |
18 |
import java.io.OutputStreamWriter; |
16 |
import java.io.UnsupportedEncodingException; |
19 |
import java.io.UnsupportedEncodingException; |
17 |
import java.util.ArrayList; |
20 |
import java.util.ArrayList; |
18 |
import java.util.HashMap; |
21 |
import java.util.HashMap; |
19 |
import java.util.HashSet; |
22 |
import java.util.HashSet; |
|
|
23 |
import java.util.Iterator; |
24 |
import java.util.List; |
20 |
import java.util.Map; |
25 |
import java.util.Map; |
|
|
26 |
import java.util.zip.ZipEntry; |
27 |
import java.util.zip.ZipFile; |
21 |
|
28 |
|
22 |
import org.eclipse.core.resources.IContainer; |
29 |
import org.eclipse.core.resources.IContainer; |
|
|
30 |
import org.eclipse.core.resources.IFile; |
23 |
import org.eclipse.core.resources.IProject; |
31 |
import org.eclipse.core.resources.IProject; |
24 |
import org.eclipse.core.resources.IResource; |
32 |
import org.eclipse.core.resources.IResource; |
25 |
import org.eclipse.core.resources.IWorkspaceRoot; |
33 |
import org.eclipse.core.resources.IWorkspaceRoot; |
Lines 44-49
Link Here
|
44 |
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; |
52 |
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; |
45 |
import org.eclipse.jdt.internal.compiler.env.AccessRule; |
53 |
import org.eclipse.jdt.internal.compiler.env.AccessRule; |
46 |
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
54 |
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
|
|
55 |
import org.eclipse.jdt.internal.compiler.util.ManifestAnalyzer; |
47 |
import org.eclipse.jdt.internal.core.util.Messages; |
56 |
import org.eclipse.jdt.internal.core.util.Messages; |
48 |
import org.eclipse.jdt.internal.core.util.Util; |
57 |
import org.eclipse.jdt.internal.core.util.Util; |
49 |
import org.w3c.dom.DOMException; |
58 |
import org.w3c.dom.DOMException; |
Lines 133-138
Link Here
|
133 |
private IPath[] exclusionPatterns; |
142 |
private IPath[] exclusionPatterns; |
134 |
private char[][] fullExclusionPatternChars; |
143 |
private char[][] fullExclusionPatternChars; |
135 |
private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() }; //$NON-NLS-1$ |
144 |
private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() }; //$NON-NLS-1$ |
|
|
145 |
private final static ClasspathEntry[] NO_ENTRIES = new ClasspathEntry[0]; |
146 |
private final static IPath[] NO_PATHS = new IPath[0]; |
136 |
|
147 |
|
137 |
private boolean combineAccessRules; |
148 |
private boolean combineAccessRules; |
138 |
|
149 |
|
Lines 848-853
Link Here
|
848 |
} |
859 |
} |
849 |
|
860 |
|
850 |
/* |
861 |
/* |
|
|
862 |
* Read the Class-Path clause of the manifest of the jar pointed by this path, and return |
863 |
* the corresponding paths. |
864 |
*/ |
865 |
public static IPath[] resolvedChainedLibraries(IPath jarPath) { |
866 |
ArrayList result = new ArrayList(); |
867 |
resolvedChainedLibraries(jarPath, new HashSet(), result); |
868 |
if (result.size() == 0) |
869 |
return NO_PATHS; |
870 |
return (IPath[]) result.toArray(new IPath[result.size()]); |
871 |
} |
872 |
|
873 |
private static void resolvedChainedLibraries(IPath jarPath, HashSet visited, ArrayList result) { |
874 |
if (visited.contains( jarPath)) |
875 |
return; |
876 |
visited.add(jarPath); |
877 |
Object target = JavaModel.getTarget(jarPath, true/*check existence, otherwise the manifest cannot be read*/); |
878 |
if (target instanceof IFile || target instanceof File) { |
879 |
JavaModelManager manager = JavaModelManager.getJavaModelManager(); |
880 |
ZipFile zip = null; |
881 |
BufferedReader reader = null; |
882 |
try { |
883 |
zip = manager.getZipFile(jarPath); |
884 |
ZipEntry manifest = zip.getEntry("META-INF/MANIFEST.MF"); //$NON-NLS-1$ |
885 |
if (manifest != null) { // non-null implies regular file |
886 |
reader = new BufferedReader(new InputStreamReader(zip.getInputStream(manifest))); |
887 |
ManifestAnalyzer analyzer = new ManifestAnalyzer(); |
888 |
boolean success = analyzer.analyzeManifestContents(reader); |
889 |
List calledFileNames = analyzer.getCalledFileNames(); |
890 |
if (!success || analyzer.getClasspathSectionsCount() == 1 && calledFileNames == null) { |
891 |
Util.log(IStatus.WARNING, "Invalid Class-Path header in manifest of jar file: " + jarPath.toOSString()); //$NON-NLS-1$ |
892 |
return; |
893 |
} else if (analyzer.getClasspathSectionsCount() > 1) { |
894 |
Util.log(IStatus.WARNING, "Multiple Class-Path headers in manifest of jar file: " + jarPath.toOSString()); //$NON-NLS-1$ |
895 |
return; |
896 |
} |
897 |
if (calledFileNames != null) { |
898 |
Iterator calledFilesIterator = calledFileNames.iterator(); |
899 |
IPath directoryPath = jarPath.removeLastSegments(1); |
900 |
while (calledFilesIterator.hasNext()) { |
901 |
String calledFileName = (String) calledFilesIterator.next(); |
902 |
if (!directoryPath.isValidPath(calledFileName)) { |
903 |
Util.log(IStatus.WARNING, "Invalid Class-Path entry " + calledFileName + " in manifest of jar file: " + jarPath.toOSString()); //$NON-NLS-1$ //$NON-NLS-2$ |
904 |
} else { |
905 |
IPath calledJar = directoryPath.append(new Path(calledFileName)); |
906 |
resolvedChainedLibraries(calledJar, visited, result); |
907 |
result.add(calledJar); |
908 |
} |
909 |
} |
910 |
} |
911 |
} |
912 |
} catch (CoreException e) { |
913 |
// not a zip file |
914 |
} catch (IOException e) { |
915 |
Util.log(e, "Could not read Class-Path header in manifest of jar file: " + jarPath.toOSString()); //$NON-NLS-1$ |
916 |
} finally { |
917 |
manager.closeZipFile(zip); |
918 |
if (reader != null) { |
919 |
try { |
920 |
reader.close(); |
921 |
} catch (IOException e) { |
922 |
// best effort |
923 |
} |
924 |
} |
925 |
} |
926 |
} |
927 |
} |
928 |
|
929 |
/* |
851 |
* Resolves the ".." in the given path. Returns the given path if it contains no ".." segment. |
930 |
* Resolves the ".." in the given path. Returns the given path if it contains no ".." segment. |
852 |
*/ |
931 |
*/ |
853 |
public static IPath resolveDotDot(IPath path) { |
932 |
public static IPath resolveDotDot(IPath path) { |
Lines 1163-1169
Link Here
|
1163 |
*/ |
1242 |
*/ |
1164 |
public String toString() { |
1243 |
public String toString() { |
1165 |
StringBuffer buffer = new StringBuffer(); |
1244 |
StringBuffer buffer = new StringBuffer(); |
1166 |
buffer.append(String.valueOf(getPath())); |
1245 |
Object target = JavaModel.getTarget(getPath(), true); |
|
|
1246 |
if (target instanceof File) |
1247 |
buffer.append(getPath().toOSString()); |
1248 |
else |
1249 |
buffer.append(String.valueOf(getPath())); |
1167 |
buffer.append('['); |
1250 |
buffer.append('['); |
1168 |
switch (getEntryKind()) { |
1251 |
switch (getEntryKind()) { |
1169 |
case IClasspathEntry.CPE_LIBRARY : |
1252 |
case IClasspathEntry.CPE_LIBRARY : |
Lines 1278-1283
Link Here
|
1278 |
this.extraAttributes); |
1361 |
this.extraAttributes); |
1279 |
} |
1362 |
} |
1280 |
|
1363 |
|
|
|
1364 |
/* |
1365 |
* Read the Class-Path clause of the manifest of the jar pointed by this entry, and return |
1366 |
* the corresponding library entries. |
1367 |
*/ |
1368 |
public ClasspathEntry[] resolvedChainedLibraries() { |
1369 |
IPath[] paths = resolvedChainedLibraries(getPath()); |
1370 |
int length = paths.length; |
1371 |
if (length == 0) |
1372 |
return NO_ENTRIES; |
1373 |
ClasspathEntry[] result = new ClasspathEntry[length]; |
1374 |
for (int i = 0; i < length; i++) { |
1375 |
result[i] = new ClasspathEntry( |
1376 |
getContentKind(), |
1377 |
getEntryKind(), |
1378 |
paths[i], |
1379 |
this.inclusionPatterns, |
1380 |
this.exclusionPatterns, |
1381 |
getSourceAttachmentPath(), |
1382 |
getSourceAttachmentRootPath(), |
1383 |
getOutputLocation(), |
1384 |
this.isExported, |
1385 |
getAccessRules(), |
1386 |
this.combineAccessRules, |
1387 |
this.extraAttributes); |
1388 |
} |
1389 |
return result; |
1390 |
} |
1391 |
|
1281 |
/** |
1392 |
/** |
1282 |
* Answers an ID which is used to distinguish entries during package |
1393 |
* Answers an ID which is used to distinguish entries during package |
1283 |
* fragment root computations |
1394 |
* fragment root computations |
Lines 1614-1620
Link Here
|
1614 |
* |
1725 |
* |
1615 |
* @param project the given java project |
1726 |
* @param project the given java project |
1616 |
* @param entry the given classpath entry |
1727 |
* @param entry the given classpath entry |
1617 |
* @param checkSourceAttachment a flag to determine if source attachement should be checked |
1728 |
* @param checkSourceAttachment a flag to determine if source attachment should be checked |
1618 |
* @param recurseInContainers flag indicating whether validation should be applied to container entries recursively |
1729 |
* @param recurseInContainers flag indicating whether validation should be applied to container entries recursively |
1619 |
* @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 |
1730 |
* @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 |
1620 |
*/ |
1731 |
*/ |
Lines 1625-1632
Link Here
|
1625 |
|
1736 |
|
1626 |
// Build some common strings for status message |
1737 |
// Build some common strings for status message |
1627 |
String projectName = project.getElementName(); |
1738 |
String projectName = project.getElementName(); |
1628 |
boolean pathStartsWithProject = projectName.equals(path.segment(0)); |
1739 |
String entryPathMsg = projectName.equals(path.segment(0)) ? path.removeFirstSegments(1).makeRelative().toString() : path.toString(); |
1629 |
String entryPathMsg = pathStartsWithProject ? path.removeFirstSegments(1).makeRelative().toString() : path.toString(); |
|
|
1630 |
|
1740 |
|
1631 |
switch(entry.getEntryKind()){ |
1741 |
switch(entry.getEntryKind()){ |
1632 |
|
1742 |
|
Lines 1719-1774
Link Here
|
1719 |
// library entry check |
1829 |
// library entry check |
1720 |
case IClasspathEntry.CPE_LIBRARY : |
1830 |
case IClasspathEntry.CPE_LIBRARY : |
1721 |
path = ClasspathEntry.resolveDotDot(path); |
1831 |
path = ClasspathEntry.resolveDotDot(path); |
1722 |
if (path.isAbsolute() && !path.isEmpty()) { |
1832 |
|
1723 |
IPath sourceAttachment = entry.getSourceAttachmentPath(); |
1833 |
// resolve Class-Path: in manifest |
1724 |
Object target = JavaModel.getTarget(path, true); |
1834 |
IPath[] chainedJars = ClasspathEntry.resolvedChainedLibraries(path); |
1725 |
if (target != null && !JavaCore.IGNORE.equals(project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true))) { |
1835 |
for (int i = 0, length = chainedJars.length; i < length; i++) { |
1726 |
long projectTargetJDK = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true)); |
1836 |
IPath chainedJar = chainedJars[i]; |
1727 |
long libraryJDK = Util.getJdkLevel(target); |
1837 |
IJavaModelStatus status = validateLibraryEntry(chainedJar, project, null/*don't check source attachment*/, null/*force computing of entryPathMsg*/); |
1728 |
if (libraryJDK != 0 && libraryJDK > projectTargetJDK) { |
1838 |
if (!status.isOK()) |
1729 |
return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(libraryJDK)); |
1839 |
return status; |
1730 |
} |
1840 |
} |
1731 |
} |
1841 |
|
1732 |
if (target instanceof IResource){ |
1842 |
IJavaModelStatus status = validateLibraryEntry(path, project, checkSourceAttachment ? entry.getSourceAttachmentPath() : null, entryPathMsg); |
1733 |
IResource resolvedResource = (IResource) target; |
1843 |
if (!status.isOK()) |
1734 |
switch(resolvedResource.getType()){ |
1844 |
return status; |
1735 |
case IResource.FILE : |
|
|
1736 |
if (checkSourceAttachment |
1737 |
&& sourceAttachment != null |
1738 |
&& !sourceAttachment.isEmpty() |
1739 |
&& JavaModel.getTarget(sourceAttachment, true) == null){ |
1740 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toString(), projectName})); |
1741 |
} |
1742 |
break; |
1743 |
case IResource.FOLDER : // internal binary folder |
1744 |
if (checkSourceAttachment |
1745 |
&& sourceAttachment != null |
1746 |
&& !sourceAttachment.isEmpty() |
1747 |
&& JavaModel.getTarget(sourceAttachment, true) == null){ |
1748 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toString(), projectName})); |
1749 |
} |
1750 |
} |
1751 |
} else if (target instanceof File){ |
1752 |
File file = JavaModel.getFile(target); |
1753 |
if (file == null) { |
1754 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalExternalFolder, new String[] {path.toOSString(), projectName})); |
1755 |
} else if (checkSourceAttachment |
1756 |
&& sourceAttachment != null |
1757 |
&& !sourceAttachment.isEmpty() |
1758 |
&& JavaModel.getTarget(sourceAttachment, true) == null){ |
1759 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toOSString(), projectName})); |
1760 |
} |
1761 |
} else { |
1762 |
boolean isExternal = path.getDevice() != null || !workspaceRoot.getProject(path.segment(0)).exists(); |
1763 |
if (isExternal) { |
1764 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {path.toOSString(), projectName})); |
1765 |
} else { |
1766 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {entryPathMsg, projectName})); |
1767 |
} |
1768 |
} |
1769 |
} else { |
1770 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryPath, new String[] {entryPathMsg, projectName})); |
1771 |
} |
1772 |
break; |
1845 |
break; |
1773 |
|
1846 |
|
1774 |
// project entry check |
1847 |
// project entry check |
Lines 1834-1837
Link Here
|
1834 |
|
1907 |
|
1835 |
return JavaModelStatus.VERIFIED_OK; |
1908 |
return JavaModelStatus.VERIFIED_OK; |
1836 |
} |
1909 |
} |
|
|
1910 |
|
1911 |
private static IJavaModelStatus validateLibraryEntry(IPath path, IJavaProject project, IPath sourceAttachment, String entryPathMsg) { |
1912 |
if (path.isAbsolute() && !path.isEmpty()) { |
1913 |
Object target = JavaModel.getTarget(path, true); |
1914 |
if (target != null && !JavaCore.IGNORE.equals(project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true))) { |
1915 |
long projectTargetJDK = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true)); |
1916 |
long libraryJDK = Util.getJdkLevel(target); |
1917 |
if (libraryJDK != 0 && libraryJDK > projectTargetJDK) { |
1918 |
return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(libraryJDK)); |
1919 |
} |
1920 |
} |
1921 |
if (target instanceof IResource){ |
1922 |
IResource resolvedResource = (IResource) target; |
1923 |
switch(resolvedResource.getType()){ |
1924 |
case IResource.FILE : |
1925 |
if (sourceAttachment != null |
1926 |
&& !sourceAttachment.isEmpty() |
1927 |
&& JavaModel.getTarget(sourceAttachment, true) == null){ |
1928 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toString(), project.getElementName()})); |
1929 |
} |
1930 |
break; |
1931 |
case IResource.FOLDER : // internal binary folder |
1932 |
if (sourceAttachment != null |
1933 |
&& !sourceAttachment.isEmpty() |
1934 |
&& JavaModel.getTarget(sourceAttachment, true) == null){ |
1935 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toString(), project.getElementName()})); |
1936 |
} |
1937 |
} |
1938 |
} else if (target instanceof File){ |
1939 |
File file = JavaModel.getFile(target); |
1940 |
if (file == null) { |
1941 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalExternalFolder, new String[] {path.toOSString(), project.getElementName()})); |
1942 |
} else if (sourceAttachment != null |
1943 |
&& !sourceAttachment.isEmpty() |
1944 |
&& JavaModel.getTarget(sourceAttachment, true) == null){ |
1945 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundSourceAttachment, new String [] {sourceAttachment.toString(), path.toOSString(), project.getElementName()})); |
1946 |
} |
1947 |
} else { |
1948 |
boolean isExternal = path.getDevice() != null || !ResourcesPlugin.getWorkspace().getRoot().getProject(path.segment(0)).exists(); |
1949 |
if (isExternal) { |
1950 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {path.toOSString(), project.getElementName()})); |
1951 |
} else { |
1952 |
if (entryPathMsg == null) |
1953 |
entryPathMsg = project.getElementName().equals(path.segment(0)) ? path.removeFirstSegments(1).makeRelative().toString() : path.toString(); |
1954 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {entryPathMsg, project.getElementName()})); |
1955 |
} |
1956 |
} |
1957 |
} else { |
1958 |
if (entryPathMsg == null) |
1959 |
entryPathMsg = project.getElementName().equals(path.segment(0)) ? path.removeFirstSegments(1).makeRelative().toString() : path.toString(); |
1960 |
return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryPath, new String[] {entryPathMsg, project.getElementName()})); |
1961 |
} |
1962 |
return JavaModelStatus.VERIFIED_OK; |
1963 |
} |
1837 |
} |
1964 |
} |