| /******************************************************************************* |
| * Copyright (c) 2003, 2006 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.common.classpath; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.Hashtable; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| 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.jdt.core.IAccessRule; |
| import org.eclipse.jdt.core.IClasspathAttribute; |
| import org.eclipse.jdt.core.IClasspathContainer; |
| import org.eclipse.jdt.core.IClasspathEntry; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jst.common.jdt.internal.classpath.ClasspathDecorations; |
| import org.eclipse.jst.common.jdt.internal.classpath.ClasspathDecorationsManager; |
| import org.eclipse.jst.j2ee.componentcore.J2EEModuleVirtualComponent; |
| import org.eclipse.jst.j2ee.componentcore.util.EARVirtualComponent; |
| import org.eclipse.jst.j2ee.internal.J2EEConstants; |
| import org.eclipse.jst.j2ee.internal.common.J2EECommonMessages; |
| import org.eclipse.jst.j2ee.internal.plugin.J2EEPlugin; |
| import org.eclipse.jst.j2ee.model.IModelProvider; |
| import org.eclipse.jst.j2ee.model.ModelProviderManager; |
| import org.eclipse.jst.j2ee.project.EarUtilities; |
| import org.eclipse.jst.j2ee.project.JavaEEProjectUtilities; |
| import org.eclipse.jst.javaee.application.Application; |
| import org.eclipse.wst.common.componentcore.ComponentCore; |
| import org.eclipse.wst.common.componentcore.internal.StructureEdit; |
| import org.eclipse.wst.common.componentcore.internal.resources.VirtualArchiveComponent; |
| import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; |
| import org.eclipse.wst.common.componentcore.resources.IVirtualReference; |
| |
| /** |
| * This classpath container is based on the Component references; not the manifest entries. Other |
| * mechanisms are in place to ensure that the component references are updated when the manifest is |
| * updated, and also to make sure the manifest is updated when the component references are updated. |
| * |
| */ |
| public class J2EEComponentClasspathContainer implements IClasspathContainer { |
| |
| public static final String CONTAINER_ID = "org.eclipse.jst.j2ee.internal.module.container"; //$NON-NLS-1$ |
| public static final IPath CONTAINER_PATH = new Path(CONTAINER_ID); |
| |
| private static IPath WEBLIB = new Path("/WEB-INF/lib"); //$NON-NLS-1$ |
| |
| private static ClasspathDecorationsManager decorationsManager = new ClasspathDecorationsManager(J2EEPlugin.PLUGIN_ID); |
| |
| public static ClasspathDecorationsManager getDecorationsManager() { |
| return decorationsManager; |
| } |
| |
| private IPath containerPath; |
| private IJavaProject javaProject; |
| private IClasspathEntry[] entries = new IClasspathEntry[0]; |
| private boolean exportEntries = true; //the default behavior is to always export these dependencies |
| private static Map keys = new Hashtable(); |
| private static int MAX_RETRIES = 10; |
| private static Map retries = new Hashtable(); |
| |
| private class LastUpdate { |
| private int baseRefCount = 0; // count of references returned directly from a component |
| private int refCount = 0; |
| private boolean[] isBinary = new boolean[refCount]; |
| private IPath[] paths = new IPath[refCount]; |
| |
| private int baseLibRefCount = 0; // count of references resolved by EAR 5 lib directory |
| |
| private boolean areSame(IVirtualComponent comp, int i){ |
| if (comp.isBinary() != isBinary[i]) { |
| return false; |
| } else { |
| IPath path = null; |
| if (comp.isBinary()) { |
| VirtualArchiveComponent archiveComp = (VirtualArchiveComponent) comp; |
| java.io.File diskFile = archiveComp.getUnderlyingDiskFile(); |
| if (diskFile.exists()) |
| path = new Path(diskFile.getAbsolutePath()); |
| else { |
| IFile iFile = archiveComp.getUnderlyingWorkbenchFile(); |
| path = iFile.getFullPath(); |
| } |
| } else { |
| path = comp.getProject().getFullPath(); |
| } |
| if (!path.equals(paths[i])) { |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| |
| private LastUpdate lastUpdate = new LastUpdate(); |
| |
| public J2EEComponentClasspathContainer(IPath path, IJavaProject javaProject) { |
| this.containerPath = path; |
| this.javaProject = javaProject; |
| } |
| |
| private boolean requiresUpdate() { |
| IVirtualComponent component = ComponentCore.createComponent(javaProject.getProject()); |
| if (component == null) { |
| return false; |
| } |
| |
| IVirtualReference[] refs = component instanceof J2EEModuleVirtualComponent ? ((J2EEModuleVirtualComponent)component).getReferences(false, true): component.getReferences(); |
| |
| // avoid updating the container if references haven't changed |
| if (refs.length == lastUpdate.baseRefCount) { |
| for (int i = 0; i < lastUpdate.baseRefCount; i++) { |
| IVirtualComponent comp = null; |
| comp = refs[i].getReferencedComponent(); |
| if(!lastUpdate.areSame(comp, i)){ |
| return true; |
| } |
| } |
| List <IVirtualReference> earRefs = getBaseEARLibRefs(component); |
| if(earRefs.size() != lastUpdate.baseLibRefCount){ |
| return true; |
| } else { |
| List refsList = new ArrayList(); |
| Set refedComps = new HashSet(); |
| refedComps.add(component); |
| for(int i = 0; i<refs.length;i++){ |
| refsList.add(refs[i]); |
| refedComps.add(refs[i].getReferencedComponent()); |
| } |
| int i=lastUpdate.baseRefCount; |
| for(IVirtualReference earRef : earRefs){ |
| IVirtualComponent comp = earRef.getReferencedComponent(); |
| // check if the referenced component is already visited - avoid cycles in the build path |
| if (!refedComps.contains(comp)) { |
| if(i == lastUpdate.refCount){ |
| return true; // found something new and need update |
| } |
| // visit the referenced component |
| refsList.add(earRef); |
| refedComps.add(comp); |
| if(!lastUpdate.areSame(comp, i)){ |
| return true; |
| } |
| i++; |
| } |
| } |
| if(i!= lastUpdate.refCount){ |
| return true; // didn't find them all |
| } |
| } |
| return false; |
| } |
| return true; |
| } |
| |
| private void update() { |
| IVirtualComponent component = ComponentCore.createComponent(javaProject.getProject()); |
| if (component == null) { |
| return; |
| } |
| Object key = null; |
| if(!javaProject.getProject().getFile(StructureEdit.MODULE_META_FILE_NAME).exists()){ |
| Integer hashCode = new Integer(javaProject.getProject().hashCode()); |
| key = keys.get(hashCode); |
| if(key == null){ |
| keys.put(hashCode, hashCode); |
| key = hashCode; |
| } |
| Integer retryCount = (Integer)retries.get(key); |
| if(retryCount == null){ |
| retryCount = new Integer(1); |
| } else if(retryCount.intValue() > MAX_RETRIES){ |
| return; |
| } else { |
| retryCount = new Integer(retryCount.intValue() + 1); |
| } |
| retries.put(key, retryCount); |
| J2EEComponentClasspathUpdater.getInstance().queueUpdate(javaProject.getProject()); |
| return; |
| } else { |
| if(key != null){ |
| retries.remove(key); |
| keys.remove(key); |
| } |
| } |
| |
| IVirtualComponent comp = null; |
| IVirtualReference ref = null; |
| |
| IVirtualReference[] refs = component instanceof J2EEModuleVirtualComponent ? ((J2EEModuleVirtualComponent)component).getReferences(false, true): component.getReferences(); |
| lastUpdate.baseRefCount = refs.length; |
| |
| List refsList = new ArrayList(); |
| Set refedComps = new HashSet(); |
| refedComps.add(component); |
| for(int i = 0; i<refs.length;i++){ |
| refsList.add(refs[i]); |
| refedComps.add(refs[i].getReferencedComponent()); |
| } |
| |
| List <IVirtualReference> earLibReferences = getBaseEARLibRefs(component); |
| lastUpdate.baseLibRefCount = earLibReferences.size(); |
| for(IVirtualReference earRef : earLibReferences){ |
| IVirtualComponent earRefComp = earRef.getReferencedComponent(); |
| // check if the referenced component is already visited - avoid cycles in the build path |
| if (!refedComps.contains(earRefComp)) { |
| // visit the referenced component |
| refsList.add(earRef); |
| refedComps.add(earRefComp); |
| } |
| } |
| |
| for(int i=0; i< refsList.size(); i++){ |
| comp = ((IVirtualReference)refsList.get(i)).getReferencedComponent(); |
| if(comp.isBinary()){ |
| IVirtualReference [] binaryRefs = comp.getReferences(); |
| for(int j = 0; j<binaryRefs.length; j++){ |
| if(!refedComps.contains(binaryRefs[j].getReferencedComponent())){ |
| refsList.add(binaryRefs[j]); |
| refedComps.add(binaryRefs[j].getReferencedComponent()); |
| } |
| } |
| } |
| } |
| |
| lastUpdate.refCount = refsList.size(); |
| lastUpdate.isBinary = new boolean[lastUpdate.refCount]; |
| lastUpdate.paths = new IPath[lastUpdate.refCount]; |
| |
| boolean isWeb = JavaEEProjectUtilities.isDynamicWebProject(component.getProject()); |
| boolean shouldAdd = true; |
| |
| List entriesList = new ArrayList(); |
| |
| try { |
| IJavaProject javaProject = JavaCore.create(component.getProject()); |
| |
| boolean useJDTToControlExport = J2EEComponentClasspathContainerUtils.getDefaultUseEARLibrariesJDTExport(); |
| if(useJDTToControlExport){ |
| //if the default is not enabled, then check whether the container is being exported |
| IClasspathEntry [] rawEntries = javaProject.readRawClasspath(); |
| for(int i=0;i<rawEntries.length; i++){ |
| IClasspathEntry entry = rawEntries[i]; |
| if(entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER){ |
| if(entry.getPath().equals(CONTAINER_PATH)){ |
| exportEntries = entry.isExported(); |
| break; |
| } |
| } |
| } |
| } |
| |
| for (int i = 0; i < refsList.size(); i++) { |
| ref = (IVirtualReference)refsList.get(i); |
| comp = ref.getReferencedComponent(); |
| lastUpdate.isBinary[i] = comp.isBinary(); |
| shouldAdd = !(isWeb && ref.getRuntimePath().equals(WEBLIB)); |
| if (!shouldAdd) { |
| continue; |
| } |
| if (comp.isBinary()) { |
| VirtualArchiveComponent archiveComp = (VirtualArchiveComponent) comp; |
| if (archiveComp.getArchiveType().equals(VirtualArchiveComponent.CLASSPATHARCHIVETYPE)) { |
| // do not process components dynamically computed from the Java classpath |
| continue; |
| } |
| java.io.File diskFile = archiveComp.getUnderlyingDiskFile(); |
| if (diskFile.exists()) { |
| lastUpdate.paths[i] = new Path(diskFile.getAbsolutePath()); |
| } else { |
| IFile iFile = archiveComp.getUnderlyingWorkbenchFile(); |
| lastUpdate.paths[i] = iFile.getFullPath(); |
| } |
| ClasspathDecorations dec = decorationsManager.getDecorations( getPath().toString(), lastUpdate.paths[i].toString() ); |
| |
| IPath srcpath = null; |
| IPath srcrootpath = null; |
| IClasspathAttribute[] attrs = {}; |
| IAccessRule[] access = {}; |
| |
| if( dec != null ) { |
| srcpath = dec.getSourceAttachmentPath(); |
| srcrootpath = dec.getSourceAttachmentRootPath(); |
| attrs = dec.getExtraAttributes(); |
| } |
| IClasspathEntry newEntry = JavaCore.newLibraryEntry( lastUpdate.paths[i], srcpath, srcrootpath, access, attrs, exportEntries ); |
| entriesList.add(newEntry); |
| } else { |
| IProject project = comp.getProject(); |
| lastUpdate.paths[i] = project.getFullPath(); |
| entriesList.add(JavaCore.newProjectEntry(lastUpdate.paths[i], exportEntries)); |
| } |
| } |
| } finally { |
| entries = new IClasspathEntry[entriesList.size()]; |
| for (int i = 0; i < entries.length; i++) { |
| entries[i] = (IClasspathEntry) entriesList.get(i); |
| } |
| } |
| } |
| |
| private List<IVirtualReference> getBaseEARLibRefs(IVirtualComponent component) { |
| List <IVirtualReference> libRefs = new ArrayList<IVirtualReference>(); |
| // check for the references in the lib dirs of the referencing EARs |
| IVirtualComponent[] referencingList = component.getReferencingComponents(); |
| for (IVirtualComponent referencingComp : referencingList) { |
| // check if the referencing component is an EAR |
| if (EarUtilities.isEARProject(referencingComp.getProject())) { |
| EARVirtualComponent earComp = (EARVirtualComponent) referencingComp; |
| // retrieve the EAR's library directory |
| String libDir = getEARLibDir(earComp); |
| // if the EAR version is lower than 5, then the library directory will be null |
| if (libDir != null) { |
| // check if the component itself is not in the library directory of this EAR - avoid cycles in the build patch |
| if (!libDir.equals(earComp.getReference(component.getName()).getRuntimePath().toString())) { |
| // retrieve the referenced components from the EAR |
| IVirtualReference[] earRefs = earComp.getReferences(); |
| for (IVirtualReference earRef : earRefs) { |
| // check if the referenced component is in the library directory |
| boolean isInLibDir = libDir.equals(earRef.getRuntimePath().toString()); |
| if(!isInLibDir){ |
| IPath fullPath = earRef.getRuntimePath().append(earRef.getArchiveName()); |
| isInLibDir = fullPath.removeLastSegments(1).toString().equals(libDir); |
| } |
| if (isInLibDir) { |
| libRefs.add(earRef); |
| } |
| } |
| } |
| } |
| } |
| } |
| return libRefs; |
| } |
| |
| public static void install(IPath containerPath, IJavaProject javaProject) { |
| try{ |
| J2EEComponentClasspathUpdater.getInstance().pauseUpdates(); |
| final IJavaProject[] projects = new IJavaProject[]{javaProject}; |
| final J2EEComponentClasspathContainer container = new J2EEComponentClasspathContainer(containerPath, javaProject); |
| container.update(); |
| final IClasspathContainer[] conts = new IClasspathContainer[]{container}; |
| try { |
| JavaCore.setClasspathContainer(containerPath, projects, conts, null); |
| } catch (JavaModelException e) { |
| J2EEPlugin.logError(e); |
| } |
| } finally { |
| J2EEComponentClasspathUpdater.getInstance().resumeUpdates(); |
| } |
| } |
| |
| public void refresh(boolean force){ |
| if(force || requiresUpdate()){ |
| install(containerPath, javaProject); |
| } |
| } |
| |
| public void refresh() { |
| refresh(false); |
| } |
| |
| private boolean isUpdating = false; |
| |
| public IClasspathEntry[] getClasspathEntries() { |
| if(!isUpdating){ |
| if(this != J2EEComponentClasspathContainerUtils.getInstalledEARLibrariesContainer(javaProject.getProject())){ |
| try { |
| isUpdating = true; |
| update(); |
| } finally{ |
| isUpdating = false; |
| } |
| } |
| } |
| return entries; |
| } |
| |
| public String getDescription() { |
| return J2EECommonMessages.J2EE_MODULE_CLASSPATH_CONTAINER_NAME; |
| } |
| |
| public int getKind() { |
| return K_APPLICATION; |
| } |
| |
| public IPath getPath() { |
| return containerPath; |
| } |
| |
| /** |
| * Get the library directory from an EAR virtual component |
| * |
| * @param earComponent |
| * the EAR virtual component |
| * |
| * @return a runtime representation of the library directory path or null if |
| * the EAR's version is lower than 5 |
| */ |
| private String getEARLibDir(EARVirtualComponent earComponent) { |
| // check if the EAR component's version is 5 or greater |
| IProject earProject = earComponent.getProject(); |
| if (!JavaEEProjectUtilities.isJEEComponent(earComponent, JavaEEProjectUtilities.DD_VERSION)) { |
| return null; |
| } |
| |
| // default lib dir if there is no deployment descriptor |
| // or if the deployment descriptor does not override |
| String libDir = J2EEConstants.EAR_DEFAULT_LIB_DIR; |
| |
| // retrieve the model provider |
| IModelProvider modelProvider = ModelProviderManager.getModelProvider(earProject); |
| if (modelProvider == null){ |
| return libDir; |
| } |
| |
| // retrieve the EAR's deployment descriptor model object |
| Application app = (Application) modelProvider.getModelObject(new Path(J2EEConstants.APPLICATION_DD_URI)); |
| if (app == null){ |
| return libDir; |
| } |
| |
| // retrieve the library directory from the model |
| String ddLibDir = app.getLibraryDirectory(); |
| if (ddLibDir != null) { |
| libDir = ddLibDir; |
| } |
| |
| return libDir; |
| } |
| |
| } |