/******************************************************************************* * Copyright (c) 2000, 2014 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.jdt.internal.core; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJarEntryResource; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaModelStatusConstants; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.core.util.Util; /** * A package fragment that represents a package fragment found in a JAR. * * @see org.eclipse.jdt.core.IPackageFragment */ @SuppressWarnings({ "rawtypes", "unchecked" }) class JarPackageFragment extends PackageFragment { /** * Constructs a package fragment that is contained within a jar or a zip. */ protected JarPackageFragment(PackageFragmentRoot root, String[] names) { super(root, names); } /** * @see Openable */ protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException { JarPackageFragmentRoot root = (JarPackageFragmentRoot) getParent(); JarPackageFragmentRootInfo parentInfo = (JarPackageFragmentRootInfo) root.getElementInfo(); ArrayList[] entries = (ArrayList[]) parentInfo.rawPackageInfo.get(this.names); if (entries == null) throw newNotPresentException(); JarPackageFragmentInfo fragInfo = (JarPackageFragmentInfo) info; // compute children fragInfo.setChildren(computeChildren(entries[0/*class files*/])); // compute non-Java resources fragInfo.setNonJavaResources(computeNonJavaResources(entries[1/*non Java resources*/])); newElements.put(this, fragInfo); return true; } /** * Compute the children of this package fragment. Children of jar package fragments * can only be IClassFile (representing .class files). */ private IJavaElement[] computeChildren(ArrayList namesWithoutExtension) { int size = namesWithoutExtension.size(); if (size == 0) return NO_ELEMENTS; IJavaElement[] children = new IJavaElement[size]; for (int i = 0; i < size; i++) { String nameWithoutExtension = (String) namesWithoutExtension.get(i); children[i] = new ClassFile(this, nameWithoutExtension); } return children; } /** * Compute all the non-java resources according to the given entry names. */ private Object[] computeNonJavaResources(ArrayList entryNames) { int length = entryNames.size(); if (length == 0) return JavaElementInfo.NO_NON_JAVA_RESOURCES; HashMap jarEntries = new HashMap(); // map from IPath to IJarEntryResource HashMap childrenMap = new HashMap(); // map from IPath to ArrayList<IJarEntryResource> ArrayList topJarEntries = new ArrayList(); for (int i = 0; i < length; i++) { String resName = (String) entryNames.get(i); // consider that a .java file is not a non-java resource (see bug 12246 Packages view shows .class and .java files when JAR has source) if (!Util.isJavaLikeFileName(resName)) { IPath filePath = new Path(resName); IPath childPath = filePath.removeFirstSegments(this.names.length); if (jarEntries.containsKey(childPath)) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=222665 continue; } JarEntryFile file = new JarEntryFile(filePath.lastSegment()); jarEntries.put(childPath, file); if (childPath.segmentCount() == 1) { file.setParent(this); topJarEntries.add(file); } else { IPath parentPath = childPath.removeLastSegments(1); while (parentPath.segmentCount() > 0) { ArrayList parentChildren = (ArrayList) childrenMap.get(parentPath); if (parentChildren == null) { Object dir = new JarEntryDirectory(parentPath.lastSegment()); jarEntries.put(parentPath, dir); childrenMap.put(parentPath, parentChildren = new ArrayList()); parentChildren.add(childPath); if (parentPath.segmentCount() == 1) { topJarEntries.add(dir); break; } childPath = parentPath; parentPath = childPath.removeLastSegments(1); } else { parentChildren.add(childPath); break; // all parents are already registered } } } } } Iterator entries = childrenMap.entrySet().iterator(); while (entries.hasNext()) { Map.Entry entry = (Map.Entry) entries.next(); IPath entryPath = (IPath) entry.getKey(); ArrayList entryValue = (ArrayList) entry.getValue(); JarEntryDirectory jarEntryDirectory = (JarEntryDirectory) jarEntries.get(entryPath); int size = entryValue.size(); IJarEntryResource[] children = new IJarEntryResource[size]; for (int i = 0; i < size; i++) { JarEntryResource child = (JarEntryResource) jarEntries.get(entryValue.get(i)); child.setParent(jarEntryDirectory); children[i] = child; } jarEntryDirectory.setChildren(children); if (entryPath.segmentCount() == 1) { jarEntryDirectory.setParent(this); } } return topJarEntries.toArray(new Object[topJarEntries.size()]); } /** * Returns true if this fragment contains at least one java resource. * Returns false otherwise. */ public boolean containsJavaResources() throws JavaModelException { return ((JarPackageFragmentInfo) getElementInfo()).containsJavaResources(); } /** * @see org.eclipse.jdt.core.IPackageFragment */ public ICompilationUnit createCompilationUnit(String cuName, String contents, boolean force, IProgressMonitor monitor) throws JavaModelException { throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this)); } /** * @see JavaElement */ protected Object createElementInfo() { return new JarPackageFragmentInfo(); } /** * @see org.eclipse.jdt.core.IPackageFragment */ public IClassFile[] getClassFiles() throws JavaModelException { ArrayList list = getChildrenOfType(CLASS_FILE); IClassFile[] array= new IClassFile[list.size()]; list.toArray(array); return array; } /** * A jar package fragment never contains compilation units. * @see org.eclipse.jdt.core.IPackageFragment */ public ICompilationUnit[] getCompilationUnits() { return NO_COMPILATION_UNITS; } /** * A package fragment in a jar has no corresponding resource. * * @see IJavaElement */ public IResource getCorrespondingResource() { return null; } /** * Returns an array of non-java resources contained in the receiver. */ public Object[] getNonJavaResources() throws JavaModelException { if (isDefaultPackage()) { // We don't want to show non java resources of the default package (see PR #1G58NB8) return JavaElementInfo.NO_NON_JAVA_RESOURCES; } else { return storedNonJavaResources(); } } protected boolean internalIsValidPackageName() { return true; } /** * Jars and jar entries are all read only */ public boolean isReadOnly() { return true; } protected Object[] storedNonJavaResources() throws JavaModelException { return ((JarPackageFragmentInfo) getElementInfo()).getNonJavaResources(); } }