Index: C:/Documents and Settings/Rob/Eclipse Workspaces/Maven2 Plugin Workspace/org.maven.ide.eclipse/src/org/maven/ide/eclipse/embedder/BuildPathManager.java =================================================================== --- C:/Documents and Settings/Rob/Eclipse Workspaces/Maven2 Plugin Workspace/org.maven.ide.eclipse/src/org/maven/ide/eclipse/embedder/BuildPathManager.java (revision 231) +++ C:/Documents and Settings/Rob/Eclipse Workspaces/Maven2 Plugin Workspace/org.maven.ide.eclipse/src/org/maven/ide/eclipse/embedder/BuildPathManager.java (working copy) @@ -58,12 +58,16 @@ import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IProjectNature; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IBundleGroup; +import org.eclipse.core.runtime.IBundleGroupProvider; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.jdt.core.IAccessRule; import org.eclipse.jdt.core.IClasspathAttribute; @@ -92,6 +96,14 @@ private final MavenModelManager mavenModelManager; private final MavenRepositoryIndexManager indexManager; private final IPreferenceStore preferenceStore; + + public static final String CLASSPATH_COMPONENT_NON_DEPENDENCY = "org.eclipse.jst.component.nondependency"; + public static final String CLASSPATH_COMPONENT_DEPENDENCY = "org.eclipse.jst.component.dependency"; + + public static final String JST_IDENTIFER = "org.eclipse.jst"; + + public static final String PACKAGING_EAR = "ear"; + public static final String PACKAGING_WAR = "war"; public BuildPathManager(MavenEmbedderManager embedderManager, Maven2Console console, @@ -125,16 +137,105 @@ Maven2ClasspathContainer container = new Maven2ClasspathContainer(entries); - JavaCore.setClasspathContainer(container.getPath(), new IJavaProject[] {JavaCore.create(project)}, + IJavaProject javaProject = JavaCore.create(project); + JavaCore.setClasspathContainer(container.getPath(), new IJavaProject[] {javaProject}, new IClasspathContainer[] {container}, monitor); + String runtimePath = getRuntimePath(pomFile); + if (runtimePath != null) { + setWTPDependencyAttribute(javaProject, container, runtimePath); + } + for(Iterator it = dependentProjects.iterator(); it.hasNext();) { IProject p = (IProject) it.next(); updateClasspathContainer(p, recursive, monitor); } } + private String getRuntimePath(IFile pomFile) { + Model model = mavenModelManager.getMavenModel(pomFile); + String packaging = model.getPackaging(); + String runtimePath = null; + if (PACKAGING_WAR.equalsIgnoreCase(packaging)) { + runtimePath = "/WEB-INF/lib"; + } + return runtimePath; + } + + /** + * Updates the specified Java project so that the Maven Classpath Container has + * the WTP component dependency attribute. + * @param javaProject Target Java project. + * @param entries Classpath entries that should have the component dependency attribute. Map from IClasspathEntry + * to the IClasspathAttribute for the WTP classpath component dependency. + * @throws CoreException Thrown if an error is encountered. + */ + private void setWTPDependencyAttribute(final IJavaProject javaProject, IClasspathContainer container, String runtimePath) throws CoreException { + if (javaProject == null || !javaProject.getProject().isAccessible()) { + return; + } + final List updatedClasspath = new ArrayList(); + final IClasspathEntry[] rawClasspath = javaProject.getRawClasspath(); + boolean found = false; + for (int i = 0; i < rawClasspath.length; i++) { + IClasspathEntry entry = rawClasspath[i]; + if (found == false && entry.getPath().equals(container.getPath())) { + found = true; + if (checkForComponentDependencyAttribute(entry) == null) { + // No work to do + return; + } + // should have the attribute and currently missing it + IClasspathAttribute attrib = JavaCore.newClasspathAttribute(CLASSPATH_COMPONENT_DEPENDENCY, runtimePath); + IClasspathAttribute[] updatedAttributes = updateAttributes(entry.getExtraAttributes(), attrib, true); + entry = JavaCore.newContainerEntry(entry.getPath(), entry.getAccessRules(), updatedAttributes, entry.isExported()); + } + + updatedClasspath.add(entry); + } + final IClasspathEntry[] updatedCPArray = (IClasspathEntry[]) updatedClasspath.toArray(new IClasspathEntry[updatedClasspath.size()]); + javaProject.setRawClasspath(updatedCPArray, null); + } + private IClasspathAttribute[] updateAttributes(final IClasspathAttribute[] currentAttribs, final IClasspathAttribute targetAttrib, final boolean add) { + final List updatedAttribs = new ArrayList(); + boolean hasAttrib = false; + for (int i = 0; i < currentAttribs.length; i++) { + if (currentAttribs[i].getName().equals(targetAttrib.getName())) { + hasAttrib = true; + if (!add) { + continue; + } + } + updatedAttribs.add(currentAttribs[i]); + } + if (add && !hasAttrib) { + updatedAttribs.add(targetAttrib); + } + return (IClasspathAttribute[]) updatedAttribs.toArray(new IClasspathAttribute[updatedAttribs.size()]); + } + + /** + * Checks if the specified IClasspathEntry has one of the special WTP component dependency + * attributes that indicate it should be mapped into the virtual component for the associated project. + * + * @param entry The IClasspathEntry. + * @return The IClasspathAttribute that holds the special WTP attribute or null if one was not found. + */ + private static IClasspathAttribute checkForComponentDependencyAttribute(final IClasspathEntry entry) { + if (entry == null) { + return null; + } + final IClasspathAttribute[] attributes = entry.getExtraAttributes(); + for (int i = 0; i < attributes.length; i++) { + final IClasspathAttribute attribute = attributes[i]; + if (CLASSPATH_COMPONENT_DEPENDENCY.equals(attribute.getName())) { + return attribute; + } + } + return null; + } + private void resolveClasspathEntries(Set libraryEntries, Map moduleArtifacts, IFile rootPomFile, IFile pomFile, boolean recursive, IProgressMonitor monitor) { if(monitor.isCanceled()) { @@ -154,6 +255,8 @@ boolean downloadSources = !offline & preferenceStore.getBoolean(Maven2PreferenceConstants.P_DOWNLOAD_SOURCES); boolean downloadJavadoc = !offline & preferenceStore.getBoolean(Maven2PreferenceConstants.P_DOWNLOAD_JAVADOC); boolean debug = preferenceStore.getBoolean(Maven2PreferenceConstants.P_DEBUG_OUTPUT); + // TODO extract and set only when installed bundles are changed + boolean wtpAvailable = isWTPAvailable(); MavenExecutionResult result = mavenModelManager.readMavenProject(pomFile, monitor, offline, debug); MavenProject mavenProject = getMavenProject(pomFile, result); @@ -195,6 +298,13 @@ // this is needed to projects with have modules (either inner or external) mavenModelManager.addProjectArtifact(rootPomFile, a); + // Check the scope & set WTP non-dependency as appropriate + List attributeList = new ArrayList(); + String scope = a.getScope(); + if (Artifact.SCOPE_PROVIDED.equals(scope) || Artifact.SCOPE_TEST.equals(scope) || Artifact.SCOPE_SYSTEM.equals(scope)) { + attributeList.add(JavaCore.newClasspathAttribute(CLASSPATH_COMPONENT_NON_DEPENDENCY, "")); + } + IFile artifactPomFile = mavenModelManager.getArtifactFile(a); if(artifactPomFile != null) { IProject artifactProject = artifactPomFile.getProject(); @@ -203,6 +313,11 @@ // add our own project to ourself continue; } + + if (wtpAvailable && PACKAGING_WAR.equals(mavenProject.getPackaging()) && hasDynamicWebProjectNature(currentProject)) { + // Leave it out so that the user can handle it the WTP way + continue; + } libraryEntries.add(JavaCore.newProjectEntry(artifactProject.getFullPath(), false)); continue; @@ -210,7 +325,7 @@ Path srcPath = materializeArtifactPath(embedder, mavenProject, a, "java-source", "sources", downloadSources, monitor); - IClasspathAttribute[] attributes = new IClasspathAttribute[0]; + if(srcPath == null) { // no need to search for javadoc if we have source code Path javadocPath = materializeArtifactPath(embedder, mavenProject, a, "javadoc", "javadoc", downloadJavadoc, monitor); String javaDocUrl = null; @@ -220,11 +335,12 @@ javaDocUrl = getJavaDocUrl(artifactLocation, monitor); } if(javaDocUrl != null) { - attributes = new IClasspathAttribute[] {JavaCore.newClasspathAttribute( - IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, javaDocUrl)}; + attributeList.add(JavaCore.newClasspathAttribute( + IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, javaDocUrl)); } } + IClasspathAttribute[] attributes = (IClasspathAttribute[]) attributeList.toArray(new IClasspathAttribute[attributeList.size()]); libraryEntries.add(JavaCore.newLibraryEntry(new Path(artifactLocation), srcPath, null, new IAccessRule[0], attributes, false /*not exported*/)); } @@ -269,7 +385,40 @@ } } - + + // TODO work out how to listen for changes in the installed bundles and only run this then + private boolean isWTPAvailable() { + IBundleGroupProvider[] bundleGroupProviders = Platform.getBundleGroupProviders(); + for(int i = 0; i < bundleGroupProviders.length; i++ ) { + IBundleGroupProvider bundleGroupProvider = bundleGroupProviders[i]; + IBundleGroup[] bundleGroups = bundleGroupProvider.getBundleGroups(); + for(int j = 0; j < bundleGroups.length; j++ ) { + IBundleGroup bundleGroup = bundleGroups[j]; + if (JST_IDENTIFER.equals(bundleGroup.getIdentifier())) { + String version = bundleGroup.getVersion(); + int majorVersion = Integer.parseInt(version.substring(0, version.indexOf('.'))); + if (majorVersion >= 2) { + return true; + } + } + } + } + return false; + } + + private boolean hasDynamicWebProjectNature(IProject project) { + try { + IProjectNature nature1 = project.getNature("org.eclipse.wst.common.modulecore.ModuleCoreNature"); + IProjectNature nature2 = project.getNature("org.eclipse.wst.common.project.facet.core.nature"); + if (nature1 != null && nature2 != null) { + return true; + } + } catch (Exception e) { + console.logError("Unable to inspect nature: " + e); + } + return false; + } + private MavenProject getMavenProject(IFile pomFile, MavenExecutionResult result) { deleteMarkers(pomFile);