Java tutorial
/******************************************************************************* * Copyright (c) 2008, 2012 Sonatype, Inc. * 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 *******************************************************************************/ package org.eclipse.m2e.wtp; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.maven.project.MavenProject; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IClasspathAttribute; 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.project.facet.core.JavaFacet; import org.eclipse.jst.common.project.facet.core.internal.JavaFacetUtil; import org.eclipse.jst.j2ee.classpathdep.IClasspathDependencyConstants; import org.eclipse.jst.j2ee.componentcore.J2EEModuleVirtualComponent; import org.eclipse.jst.j2ee.internal.project.J2EEProjectUtilities; import org.eclipse.jst.j2ee.project.JavaEEProjectUtilities; import org.eclipse.jst.j2ee.project.facet.IJ2EEFacetConstants; import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.core.project.MavenProjectUtils; import org.eclipse.m2e.jdt.internal.MavenClasspathHelpers; import org.eclipse.m2e.wtp.overlay.modulecore.IOverlayVirtualComponent; import org.eclipse.wst.common.componentcore.ComponentCore; import org.eclipse.wst.common.componentcore.ModuleCoreNature; import org.eclipse.wst.common.componentcore.internal.ComponentResource; import org.eclipse.wst.common.componentcore.internal.StructureEdit; import org.eclipse.wst.common.componentcore.internal.WorkbenchComponent; import org.eclipse.wst.common.componentcore.internal.impl.ResourceTreeNode; import org.eclipse.wst.common.componentcore.internal.impl.ResourceTreeRoot; import org.eclipse.wst.common.componentcore.internal.util.FacetedProjectUtilities; import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; import org.eclipse.wst.common.componentcore.resources.IVirtualFolder; import org.eclipse.wst.common.componentcore.resources.IVirtualReference; import org.eclipse.wst.common.project.facet.core.IFacetedProject; import org.eclipse.wst.common.project.facet.core.IFacetedProject.Action; import org.eclipse.wst.common.project.facet.core.IProjectFacet; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager; /** * Utility class for WTP projects. * * @provisional This class has been added as part of a work in progress. * It is not guaranteed to work or remain the same in future releases. * For more information contact <a href="mailto:m2e-wtp-dev@eclipse.org">m2e-wtp-dev@eclipse.org</a>. * * @author Fred Bricon */ @SuppressWarnings("restriction") public class WTPProjectsUtil { public static final IProjectFacet UTILITY_FACET = ProjectFacetsManager .getProjectFacet(IJ2EEFacetConstants.UTILITY); public static final IProjectFacetVersion UTILITY_10 = UTILITY_FACET.getVersion("1.0"); public static final IProjectFacet EJB_FACET = ProjectFacetsManager.getProjectFacet(IJ2EEFacetConstants.EJB); public static final IProjectFacet JCA_FACET = ProjectFacetsManager.getProjectFacet(IJ2EEFacetConstants.JCA); public static final IProjectFacet WEB_FRAGMENT_FACET = ProjectFacetsManager .getProjectFacet(IJ2EEFacetConstants.WEBFRAGMENT); public static final IProjectFacetVersion WEB_FRAGMENT_3_0 = WEB_FRAGMENT_FACET.getVersion("3.0"); public static final IProjectFacet DYNAMIC_WEB_FACET = ProjectFacetsManager .getProjectFacet(IJ2EEFacetConstants.DYNAMIC_WEB); public static final IProjectFacet APP_CLIENT_FACET = ProjectFacetsManager .getProjectFacet(IJ2EEFacetConstants.APPLICATION_CLIENT); public static final IClasspathAttribute NONDEPENDENCY_ATTRIBUTE = JavaCore .newClasspathAttribute(IClasspathDependencyConstants.CLASSPATH_COMPONENT_NON_DEPENDENCY, ""); /** * Defaults Web facet version to 2.5 */ public static final IProjectFacetVersion DEFAULT_WEB_FACET = DYNAMIC_WEB_FACET.getVersion("2.5"); public static final IProjectFacet EAR_FACET = ProjectFacetsManager .getProjectFacet(IJ2EEFacetConstants.ENTERPRISE_APPLICATION); public static final String DYN_REQUESTED_REFERENCE_TYPE; static { //Bug #385605 : IVirtualComponent.DISPLAYABLE_REFERENCES_ALL is not available in helios String reqRefType = null; try { Field displayableRefsAllField = IVirtualComponent.class.getField("DISPLAYABLE_REFERENCES_ALL"); reqRefType = (String) displayableRefsAllField.get(null); } catch (Throwable e) { //Falling back on IVirtualComponent.HARD_REFERENCES works in helios wrt bug #385229 : reqRefType = IVirtualComponent.HARD_REFERENCES; } DYN_REQUESTED_REFERENCE_TYPE = reqRefType; } /** * Checks if a project has a given class in its classpath * @param project : the workspace project * @param className : the fully qualified name of the class to search for * @return true if className is found in the project's classpath (provided the project is a JavaProject and its classpath has been set.) */ public static boolean hasInClassPath(IProject project, String className) { boolean result = false; if (project != null) { IJavaProject javaProject = JavaCore.create(project); try { if (javaProject != null && javaProject.findType(className) != null) { result = true; } } catch (JavaModelException ex) { //Ignore this } } return result; } /** * Checks if the project is one of Dynamic Web, EJB, Application client, EAR or JCA project. * @param project - the project to be checked. * @return true if the project is a JEE - or legacy J2EE - project (but not a utility project). */ public static boolean isJavaEEProject(IProject project) { return (J2EEProjectUtilities.isLegacyJ2EEProject(project) || J2EEProjectUtilities.isJEEProject(project)) && !JavaEEProjectUtilities.isUtilityProject(project); } /** * Delete a project's component resources having a given runtimePath * @param project - the project to modify * @param runtimePath - the component resource runtime path (i.e. deploy path) * @param monitor - an eclipse monitor * @throws CoreException */ public static void deleteLinks(IProject project, IPath runtimePath, IProgressMonitor monitor) throws CoreException { deleteLinks(project, runtimePath, null, monitor); } /** * Delete a project's component resources having a given runtimePath * @param project - the project to modify * @param runtimePath - the component resource runtime path (i.e. deploy path) * @param sourcePathToKeep - the list of source paths to keep * @param monitor - an eclipse monitor * @throws CoreException */ public static void deleteLinks(IProject project, IPath runtimePath, List<IPath> sourcePathToKeep, IProgressMonitor monitor) throws CoreException { //Looks like WTP'APIS doesn't have such feature, hence this implementation. StructureEdit moduleCore = null; try { moduleCore = StructureEdit.getStructureEditForWrite(project); if (moduleCore == null) { return; } WorkbenchComponent component = moduleCore.getComponent(); if (component == null) { return; } ResourceTreeRoot root = ResourceTreeRoot.getDeployResourceTreeRoot(component); ComponentResource[] resources = root.findModuleResources(runtimePath, 0); for (ComponentResource link : resources) { if (runtimePath.equals(link.getRuntimePath()) && (sourcePathToKeep == null || !sourcePathToKeep.contains(link.getSourcePath()))) { component.getResources().remove(link); } } } finally { if (moduleCore != null) { moduleCore.saveIfNecessary(monitor); moduleCore.dispose(); } } } public static void insertLinkBefore(IProject project, IPath newSource, IPath referenceSource, IPath runtimePath, IProgressMonitor monitor) throws CoreException { //Looks like WTP'APIS doesn't have such feature, hence this implementation. StructureEdit moduleCore = null; try { moduleCore = StructureEdit.getStructureEditForWrite(project); if (moduleCore == null) { return; } WorkbenchComponent component = moduleCore.getComponent(); if (component == null) { return; } int i = 0; int refPosition = -1; int newSourcePosition = -1; List<ComponentResource> resources = component.getResources(); for (ComponentResource resource : resources) { IPath sourcePath = resource.getSourcePath(); if (referenceSource.equals(sourcePath)) { refPosition = i; } else if (newSource.equals(sourcePath)) { newSourcePosition = i; } if (refPosition > -1 && newSourcePosition > -1) { break; } i++; } if (refPosition < 0) { refPosition = i; } IResource folder = project.getFolder(newSource); if (newSourcePosition > refPosition) { component.getResources().move(newSourcePosition, refPosition); } else if (newSourcePosition < 0) { ComponentResource componentResource = moduleCore.createWorkbenchModuleResource(folder); componentResource.setRuntimePath(runtimePath); component.getResources().add(refPosition, componentResource); } } finally { if (moduleCore != null) { moduleCore.saveIfNecessary(monitor); moduleCore.dispose(); } } } public static void insertLinkFirst(IProject project, IPath newSource, IPath runtimePath, IProgressMonitor monitor) throws CoreException { //Looks like WTP'APIS doesn't have such feature, hence this implementation. StructureEdit moduleCore = null; try { moduleCore = StructureEdit.getStructureEditForWrite(project); if (moduleCore == null) { return; } WorkbenchComponent component = moduleCore.getComponent(); if (component == null) { return; } IResource folder = project.getFolder(newSource); ComponentResource componentResource = moduleCore.createWorkbenchModuleResource(folder); componentResource.setRuntimePath(runtimePath); component.getResources().add(0, componentResource); } finally { if (moduleCore != null) { moduleCore.saveIfNecessary(monitor); moduleCore.dispose(); } } } public static boolean hasLink(IProject project, IPath runtimePath, IPath aProjectRelativeLocation, IProgressMonitor monitor) throws CoreException { StructureEdit moduleCore = null; try { moduleCore = StructureEdit.getStructureEditForRead(project); if (moduleCore != null) { WorkbenchComponent component = moduleCore.getComponent(); if (component != null) { ResourceTreeRoot root = ResourceTreeRoot.getDeployResourceTreeRoot(component); ComponentResource[] resources = root.findModuleResources(runtimePath, ResourceTreeNode.CREATE_NONE); if (resources.length > 0) { for (int resourceIndx = 0; resourceIndx < resources.length; resourceIndx++) { if (aProjectRelativeLocation.makeAbsolute() .equals(resources[resourceIndx].getSourcePath())) { return true; } } } } } } finally { if (moduleCore != null) { moduleCore.dispose(); } } return false; } /** * @param project * @param dir * @return */ public static IPath tryProjectRelativePath(IProject project, String resourceLocation) { if (resourceLocation == null) { return null; } IPath projectLocation = project.getLocation(); IPath directory = Path.fromOSString(resourceLocation); // this is an absolute path! if (projectLocation == null || !projectLocation.isPrefixOf(directory)) { return directory; } return directory.removeFirstSegments(projectLocation.segmentCount()).makeRelative().setDevice(null); } public static boolean hasChanged(IVirtualReference[] existingRefs, IVirtualReference[] refArray) { if (existingRefs == refArray) { return false; } if (existingRefs == null || existingRefs.length != refArray.length) { return true; } for (int i = 0; i < existingRefs.length; i++) { IVirtualReference existingRef = existingRefs[i]; IVirtualReference newRef = refArray[i]; if ((existingRef.getArchiveName() != null && !existingRef.getArchiveName().equals(newRef.getArchiveName())) || (existingRef.getArchiveName() == null && newRef.getArchiveName() != null) || !existingRef.getReferencedComponent().equals(newRef.getReferencedComponent()) || !existingRef.getRuntimePath().equals(newRef.getRuntimePath())) { return true; } } return false; } public static boolean hasChanged2(IVirtualReference[] existingRefs, IVirtualReference[] refArray) { if (existingRefs == refArray) { return false; } if (existingRefs == null || existingRefs.length != refArray.length) { return true; } for (int i = 0; i < existingRefs.length; i++) { IVirtualReference existingRef = existingRefs[i]; IVirtualReference newRef = refArray[i]; if (!existingRef.getReferencedComponent().equals(newRef.getReferencedComponent()) || !existingRef.getRuntimePath().equals(newRef.getRuntimePath())) { return true; } } return false; } public static IVirtualReference[] extractHardReferences(IVirtualComponent warComponent, boolean overlays) { Map<String, Object> options = new HashMap<String, Object>(1); options.put(IVirtualComponent.REQUESTED_REFERENCE_TYPE, DYN_REQUESTED_REFERENCE_TYPE); IVirtualReference[] allReferences = warComponent.getReferences(options); if (allReferences == null || allReferences.length == 0) { return new IVirtualReference[] {}; } List<IVirtualReference> selectedRefs = new ArrayList<IVirtualReference>(); for (IVirtualReference ref : allReferences) { IVirtualComponent component = ref.getReferencedComponent(); if (component != null) { if (component instanceof IOverlayVirtualComponent) { if (overlays) { selectedRefs.add(ref); } } else { if (!overlays) { selectedRefs.add(ref); } } } } IVirtualReference[] selectedReferences = new IVirtualReference[selectedRefs.size()]; selectedRefs.toArray(selectedReferences); return selectedReferences; } /** * Remove the WTP classpath containers that might conflicts with the Maven Library * classpath container * @param project * @throws JavaModelException */ public static void removeWTPClasspathContainer(IProject project) throws JavaModelException { IJavaProject javaProject = JavaCore.create(project); if (javaProject != null) { // remove classpatch container from JavaProject ArrayList<IClasspathEntry> newEntries = new ArrayList<IClasspathEntry>(); for (IClasspathEntry entry : javaProject.getRawClasspath()) { String path = entry.getPath().toString(); if (!"org.eclipse.jst.j2ee.internal.module.container".equals(path) && !"org.eclipse.jst.j2ee.internal.web.container".equals(path)) { newEntries.add(entry); } } javaProject.setRawClasspath(newEntries.toArray(new IClasspathEntry[newEntries.size()]), null); } } /** * Adds uninstall actions of facets from the faceted project that conflict with the given facetVersion. */ public static void removeConflictingFacets(IFacetedProject project, IProjectFacetVersion facetVersion, Set<Action> actions) { if (project == null) { throw new IllegalArgumentException("project can not be null"); } if (facetVersion == null) { throw new IllegalArgumentException("Facet version can not be null"); } if (actions == null) { throw new IllegalArgumentException("actions can not be null"); } for (IProjectFacetVersion existingFacetVersion : project.getProjectFacets()) { if (facetVersion.conflictsWith(existingFacetVersion)) { actions.add(new IFacetedProject.Action(IFacetedProject.Action.Type.UNINSTALL, existingFacetVersion, null)); } } } /** * @param actions * @param project * @param facetedProject */ public static void installJavaFacet(Set<Action> actions, IProject project, IFacetedProject facetedProject) { IProjectFacetVersion javaFv = JavaFacet.FACET.getVersion(JavaFacetUtil.getCompilerLevel(project)); if (!facetedProject.hasProjectFacet(JavaFacet.FACET)) { actions.add(new IFacetedProject.Action(IFacetedProject.Action.Type.INSTALL, javaFv, null)); } else if (!facetedProject.hasProjectFacet(javaFv)) { actions.add(new IFacetedProject.Action(IFacetedProject.Action.Type.VERSION_CHANGE, javaFv, null)); } } /** * @param project * @return */ @SuppressWarnings("restriction") public static boolean hasWebFragmentFacet(IProject project) { return FacetedProjectUtilities.isProjectOfType(project, WTPProjectsUtil.WEB_FRAGMENT_FACET.getId()); } /** * @param mavenProject * @return */ public static boolean isQualifiedAsWebFragment(IMavenProjectFacade facade) { if ("jar".equals(facade.getPackaging())) { IFolder classes = getClassesFolder(facade); if (classes != null && classes.getFile("META-INF/web-fragment.xml").exists()) { return true; } else { //No processed/filtered web-fragment.xml found //fall back : iterate over the resource folders IProject project = facade.getProject(); for (IPath resourceFolderPath : facade.getResourceLocations()) { if (resourceFolderPath != null && project.exists(resourceFolderPath.append("META-INF/web-fragment.xml"))) { return true; } } } } return false; } /** * Return the project's classes folder, a.k.a. output build directory * @param facade * @return the project's classes folder */ public static IFolder getClassesFolder(IMavenProjectFacade facade) { final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IFolder output = root.getFolder(facade.getOutputLocation()); return output; } public static void removeTestFolderLinks(IProject project, MavenProject mavenProject, IProgressMonitor monitor, String folder) throws CoreException { IVirtualComponent component = ComponentCore.createComponent(project); if (component == null) { return; } IVirtualFolder jsrc = component.getRootFolder().getFolder(folder); for (IPath location : MavenProjectUtils.getSourceLocations(project, mavenProject.getTestCompileSourceRoots())) { if (location == null) continue; jsrc.removeLink(location, 0, monitor); } for (IPath location : MavenProjectUtils.getResourceLocations(project, mavenProject.getTestResources())) { if (location == null) continue; jsrc.removeLink(location, 0, monitor); } //MECLIPSEWTP-217 : exclude other test source folders, added by build-helper for instance if (project.hasNature(JavaCore.NATURE_ID)) { IJavaProject javaProject = JavaCore.create(project); if (javaProject == null) { return; } IPath testOutputDirPath = MavenProjectUtils.getProjectRelativePath(project, mavenProject.getBuild().getTestOutputDirectory()); if (testOutputDirPath == null) { return; } IPath testPath = project.getFullPath().append(testOutputDirPath); IClasspathEntry[] cpes = javaProject.getRawClasspath(); IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); for (IClasspathEntry cpe : cpes) { if (cpe != null && cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE) { IPath outputLocation = cpe.getOutputLocation(); if (testPath.equals(outputLocation)) { IPath sourcePath = root.getFolder(cpe.getPath()).getProjectRelativePath(); if (sourcePath != null) { jsrc.removeLink(sourcePath, 0, monitor); } } } } } } public static void setNonDependencyAttributeToContainer(IProject project, IProgressMonitor monitor) throws JavaModelException { updateContainerAttributes(project, NONDEPENDENCY_ATTRIBUTE, IClasspathDependencyConstants.CLASSPATH_COMPONENT_DEPENDENCY, monitor); } public static void updateContainerAttributes(IProject project, IClasspathAttribute attributeToAdd, String attributeToDelete, IProgressMonitor monitor) throws JavaModelException { IJavaProject javaProject = JavaCore.create(project); if (javaProject == null) return; IClasspathEntry[] cp = javaProject.getRawClasspath(); for (int i = 0; i < cp.length; i++) { if (IClasspathEntry.CPE_CONTAINER == cp[i].getEntryKind() && MavenClasspathHelpers.isMaven2ClasspathContainer(cp[i].getPath())) { LinkedHashMap<String, IClasspathAttribute> attrs = new LinkedHashMap<String, IClasspathAttribute>(); for (IClasspathAttribute attr : cp[i].getExtraAttributes()) { if (!attr.getName().equals(attributeToDelete)) { attrs.put(attr.getName(), attr); } } attrs.put(attributeToAdd.getName(), attributeToAdd); IClasspathAttribute[] newAttrs = attrs.values().toArray(new IClasspathAttribute[attrs.size()]); cp[i] = JavaCore.newContainerEntry(cp[i].getPath(), cp[i].getAccessRules(), newAttrs, cp[i].isExported()); break; } } javaProject.setRawClasspath(cp, monitor); } /** * Add the ModuleCoreNature to a project, if necessary. * * @param project An accessible project. * @param monitor A progress monitor to track the time to completion * @throws CoreException if the ModuleCoreNature cannot be added */ public static void fixMissingModuleCoreNature(IProject project, IProgressMonitor monitor) throws CoreException { //MECLIPSEWTP-41 Fix the missing moduleCoreNature if (null == ModuleCoreNature.addModuleCoreNatureIfNecessary(project, monitor)) { //If we can't add the missing nature, then the project is useless, so let's tell the user throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, "Unable to add the ModuleCoreNature to " + project.getName(), null)); } } /** * @return true if the Maven project associated ArtifactHandler's language is java. */ public static boolean isJavaProject(IMavenProjectFacade facade) { //Java rocks ... not if (facade == null || facade.getMavenProject() == null || facade.getMavenProject().getArtifact() == null || facade.getMavenProject().getArtifact().getArtifactHandler() == null) { return false; } String language = facade.getMavenProject().getArtifact().getArtifactHandler().getLanguage(); return "java".equals(language); } /** * Sets the default deployment descriptor folder for Eclipse > Indigo */ public static void setDefaultDeploymentDescriptorFolder(IVirtualFolder folder, IPath aProjectRelativeLocation, IProgressMonitor monitor) { try { Method getDefaultDeploymentDescriptorFolder = J2EEModuleVirtualComponent.class .getMethod("getDefaultDeploymentDescriptorFolder", IVirtualFolder.class); IPath currentDefaultLocation = (IPath) getDefaultDeploymentDescriptorFolder.invoke(null, folder); if (aProjectRelativeLocation.equals(currentDefaultLocation)) { return; } Method setDefaultDeploymentDescriptorFolder = J2EEModuleVirtualComponent.class.getMethod( "setDefaultDeploymentDescriptorFolder", IVirtualFolder.class, IPath.class, IProgressMonitor.class); setDefaultDeploymentDescriptorFolder.invoke(null, folder, aProjectRelativeLocation, monitor); } catch (NoSuchMethodException nsme) { //Not available in this WTP version, let's ignore it } catch (Exception ex) { //The exception shouldn't halt the configuration process. ex.printStackTrace(); } } /** * Gets the default deployment descriptor folder's relative path. * @return An IFolder representing the default folder for deployment descriptor, or null if * the default folder is the root of the project. */ public static IFolder getDefaultDeploymentDescriptorFolder(IVirtualFolder vFolder) { IPath defaultPath = null; try { Method getDefaultDeploymentDescriptorFolder = J2EEModuleVirtualComponent.class .getMethod("getDefaultDeploymentDescriptorFolder", IVirtualFolder.class); defaultPath = (IPath) getDefaultDeploymentDescriptorFolder.invoke(null, vFolder); } catch (NoSuchMethodException nsme) { //Not available in this WTP version, let's ignore it } catch (Exception ex) { //The exception shouldn't halt the configuration process. ex.printStackTrace(); } IFolder folder = null; IVirtualComponent component = vFolder.getComponent(); if (defaultPath == null) { IContainer container = vFolder.getUnderlyingFolder(); if (container instanceof IFolder) folder = (IFolder) container; } else if (!defaultPath.isRoot()) { folder = component.getProject().getFolder(defaultPath); } return folder; } public static boolean isWTPProject(IProject project) { return ModuleCoreNature.getModuleCoreNature(project) != null; } }