Index: /Users/amuino/dev/workspaces/m2eclipse/org.maven.ide.eclipse/META-INF/MANIFEST.MF =================================================================== --- /Users/amuino/dev/workspaces/m2eclipse/org.maven.ide.eclipse/META-INF/MANIFEST.MF (revision 250) +++ /Users/amuino/dev/workspaces/m2eclipse/org.maven.ide.eclipse/META-INF/MANIFEST.MF (working copy) @@ -2,7 +2,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: Maven 2.0 integration Bundle-SymbolicName: org.maven.ide.eclipse; singleton:=true -Bundle-Version: 0.0.11.20070603-1200 +Bundle-Version: 0.0.11.20070731-0000 Bundle-Activator: org.maven.ide.eclipse.Maven2Plugin Bundle-Vendor: maven.org Bundle-Localization: plugin Index: /Users/amuino/dev/workspaces/m2eclipse/org.maven.ide.eclipse/src/org/maven/ide/eclipse/embedder/BuildPathManager.java =================================================================== --- /Users/amuino/dev/workspaces/m2eclipse/org.maven.ide.eclipse/src/org/maven/ide/eclipse/embedder/BuildPathManager.java (revision 250) +++ /Users/amuino/dev/workspaces/m2eclipse/org.maven.ide.eclipse/src/org/maven/ide/eclipse/embedder/BuildPathManager.java (working copy) @@ -58,8 +58,11 @@ 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; @@ -64,6 +67,7 @@ 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; @@ -85,7 +89,11 @@ import org.maven.ide.eclipse.preferences.Maven2PreferenceConstants; import org.maven.ide.eclipse.util.Util; - +/** + * TODO: Document me + * + * @author amuino (MNGECLIPSE-105) + */ public class BuildPathManager { private final MavenEmbedderManager embedderManager; private final Maven2Console console; @@ -92,6 +100,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, @@ -126,7 +142,8 @@ public void updateClasspathContainer(IProject project, boolean recursive, IProgressMonitor monitor) throws CoreException { - IClasspathEntry containerEntry = getMavenContainerEntry(JavaCore.create(project)); + IJavaProject javaProject = JavaCore.create(project); + IClasspathEntry containerEntry = getMavenContainerEntry(javaProject); boolean resolveWorkspaceProjects = isResolvingWorkspaceProjects(containerEntry); boolean includeModules = isIncludingModules(containerEntry); @@ -151,9 +168,14 @@ Maven2ClasspathContainer container = new Maven2ClasspathContainer(containerEntry.getPath(), entries); - JavaCore.setClasspathContainer(container.getPath(), new IJavaProject[] {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); @@ -180,7 +202,9 @@ 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: Should be done only once and when bundles are reinstalled + boolean wtpAvailable = isWTPAvailable(); + MavenExecutionResult result = mavenModelManager.readMavenProject(pomFile, monitor, offline, debug, resolveWorkspaceProjects); MavenProject mavenProject = getMavenProject(pomFile, result); if(mavenProject == null) { @@ -217,6 +241,7 @@ } moduleArtifacts.put(artifactLocation, a); + List attributes = new ArrayList(); if(resolveWorkspaceProjects) { mavenModelManager.addProjectArtifact(pomFile, a); // this is needed to projects with have modules (either inner or external) @@ -222,6 +247,14 @@ // 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 + String scope = a.getScope(); + if (Artifact.SCOPE_PROVIDED.equals(scope) + || Artifact.SCOPE_TEST.equals(scope) + || Artifact.SCOPE_SYSTEM.equals(scope)) { + attributes.add(JavaCore.newClasspathAttribute(CLASSPATH_COMPONENT_NON_DEPENDENCY, "")); + } + IFile artifactPomFile = mavenModelManager.getArtifactFile(a); if(artifactPomFile != null) { IProject artifactProject = artifactPomFile.getProject(); @@ -230,6 +263,14 @@ // 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; @@ -238,7 +279,6 @@ Path srcPath = materializeArtifactPath(embedder, mavenProject, a, "java-source", "sources", downloadSources, monitor); - ArrayList attributes = new ArrayList(); attributes.add(JavaCore.newClasspathAttribute(Maven2ClasspathContainer.GROUP_ID_ATTRIBUTE, a.getGroupId())); attributes.add(JavaCore.newClasspathAttribute(Maven2ClasspathContainer.ARTIFACT_ID_ATTRIBUTE, a.getArtifactId())); attributes.add(JavaCore.newClasspathAttribute(Maven2ClasspathContainer.VERSION_ATTRIBUTE, a.getVersion())); @@ -302,7 +342,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); @@ -799,6 +872,100 @@ Maven2Plugin.log(ex); } } + + /** + * Returns the path where this container dependencies will be located at runtime + * (like /WEB-INF/lib for war packaging). + * If the project packaging does not know about deployment, it will be null. + * @param pomFile + * @return the path to the runtime folder, or null. + */ + 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 (hasComponentDependencyAttribute(entry)) { + // 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 + * attribute (org.eclipse.jst.component.dependency) that indicates it should be mapped into the virtual component for the associated project. + * + * @param entry The IClasspathEntry. + * @return true if the classpath entry will be mapped, false if it lacks the attribute. + */ + private static boolean hasComponentDependencyAttribute(final IClasspathEntry entry) { + if (entry == null) { + throw new IllegalArgumentException("Parameter 'entry' can't be 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())) { + // Attribute found + return true; + } + } + // Attribute not found + return false; + } + public static boolean isMaven2ClasspathContainer( IPath containerPath) { return containerPath!=null && containerPath.segmentCount()>0