/******************************************************************************* * Copyright (c) 2003, 2007 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.jst.j2ee.internal.archive; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jst.j2ee.internal.J2EEConstants; import org.eclipse.jst.j2ee.internal.plugin.IJ2EEModuleConstants; import org.eclipse.jst.j2ee.internal.plugin.J2EEPlugin; import org.eclipse.jst.j2ee.internal.project.J2EEProjectUtilities; import org.eclipse.jst.jee.archive.ArchiveOpenFailureException; import org.eclipse.jst.jee.archive.ArchiveOptions; import org.eclipse.jst.jee.archive.IArchive; import org.eclipse.jst.jee.archive.IArchiveFactory; import org.eclipse.jst.jee.archive.IArchiveResource; import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; import org.eclipse.wst.common.componentcore.resources.IVirtualContainer; public class ConnectorComponentArchiveLoadAdapter extends ComponentArchiveLoadAdapter { private int dotJavaLength = JavaEEArchiveUtilities.DOT_JAVA.length(); private List alreadyIndexed = new ArrayList(); private Map classesMap; private IFile knownDD; public static String[] knownLibExtensions = { IJ2EEModuleConstants.JAR_EXT, ".zip", //$NON-NLS-1$ ".so", //$NON-NLS-1$ ".o", //$NON-NLS-1$ ".sl", //$NON-NLS-1$ ".dll", //$NON-NLS-1$ }; public ConnectorComponentArchiveLoadAdapter(IVirtualComponent vComponent) { this(vComponent, true); } public ConnectorComponentArchiveLoadAdapter(IVirtualComponent vComponent, boolean includeClasspathComponents) { super(vComponent, includeClasspathComponents); knownDD = vComponent.getRootFolder().getFile(J2EEConstants.RAR_DD_URI).getUnderlyingFile(); } @Override public List<IArchiveResource> getArchiveResources() { if (shouldOptimize()) { attemptOptimization(); } if (!membersOptimized) { addNestedJARsFromSourceRoots(); aggregateSourceFiles(); } return filesHolder.getFiles(); } private void addNestedJARsFromSourceRoots() { IPackageFragmentRoot[] sourceRoots = J2EEProjectUtilities.getSourceContainers(vComponent.getProject()); for (int i = 0; i < sourceRoots.length; i++) { IArchiveResource aFile; try { aFile = getNestedJar(sourceRoots[i]); if (null != aFile) { filesHolder.addFile(aFile); } } catch (JavaModelException e) { J2EEPlugin.logError(e); } catch (ArchiveOpenFailureException e) { J2EEPlugin.logError(e); } } } private IArchiveResource getNestedJar(IPackageFragmentRoot sourceRoot) throws JavaModelException, ArchiveOpenFailureException { IPath outputPath = sourceRoot.getRawClasspathEntry().getOutputLocation(); if (outputPath == null) { IProject project = vComponent.getProject(); try { if (project.hasNature(JavaCore.NATURE_ID)) { IJavaProject javaProject = JavaCore.create(project); outputPath = javaProject.getOutputLocation(); } } catch (CoreException e) { J2EEPlugin.logError(e); } if (outputPath == null) { return null; } } IFolder javaOutputFolder = ResourcesPlugin.getWorkspace().getRoot().getFolder(outputPath); indexClassesForOutputFolder(javaOutputFolder); IContainer sourceContainer = (IContainer) sourceRoot.getResource(); int sourceContainerSegmentCount = sourceContainer.getProjectRelativePath().segmentCount(); boolean isModuleRoot = knownDD.getProjectRelativePath().toString().startsWith(sourceContainer.getProjectRelativePath().toString()); Set iFilesSet = new HashSet(); boolean foundJava = gatherFilesForJAR(iFilesSet, sourceContainer, isModuleRoot, false, sourceContainerSegmentCount); if (!isModuleRoot || foundJava) { List <IFile> iFilesList = Collections.list(Collections.enumeration(iFilesSet)); for (int i = 0; i < iFilesList.size(); i++) { filesHolder.removeIFile(iFilesList.get(i)); } IArchiveResource nestedArchive = createNestedArchive(iFilesList, sourceContainer, javaOutputFolder); return nestedArchive; } return null; } private boolean gatherFilesForJAR(Collection iFiles, IContainer current, boolean isModuleRoot, boolean foundJava, int sourceContainerSegmentCount) { IResource[] members = null; try { members = current.members(); } catch (CoreException core) { // TODO // throw new ArchiveRuntimeException(core); } IContainer ddFolder = vComponent.getRootFolder().getFolder(J2EEConstants.META_INF).getUnderlyingFolder(); boolean localFoundJava = foundJava; if(members != null){ for (int i = 0; i < members.length; i++) { IResource res = members[i]; if (res.getType() == IResource.FOLDER) { if (!ddFolder.equals(res)) {//if it's not the dd folder localFoundJava = gatherFilesForJAR(iFiles, (IFolder) res, isModuleRoot, localFoundJava, sourceContainerSegmentCount) || localFoundJava; } } else {// it must be a file IFile srcFile = (IFile) res; if (belongsInNestedJAR(srcFile, isModuleRoot)) { if (JavaEEArchiveUtilities.isJava(srcFile)) { if (exportSource) { iFiles.add(srcFile); // don't need to check // duplicates here } String className = srcFile.getProjectRelativePath().removeFirstSegments(sourceContainerSegmentCount).toString(); className = className.substring(0, className.length() - dotJavaLength); List classes = retrieveClasses(className); if (null != classes) { Iterator iterator = classes.iterator(); while (iterator.hasNext()) { IFile clazz = (IFile) iterator.next(); if (!iFiles.contains(clazz)) { // .class need to check for duplicates iFiles.add(clazz); } } } } else { if (!iFiles.contains(srcFile)) { // if it's not src, then it could be .class and need // to check for duplicates iFiles.add(srcFile); } } if (isModuleRoot) localFoundJava = localFoundJava || JavaEEArchiveUtilities.isJava(srcFile) || JavaEEArchiveUtilities.isClass(srcFile); } } } } return localFoundJava; } private IArchive createNestedArchive(List <IFile> files, IContainer sourceContainer, IFolder javaOutputFolder) throws ArchiveOpenFailureException { ConnectorComponentNestedJARArchiveLoadAdapter nestedLoader = new ConnectorComponentNestedJARArchiveLoadAdapter(files, sourceContainer, javaOutputFolder); ArchiveOptions nestedOptions = new ArchiveOptions(); nestedOptions.setOption(ArchiveOptions.LOAD_ADAPTER, nestedLoader); IArchive nestedArchive = IArchiveFactory.INSTANCE.openArchive(nestedOptions); nestedArchive.setPath(new Path(computeUniqueArchiveURI(sourceContainer))); nestedArchive.setArchive(archive); return nestedArchive; } private String computeUniqueArchiveURI(IResource resource) { int increment = 0; String name = resource.getName(); StringBuffer sb = null; do { sb = new StringBuffer(name.length() + 5); sb.append('_'); sb.append(name); if (increment > 0) sb.append(increment); sb.append(IJ2EEModuleConstants.JAR_EXT); increment++; } while (filesHolder.contains(new Path(sb.toString()))); return sb.toString(); } private boolean belongsInNestedJAR(IFile iFile, boolean isModuleRoot) { if (isModuleRoot && isDeploymentDescriptor(iFile)) { return false; } for (int i = 0; i < knownLibExtensions.length; i++) { if (JavaEEArchiveUtilities.hasExtension(iFile, knownLibExtensions[i])) return false; } return true; } @Override protected boolean shouldInclude(IPath path) { String lastSegment = path.lastSegment(); return null != lastSegment && !JavaEEArchiveUtilities.hasExtension(lastSegment, JavaEEArchiveUtilities.DOT_CLASS) && !JavaEEArchiveUtilities.hasExtension(lastSegment, JavaEEArchiveUtilities.DOT_JAVA); } /** * Find all the .class files and index them so inner classes can be located. */ private void indexClassesForOutputFolder(IFolder javaOutputFolder) { if (null == javaOutputFolder || alreadyIndexed.contains(javaOutputFolder)) { return; } alreadyIndexed.add(javaOutputFolder); int segmentCount = javaOutputFolder.getProjectRelativePath().segmentCount(); indexClasses(javaOutputFolder, segmentCount); } private void indexClasses(IResource resource, int javaOutputSegmentCount) { switch (resource.getType()) { case IResource.FILE: indexClass((IFile) resource, javaOutputSegmentCount); break; case IResource.FOLDER: try { IResource[] members = ((IFolder) resource).members(); for (int i = 0; i < members.length; i++) { indexClasses(members[i], javaOutputSegmentCount); } } catch (CoreException e) { J2EEPlugin.logError(e); } break; } } private void indexClass(IFile iFile, int javaOutputSegmentCount) { if (!JavaEEArchiveUtilities.isClass(iFile)) return; if (classesMap == null) classesMap = new HashMap(); String name = iFile.getName(); IPath relPath = iFile.getProjectRelativePath().removeFirstSegments(javaOutputSegmentCount); String key = relPath.toString(); if (name.indexOf('$') != -1) { key = key.substring(0, key.indexOf('$')); } else { key = key.substring(0, key.indexOf('.')); } List inners = (List) classesMap.get(key); if (inners == null) { inners = new ArrayList(1); classesMap.put(key, inners); } inners.add(iFile); } public List retrieveClasses(String key) { if (classesMap == null) return null; return (List) classesMap.get(key); } private boolean isDeploymentDescriptor(IFile iFile) { return knownDD.equals(iFile); } @Override protected IPath getDefaultModelObjectPath() { return new Path(J2EEConstants.RAR_DD_URI); } @Override protected boolean shouldInclude(IVirtualContainer vContainer) { boolean isDDFolder = vComponent.getRootFolder().getFolder(J2EEConstants.META_INF).equals(vContainer); return isDDFolder || !inJavaSrc(vContainer); } }