blob: 3747198fd8a94dc168f3edfa7278b79bbdc593c8 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2009 Red Hat
* 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:
* Rob Stryker - initial implementation
******************************************************************************/
package org.eclipse.jst.j2ee.internal.modulecore.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jst.common.internal.modulecore.util.ArchiveManifest;
import org.eclipse.jst.common.internal.modulecore.util.IJavaComponentDiscerner;
import org.eclipse.jst.common.internal.modulecore.util.ManifestUtilities;
import org.eclipse.jst.j2ee.project.EarUtilities;
import org.eclipse.wst.common.componentcore.ComponentCore;
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
import org.eclipse.wst.common.componentcore.resources.IVirtualFile;
import org.eclipse.wst.common.componentcore.resources.IVirtualFolder;
import org.eclipse.wst.common.componentcore.resources.IVirtualReference;
/**
* This class is meant to discover possible manifest entries for a parent / child combo.
* This might be better implemented using flat virtual component model to make more
* accurate use of consumes, etc. But that can change later (as usual)
*/
public class JEEManifestDiscerner implements IJavaComponentDiscerner {
public IProject[] findParentProjects(IProject child) {
return EarUtilities.getReferencingEARProjects(child);
}
public IVirtualReference[] findPossibleManifestEntries(
IProject parentProject, IProject childProject) {
if( EarUtilities.isEARProject(parentProject)) {
ArrayList<IVirtualReference> allPossible = findAllPossibleEntries(parentProject, childProject);
IVirtualReference[] alreadyReferenced = findCurrentManifestEntries(parentProject, childProject, allPossible);
allPossible.removeAll(Arrays.asList(alreadyReferenced));
return allPossible.toArray(new IVirtualReference[allPossible.size()]);
}
return new IVirtualReference[]{};
}
public IVirtualReference[] findPossibleManifestEntries(
IProject parentProject, IProject childProject, IVirtualReference[] currentEntries) {
if( EarUtilities.isEARProject(parentProject)) {
ArrayList<IVirtualReference> allPossible = findAllPossibleEntries(parentProject, childProject);
allPossible.removeAll(Arrays.asList(currentEntries));
return allPossible.toArray(new IVirtualReference[allPossible.size()]);
}
return new IVirtualReference[]{};
}
protected ArrayList<IVirtualReference> findAllPossibleEntries(IProject parentProject, IProject childProject) {
IVirtualComponent ear = ComponentCore.createComponent(parentProject);
IVirtualReference[] hardRefs = ear.getReferences();
IVirtualReference[] actual_tmp = trimEarHardRefs(ear, childProject, hardRefs);
IVirtualReference[] actual_clean = cleanHardRefs(actual_tmp, childProject, hardRefs);
ArrayList<IVirtualReference> refs = new ArrayList<IVirtualReference>();
refs.addAll(Arrays.asList(actual_clean));
return refs;
}
/**
* Prune out unacceptable reference types
* @param childProject
* @param hardRefs
* @return
*/
private IVirtualReference[] trimEarHardRefs(IVirtualComponent ear, IProject childProject, IVirtualReference[] hardRefs) {
String earLibDir = EarUtilities.getEARLibDir(ear);
IPath earLibDirPath = null;
if(earLibDir != null)
earLibDirPath = new Path(earLibDir).makeRelative();
ArrayList<IVirtualReference> refs = new ArrayList<IVirtualReference>();
// We have to prune out self-references
for( int i = 0; i < hardRefs.length; i++ ) {
// This is actually hard to make sure we're not adding ourself
if((hardRefs[i].getReferencedComponent().isBinary()
|| hardRefs[i].getDependencyType() == IVirtualReference.DEPENDENCY_TYPE_CONSUMES
|| !hardRefs[i].getReferencedComponent().getProject().equals(childProject))
&& hardRefs[i].getArchiveName().endsWith("jar")) { //$NON-NLS-1$ // Only jar's are legal in MANIFEST
if(earLibDirPath == null || earLibDirPath.isEmpty() || !hardRefs[i].getRuntimePath().makeRelative().equals(earLibDirPath)) {// Jars in the EAR's library directory should not be added to the MANIFEST for EE5/EE6
refs.add(hardRefs[i]);
}
}
}
return refs.toArray(new IVirtualReference[refs.size()]);
}
/**
* Make sure the runtime path + archiveName is what should go in the manifest file
* if this reference is selected
*
* @param original
* @return
*/
private IVirtualReference[] cleanHardRefs(IVirtualReference[] original, IProject childProject, IVirtualReference[] hardRefs) {
IVirtualReference childProjectVirtualRef = null;
for( int i = 0; i < hardRefs.length; i++ ) {
if(hardRefs[i].getReferencedComponent().getProject().equals(childProject)) {
childProjectVirtualRef = hardRefs[i];
break;
}
}
IVirtualReference[] newRefs = new IVirtualReference[original.length];
for( int i = 0; i < newRefs.length; i++ ) {
newRefs[i] = ComponentCore.createReference(original[i].getEnclosingComponent(),
original[i].getReferencedComponent(), calculateManifestRelativeRuntimePath(childProjectVirtualRef, original[i]));
newRefs[i].setDependencyType(original[i].getDependencyType());
newRefs[i].setArchiveName((new Path(original[i].getArchiveName())).lastSegment());
}
return newRefs;
}
public static IPath calculateManifestRelativeRuntimePath(IVirtualReference childProjectVirtualRef, IVirtualReference manifestEntryReference) {
IPath manifestEntryPath = manifestEntryReference.getRuntimePath();
// Return the manifestEntryReference's relative runtime path if the child project is at root level
if(childProjectVirtualRef == null || childProjectVirtualRef.getRuntimePath().equals("/")) //$NON-NLS-1$
return manifestEntryPath.makeRelative();
IPath childProjectRuntimePath = childProjectVirtualRef.getRuntimePath();
// Return an empty runtime path if the child project and manifest entry have same runtime path
if(childProjectRuntimePath.equals(manifestEntryPath))
return new Path(""); //$NON-NLS-1$
String[] childProjectFolders = childProjectRuntimePath.segments();
String[] manifestEntryFolders = manifestEntryPath.segments();
int commonFolderCount = 0;
for(int i = 0; i < childProjectFolders.length; i++) {
if(i >= manifestEntryFolders.length || !childProjectFolders[i].equals(manifestEntryFolders[i]))
break;
commonFolderCount++;
}
final String upOneLevel = "../"; //$NON-NLS-1$
String resultString = ""; //$NON-NLS-1$
for(int i = 0; i < childProjectFolders.length - commonFolderCount; i++) {
resultString += upOneLevel;
}
return new Path(resultString).append(manifestEntryPath.removeFirstSegments(commonFolderCount));
}
public IVirtualReference[] findCurrentManifestEntries(
IProject parentProject, IProject childProject) {
return findCurrentManifestEntries(parentProject, childProject,
findAllPossibleEntries(parentProject, childProject));
}
protected IVirtualReference[] findCurrentManifestEntries(
IProject parentProject, IProject childProject, ArrayList<IVirtualReference> allPossibleEntries) {
ArrayList<IVirtualReference> currentEntries = new ArrayList<IVirtualReference>();
IFile manifestFile = getManifestFile(childProject);
if(manifestFile != null) {
ArchiveManifest manifest = ManifestUtilities.getManifest(manifestFile);
List<String> entries = Arrays.asList(manifest.getClassPathTokenized());
Iterator<IVirtualReference> i = allPossibleEntries.iterator();
IVirtualReference currentI;
// Add entries that are in the Manifest
while(i.hasNext()) {
currentI = i.next();
String currentEntry = currentI.getRuntimePath().append((new Path(currentI.getArchiveName())).lastSegment()).toString();
if(entries.contains(currentEntry))
currentEntries.add(currentI);
}
}
return currentEntries.toArray(new IVirtualReference[currentEntries.size()]);
}
protected IFile getManifestFile(IProject child) {
IVirtualComponent root = ComponentCore.createComponent(child);
IVirtualFolder rootFolder = root.getRootFolder();
IVirtualFile vf = rootFolder.getFile(new Path("META-INF/MANIFEST.MF")); //$NON-NLS-1$
if( vf.exists() )
return vf.getUnderlyingFile();
return null;
}
/**
* This is the usecase we'd like to deprecate, one day. One day.....
* (Though konstantin says NO)
* @param parentProject
* @param hardRefs
* @return
*/
// private IVirtualReference[] LEGACY_getClasspathDependencies(IProject parentProject, IVirtualReference[] hardRefs) {
// ArrayList<IVirtualReference> retval = new ArrayList<IVirtualReference>();
// ArrayList<IProject> seenProjects = new ArrayList<IProject>();
// seenProjects.add(parentProject);
// for( int i = 0; i < hardRefs.length; i++ ) {
// if( hardRefs[i].getReferencedComponent() instanceof IClasspathDependencyProvider) {
// // Already flagged classpaths
// final IClasspathDependencyProvider j2eeComp = (IClasspathDependencyProvider) hardRefs[i].getReferencedComponent();
// final IVirtualReference[] refs = j2eeComp.getJavaClasspathReferences();
// for( int j = 0; j < refs.length; j++ ) {
// if( !((IClasspathDependencyComponent)refs[j].getReferencedComponent()).isClassFolder()) {
// // Clean this reference's runtime path
// IPath newRuntimePath = refs[j].getRuntimePath();
// if( newRuntimePath.toString().startsWith("../")) //$NON-NLS-1$
// newRuntimePath = new Path(newRuntimePath.toString().substring(2)).makeRelative();
// IVirtualReference tmp = ComponentCore.createReference(refs[j].getEnclosingComponent(),
// refs[j].getReferencedComponent(), newRuntimePath);
// tmp.setDependencyType(refs[j].getDependencyType());
// tmp.setArchiveName(refs[j].getArchiveName());
// retval.add(tmp);
// }
// }
// }
// }
// return retval.toArray(new IVirtualReference[retval.size()]);
// }
// // Now find *potential* entries
// IProject cp = hardRefs[i].getReferencedComponent().getProject();
// if( !seenProjects.contains(cp)) {
// seenProjects.add(cp);
// IJavaProjectLite lite = JavaCoreLite.create(cp);
// try {
// List<IClasspathEntry> entries = ClasspathDependencyUtil.getPotentialComponentClasspathDependencies(lite);
// Iterator<IClasspathEntry> k = entries.iterator();
// while(k.hasNext()) {
// IVirtualReference tmp = LEGACY_convertClasspathEntry(cp, k.next());
// if( tmp != null )
// retval.add(tmp);
// }
// } catch( CoreException ce ) {}
// }
// }
//
// private IVirtualReference LEGACY_convertClasspathEntry(IProject project, IClasspathEntry entry) {
// IVirtualComponent tmp = ComponentCore.createComponent(project);
// final IPath entryLocation = ClasspathDependencyUtil.getEntryLocation(entry);
// if(entryLocation != null && !ClasspathDependencyUtil.isClassFolderEntry(entry)) {
// final IClasspathAttribute attrib = ClasspathDependencyUtil.checkForComponentDependencyAttribute(
// entry, DependencyAttributeType.CLASSPATH_COMPONENT_DEPENDENCY, false);
// boolean isWebApp = J2EEProjectUtilities.isDynamicWebProject(project);
// IPath runtimePath = ClasspathDependencyUtil.getRuntimePath(attrib, isWebApp, false);
// String componentPath = VirtualArchiveComponent.CLASSPATHARCHIVETYPE
// + IPath.SEPARATOR + entryLocation.toPortableString();
// IVirtualComponent entryComponent = new ClasspathDependencyVirtualComponent(
// project, componentPath, false);
// final IVirtualReference entryReference = ComponentCore.createReference(tmp, entryComponent, runtimePath);
// ((VirtualReference) entryReference).setDerived(true);
// entryReference.setArchiveName(ClasspathDependencyUtil.getArchiveName(entry));
// return entryReference;
// }
// return null;
// }
}