[291251] API needed to determine if project has no single root and reasons why
diff --git a/plugins/org.eclipse.jst.j2ee/j2eecreation/org/eclipse/jst/j2ee/internal/project/SingleRootStatus.java b/plugins/org.eclipse.jst.j2ee/j2eecreation/org/eclipse/jst/j2ee/internal/project/SingleRootStatus.java new file mode 100644 index 0000000..52af73c --- /dev/null +++ b/plugins/org.eclipse.jst.j2ee/j2eecreation/org/eclipse/jst/j2ee/internal/project/SingleRootStatus.java
@@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2009 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.project; + +import org.eclipse.core.runtime.Status; +import org.eclipse.jst.j2ee.internal.plugin.J2EEPlugin; +import org.eclipse.jst.j2ee.project.ISingleRootStatus; +import org.eclipse.wst.common.componentcore.internal.ComponentResource; + +public class SingleRootStatus extends Status implements ISingleRootStatus { + + ComponentResource resource; + + public SingleRootStatus(int type, int code, ComponentResource resource, String message, Throwable exception) { + super(type, J2EEPlugin.PLUGIN_ID, code, message, exception); + this.resource = resource; + } + + public SingleRootStatus(int code, ComponentResource resource, String message) { + this(getSeverity(code), code, resource, message, null); + } + + public ComponentResource getComponentResource() { + return resource; + } + + protected static int getSeverity(int code) { + return code == 0 ? 0 : 1 << (code / 33); + } + +}
diff --git a/plugins/org.eclipse.jst.j2ee/j2eecreation/org/eclipse/jst/j2ee/project/ISingleRootStatus.java b/plugins/org.eclipse.jst.j2ee/j2eecreation/org/eclipse/jst/j2ee/project/ISingleRootStatus.java new file mode 100644 index 0000000..912b905 --- /dev/null +++ b/plugins/org.eclipse.jst.j2ee/j2eecreation/org/eclipse/jst/j2ee/project/ISingleRootStatus.java
@@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2009 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.project; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.wst.common.componentcore.internal.ComponentResource; + +public interface ISingleRootStatus extends IStatus { + + // Information Only [0-32] + + // Warnings [33-65] + public static final int SOURCE_PATH_NOT_FOUND = 33; + + // Errors [66-98] + public static final int NO_COMPONENT_FOUND = 67; + + public static final int JAVA_OUTPUT_GREATER_THAN_1 = 68; + + public static final int EAR_PROJECT_FOUND = 69; + + public static final int LINKED_RESOURCES_FOUND = 70; + + public static final int JAVA_OUTPUT_NOT_A_CONTENT_ROOT = 71; + + public static final int JAVA_OUTPUT_NOT_WEBINF_CLASSES = 72; + + public static final int ATLEAST_1_RESOURCE_MAP_MISSING = 73; + + public static final int NO_RESOURCE_MAPS_FOUND = 74; + + public static final int ONE_CONTENT_ROOT_REQUIRED = 75; + + public static final int ATLEAST_1_JAVA_SOURCE_REQUIRED = 76; + + public static final int RUNTIME_PATH_NOT_ROOT = 77; + + public static final int SOURCE_NOT_JAVA_CONTAINER = 78; + + public static final int RUNTIME_PATH_NOT_ROOT_OR_WEBINF_CLASSES = 79; + + public static final int ONLY_1_CONTENT_ROOT_ALLOWED = 80; + + public ComponentResource getComponentResource(); + + +}
diff --git a/plugins/org.eclipse.jst.j2ee/j2eecreation/org/eclipse/jst/j2ee/project/SingleRootUtil.java b/plugins/org.eclipse.jst.j2ee/j2eecreation/org/eclipse/jst/j2ee/project/SingleRootUtil.java new file mode 100644 index 0000000..db6eadd --- /dev/null +++ b/plugins/org.eclipse.jst.j2ee/j2eecreation/org/eclipse/jst/j2ee/project/SingleRootUtil.java
@@ -0,0 +1,484 @@ +/******************************************************************************* + * Copyright (c) 2009 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.project; + +import java.util.Iterator; +import java.util.List; + +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.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jst.j2ee.internal.J2EEConstants; +import org.eclipse.jst.j2ee.internal.plugin.J2EEPlugin; +import org.eclipse.jst.j2ee.internal.project.SingleRootStatus; +import org.eclipse.jst.j2ee.internal.project.J2EEProjectUtilities; +import org.eclipse.wst.common.componentcore.internal.ComponentResource; +import org.eclipse.wst.common.componentcore.internal.Property; +import org.eclipse.wst.common.componentcore.internal.StructureEdit; +import org.eclipse.wst.common.componentcore.internal.WorkbenchComponent; +import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; + +public class SingleRootUtil { + + /** + * Used to return immediately after the first error code is found. + */ + public static final int INCLUDE_FIRST_ERROR = 0x08; + /** + * Used to capture all status codes (error, info, warning). + */ + public static final int INCLUDE_ALL = 0x07; + /** + * Used to capture all error and warning status codes. + */ + public static final int INCLUDE_ERRORS_AND_WARNINGS = 0x06; + /** + * Used to capture all error status codes. + */ + public static final int INCLUDE_ERRORS = 0x04; + + private static final int WARNINGS = 0x02; + private static final int INFO = 0x01; + private static final int NONE = 0x0; + private static String USE_SINGLE_ROOT_PROPERTY = "useSingleRoot"; //$NON-NLS-1$ + private IVirtualComponent component; + private IPackageFragmentRoot[] cachedSourceContainers; + private IContainer[] cachedOutputContainers; + private boolean isSingleJavaOutputNonSource; + private MultiStatus wrapperStatus; + private int INCLUDE_FLAG; + + public SingleRootUtil(IVirtualComponent component) { + this.component = component; + } + + /** + * Returns true if this module has a simple structure based on a + * single root folder, and false otherwise. + * + * In a single root structure, all files that are contained within the root folder + * are part of the module, and are already in the correct module structure. No + * module resources exist outside of this single folder. + * + * @return true if this module has a single root structure, and + * false otherwise + */ + public boolean isSingleRoot() { + return validateSingleRoot(INCLUDE_FIRST_ERROR).getSeverity() != IStatus.ERROR; + } + + /** + * Validates whether the component module has a single root structure. + * An IStatus with a severity of OK is returned for a valid single root + * structure. A MultiStatus containing children of type ISingleRootStatus + * is returned if any status codes were captured during the validation. + * A MultiStatus with a severity of INFO or WARNING is returned for a valid + * single root structure containing status codes with no severities of ERROR. + * A MultiStatus with a severity of ERROR means the component does not have a + * valid single root structure. + * + * @param flag - indicates the status codes (by severity) to capture + * during the validation. + * Valid flags are: INCLUDE_FIRST_ERROR + * INCLUDE_ALL + * INCLUDE_ERRORS_AND_WARNINGS + * INCLUDE_ERRORS + * + * @return IStatus + */ + public IStatus validateSingleRoot(int flag) { + INCLUDE_FLAG = flag; + isSingleJavaOutputNonSource = false; + wrapperStatus = null; + StructureEdit edit = null; + try { + edit = StructureEdit.getStructureEditForRead(getProject()); + if (edit == null || edit.getComponent() == null) { + reportStatus(ISingleRootStatus.NO_COMPONENT_FOUND); + return getStatus(); + } + + WorkbenchComponent wbComp = edit.getComponent(); + List resourceMaps = wbComp.getResources(); + + // 229650 - check to see if the property 'useSingleRoot' is defined. If it is set and + // the value of the property is true then it will override the logic checks below + final List componentProperties = wbComp.getProperties(); + if (componentProperties != null) { + final Iterator componentPropertiesIterator = componentProperties.iterator(); + while (componentPropertiesIterator.hasNext()) { + Property wbProperty = (Property) componentPropertiesIterator.next(); + if (USE_SINGLE_ROOT_PROPERTY.equals(wbProperty.getName())) { + boolean useSingleRoot = Boolean.valueOf(wbProperty.getValue()).booleanValue(); + if (useSingleRoot) { + return Status.OK_STATUS; + } + } + } + } + + if (JavaEEProjectUtilities.isEARProject(getProject())) { + // Always return false for EARs so that members for EAR are always calculated and j2ee modules are filtered out + reportStatus(ISingleRootStatus.EAR_PROJECT_FOUND); + } else if (JavaEEProjectUtilities.isDynamicWebProject(getProject())) { + //validate web projects for single root + validateWebProject(resourceMaps); + } + else if (JavaEEProjectUtilities.isEJBProject(getProject()) || JavaEEProjectUtilities.isJCAProject(getProject()) + || JavaEEProjectUtilities.isApplicationClientProject(getProject()) || JavaEEProjectUtilities.isUtilityProject(getProject())) { + + validateProject(resourceMaps); + } + //return the current status + return getStatus(); + } finally { + cachedOutputContainers = null; + cachedSourceContainers = null; + if (edit != null) + edit.dispose(); + } + } + + private void validateProject(List resourceMaps) { + // if there are any linked resources then this is not a singleroot module + if (this.rootFoldersHaveLinkedContent()) { + reportStatus(ISingleRootStatus.LINKED_RESOURCES_FOUND); + if (INCLUDE_FLAG == NONE) return; + } + + // Ensure there are only source folder component resource mappings to the root content folder + if (isRootResourceMapping(resourceMaps)) { + IContainer[] javaOutputFolders = getJavaOutputFolders(); + // Verify only one java outputfolder + if (javaOutputFolders.length==1) { + // By the time we get here we know: for any folders defined as source in the + // .component file that they are also java source folders. + if (JavaEEProjectUtilities.isUtilityProject(getProject()) || + JavaEEProjectUtilities.isEJBProject(getProject()) || + JavaEEProjectUtilities.isApplicationClientProject(getProject())) { + + if (!isSourceContainer(javaOutputFolders[0].getFullPath())) { + // The single output folder is NOT a source folder so this is single-rooted. Since the + // output folder (something like classes or bin) is not a source folder, JDT copies all files + // (including non Java files) to this folder, so every resource needed at runtime is located + // in a single directory. + isSingleJavaOutputNonSource = true; + return; + } + } + // Verify the java output folder is the same as one of the content roots + IPath javaOutputPath = getJavaOutputFolders()[0].getProjectRelativePath(); + IContainer[] rootFolders = component.getRootFolder().getUnderlyingFolders(); + for (int i=0; i<rootFolders.length; i++) { + IPath compRootPath = rootFolders[i].getProjectRelativePath(); + if (javaOutputPath.equals(compRootPath)) + return; + } + reportStatus(ISingleRootStatus.JAVA_OUTPUT_NOT_A_CONTENT_ROOT); + } + else { + reportStatus(ISingleRootStatus.JAVA_OUTPUT_GREATER_THAN_1); + } + } + } + + private void validateWebProject(List resourceMaps) { + // if there are any linked resources then this is not a singleroot module + if (this.rootFoldersHaveLinkedContent()) { + reportStatus(ISingleRootStatus.LINKED_RESOURCES_FOUND); + if (INCLUDE_FLAG == NONE) return; + } + + // Ensure there are only basic component resource mappings -- one for the content folder + // and any for src folders mapped to WEB-INF/classes + if (hasDefaultWebResourceMappings(resourceMaps)) { + // Verify only one java output folder + if (getJavaOutputFolders().length==1) { + // Verify the java output folder is to <content root>/WEB-INF/classes + IPath javaOutputPath = getJavaOutputFolders()[0].getProjectRelativePath(); + IPath compRootPath = component.getRootFolder().getUnderlyingFolder().getProjectRelativePath(); + if (compRootPath.append(J2EEConstants.WEB_INF_CLASSES).equals(javaOutputPath)) { + return; + } + else { + reportStatus(ISingleRootStatus.JAVA_OUTPUT_NOT_WEBINF_CLASSES); + } + } + else { + reportStatus(ISingleRootStatus.JAVA_OUTPUT_GREATER_THAN_1); + } + } + } + + /** + * Returns the root folders containing Java output in this module. + * + * @return a possibly-empty array of Java output folders + */ + public IContainer[] getJavaOutputFolders() { + if (cachedOutputContainers == null) + cachedOutputContainers = getJavaOutputFolders(getProject()); + return cachedOutputContainers; + } + + public IContainer[] getJavaOutputFolders(IProject project) { + if (project == null) + return new IContainer[0]; + return J2EEProjectUtilities.getOutputContainers(project); + } + + /** + * Checks if the path argument is to a source container for the project. + * + * @param a workspace relative full path + * @return is path a source container? + */ + private boolean isSourceContainer(IPath path) { + IPackageFragmentRoot[] srcContainers = getSourceContainers(); + for (int i = 0; i < srcContainers.length; i++) { + if (srcContainers[i].getPath().equals(path)) + return true; + } + return false; + } + + private IPackageFragmentRoot[] getSourceContainers() { + if (cachedSourceContainers == null) + cachedSourceContainers = J2EEProjectUtilities.getSourceContainers(getProject()); + return cachedSourceContainers; + } + + /* + * This method returns true if the root folders of this component have any linked resources (folder or file); + * Otherwise false is returned. + */ + private boolean rootFoldersHaveLinkedContent() { + if (this.component != null) { + final IContainer[] rootFolders = this.component.getRootFolder().getUnderlyingFolders(); + for (int i = 0; i < rootFolders.length; i++) { + try { + boolean hasLinkedContent = this.hasLinkedContent(rootFolders[i]); + if (hasLinkedContent) { + return true; + } + } + catch (CoreException coreEx) { + J2EEPlugin.logError(coreEx); + } + } + } + return false; + } + + /* + * If the resource to check is a file then this method will return true if the file is linked. If the resource to + * check is a folder then this method will return true if it, any of its sub directories, or any file contained + * with-in this directory of any of it's sub directories are linked. Otherwise false is returned. + */ + private boolean hasLinkedContent(final IResource resourceToCheck) throws CoreException { + if ((resourceToCheck != null) && resourceToCheck.isAccessible()) { + // skip non-accessible files + if (resourceToCheck.isLinked()) { + return true; + } + else { + switch (resourceToCheck.getType()) { + case IResource.FOLDER: + // recursively check sub directory contents + final IResource[] subDirContents = ((IFolder) resourceToCheck).members(); + for (int i = 0; i < subDirContents.length; i++) { + if (hasLinkedContent(subDirContents[i])) { + return true; + } + } + break; + case IResource.FILE: + return resourceToCheck.isLinked(); + default: + // skip as we only care about files and folders + break; + } + } + } + return false; + } + + /** + * Ensure that any component resource mappings are for source folders and + * that they map to the root content folder + * + * @param resourceMaps + * @return boolean + */ + private boolean isRootResourceMapping(List resourceMaps) { + // If the list is empty, return false + if (resourceMaps.size() < 1) { + reportStatus(ISingleRootStatus.NO_RESOURCE_MAPS_FOUND); + return false; + } + + for (int i=0; i < resourceMaps.size(); i++) { + ComponentResource resourceMap = (ComponentResource) resourceMaps.get(i); + // Verify it maps to "/" for the content root + if (!resourceMap.getRuntimePath().equals(Path.ROOT)) { + reportStatus(ISingleRootStatus.RUNTIME_PATH_NOT_ROOT, resourceMap); + if (INCLUDE_FLAG == NONE) return false; + } + + // verify it is also a src container + IResource sourceResource = getProject().findMember(resourceMap.getSourcePath()); + if (sourceResource != null && sourceResource.exists()){ + IPath sourcePath = getProject().getFullPath().append(resourceMap.getSourcePath()); + if (!isSourceContainer(sourcePath)) + reportStatus(ISingleRootStatus.SOURCE_NOT_JAVA_CONTAINER, resourceMap); + } + else { + reportStatus(ISingleRootStatus.SOURCE_PATH_NOT_FOUND, resourceMap); + } + if (INCLUDE_FLAG == NONE) return false; + } + return true; + } + + /** + * Ensure the default web setup is correct with one resource map and any number of java + * resource maps to WEB-INF/classes + * + * @param resourceMaps + * @return boolean + */ + private boolean hasDefaultWebResourceMappings(List resourceMaps) { + int rootValidMaps = 0; + int javaValidRoots = 0; + + // If there aren't at least 2 maps, return false + if (INCLUDE_FLAG == INCLUDE_FIRST_ERROR && resourceMaps.size() < 2) { + reportStatus(ISingleRootStatus.ATLEAST_1_RESOURCE_MAP_MISSING); + return false; + } + + IPath webInfClasses = new Path(J2EEConstants.WEB_INF_CLASSES).makeAbsolute(); + for (int i = 0; i < resourceMaps.size(); i++) { + ComponentResource resourceMap = (ComponentResource) resourceMaps.get(i); + IPath sourcePath = getProject().getFullPath().append(resourceMap.getSourcePath()); + + // Verify if the map is for the content root + if (resourceMap.getRuntimePath().equals(Path.ROOT)) { + rootValidMaps++; + } + // Verify if the map is for a java src folder and is mapped to "WEB-INF/classes" + else if (resourceMap.getRuntimePath().equals(webInfClasses)) { + if (exists(sourcePath)) { + if (isSourceContainer(sourcePath)) { + javaValidRoots++; + } + else { + reportStatus(ISingleRootStatus.SOURCE_NOT_JAVA_CONTAINER, resourceMap); + } + } + else { + reportStatus(ISingleRootStatus.SOURCE_PATH_NOT_FOUND, resourceMap); + } + } + else { + reportStatus(ISingleRootStatus.RUNTIME_PATH_NOT_ROOT_OR_WEBINF_CLASSES, resourceMap); + } + if (INCLUDE_FLAG == NONE) return false; + } + // Make sure only one of the maps is the content root, and that at least one is for the java folder + if (rootValidMaps != 1) { + if (rootValidMaps < 1) { + reportStatus(ISingleRootStatus.ONE_CONTENT_ROOT_REQUIRED); + } + else if (rootValidMaps > 1) { + reportStatus(ISingleRootStatus.ONLY_1_CONTENT_ROOT_ALLOWED); + } + if (INCLUDE_FLAG == NONE) return false; + } + if (javaValidRoots < 1) { + reportStatus(ISingleRootStatus.ATLEAST_1_JAVA_SOURCE_REQUIRED); + } + return INCLUDE_FLAG == NONE ? false : true; + } + + /** + * Checks if the path argument exists relative to this workspace root. + * + * @param a workspace relative full path + * @return is path in the workspace? + */ + private boolean exists(IPath path) { + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + return workspaceRoot.exists(path); + } + + private IProject getProject() { + return component.getProject(); + } + + public boolean isSingleJavaOutputNonSource() { + return isSingleJavaOutputNonSource; + } + + public void reportStatus(int code) { + reportStatus(code, null, null); + } + + public void reportStatus(int code, ComponentResource resource) { + reportStatus(code, resource, null); + } + + public void reportStatus(int code, ComponentResource resource, String message) { + ISingleRootStatus status = new SingleRootStatus(code, resource, message); + if (status.getSeverity() == IStatus.ERROR) { + if ((INCLUDE_FLAG & INCLUDE_FIRST_ERROR) != 0) { + INCLUDE_FLAG = NONE; + addStatus(status); + } + else if ((INCLUDE_FLAG & INCLUDE_ERRORS) != 0) { + addStatus(status); + } + } + else if (status.getSeverity() == IStatus.WARNING && (INCLUDE_FLAG & WARNINGS) != 0) { + addStatus(status); + } + else if (status.getSeverity() == IStatus.INFO && (INCLUDE_FLAG & INFO) != 0) { + addStatus(status); + } + } + + public IStatus getStatus() { + if (wrapperStatus != null) { + return wrapperStatus; + } + return Status.OK_STATUS; + } + + private void addStatus(ISingleRootStatus status) { + if (wrapperStatus == null) { + wrapperStatus = new MultiStatus(J2EEPlugin.PLUGIN_ID, 0, new IStatus[] { status }, null, null); + } + else { + wrapperStatus.add(status); + } + } + +}
diff --git a/plugins/org.eclipse.jst.j2ee/j2eeplugin/org/eclipse/jst/j2ee/internal/deployables/J2EEFlexProjDeployable.java b/plugins/org.eclipse.jst.j2ee/j2eeplugin/org/eclipse/jst/j2ee/internal/deployables/J2EEFlexProjDeployable.java index a0d2b97..8ed0641 100644 --- a/plugins/org.eclipse.jst.j2ee/j2eeplugin/org/eclipse/jst/j2ee/internal/deployables/J2EEFlexProjDeployable.java +++ b/plugins/org.eclipse.jst.j2ee/j2eeplugin/org/eclipse/jst/j2ee/internal/deployables/J2EEFlexProjDeployable.java
@@ -17,17 +17,13 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Set; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; -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; @@ -51,7 +47,7 @@ import org.eclipse.jst.j2ee.internal.plugin.IJ2EEModuleConstants; import org.eclipse.jst.j2ee.internal.plugin.J2EEPlugin; import org.eclipse.jst.j2ee.internal.project.J2EEProjectUtilities; -import org.eclipse.jst.j2ee.project.JavaEEProjectUtilities; +import org.eclipse.jst.j2ee.project.SingleRootUtil; import org.eclipse.jst.jee.util.internal.JavaEEQuickPeek; import org.eclipse.jst.server.core.IApplicationClientModule; import org.eclipse.jst.server.core.IConnectorModule; @@ -61,10 +57,6 @@ import org.eclipse.jst.server.core.IWebModule; import org.eclipse.wst.common.componentcore.ArtifactEdit; import org.eclipse.wst.common.componentcore.ComponentCore; -import org.eclipse.wst.common.componentcore.internal.ComponentResource; -import org.eclipse.wst.common.componentcore.internal.Property; -import org.eclipse.wst.common.componentcore.internal.StructureEdit; -import org.eclipse.wst.common.componentcore.internal.WorkbenchComponent; import org.eclipse.wst.common.componentcore.internal.resources.VirtualArchiveComponent; import org.eclipse.wst.common.componentcore.internal.util.ComponentUtilities; import org.eclipse.wst.common.componentcore.internal.util.IModuleConstants; @@ -86,13 +78,13 @@ protected static final IPath WEB_CLASSES_PATH = new Path(J2EEConstants.WEB_INF_CLASSES); protected static final IPath MANIFEST_PATH = new Path(J2EEConstants.MANIFEST_URI); protected static IPath WEBLIB = new Path(J2EEConstants.WEB_INF_LIB).makeAbsolute(); - private static String USE_SINGLE_ROOT_PROPERTY = "useSingleRoot"; //$NON-NLS-1$ protected IPackageFragmentRoot[] cachedSourceContainers; protected IContainer[] cachedOutputContainers; protected HashMap cachedOutputMappings; protected HashMap cachedSourceOutputPairs; protected List classpathComponentDependencyURIs = new ArrayList(); private boolean isSingleJavaOutputNonSource = false; + private SingleRootUtil singleUtil; /** * Constructor for J2EEFlexProjDeployable. @@ -829,62 +821,9 @@ } } - /* - * If the resource to check is a file then this method will return true if the file is linked. If the resource to - * check is a folder then this method will return true if it, any of its sub directories, or any file contained - * with-in this directory of any of it's sub directories are linked. Otherwise false is returned. - */ - private boolean hasLinkedContent(final IResource resourceToCheck) throws CoreException { + - if ((resourceToCheck != null) && resourceToCheck.isAccessible()) { - // skip non-accessible files - if (resourceToCheck.isLinked()) { - return true; - } - else { - switch (resourceToCheck.getType()) { - case IResource.FOLDER: - // recursively check sub directory contents - final IResource[] subDirContents = ((IFolder) resourceToCheck).members(); - for (int i = 0; i < subDirContents.length; i++) { - if (hasLinkedContent(subDirContents[i])) { - return true; - } - } - break; - case IResource.FILE: - return resourceToCheck.isLinked(); - default: - // skip as we only care about files and folders - break; - } - } - } - return false; - } - - /* - * This method returns true if the root folders of this component have any linked resources (folder or file); - * Otherwise false is returned. - */ - private boolean rootFoldersHaveLinkedContent() { - - if (this.component != null) { - final IContainer[] rootFolders = this.component.getRootFolder().getUnderlyingFolders(); - for (int i = 0; i < rootFolders.length; i++) { - try { - boolean hasLinkedContent = this.hasLinkedContent(rootFolders[i]); - if (hasLinkedContent) { - return true; - } - } - catch (CoreException coreEx) { - J2EEPlugin.logError(coreEx); - } - } - } - return false; - } + /** * Returns <code>true</code> if this module has a simple structure based on a @@ -903,207 +842,20 @@ * <code>false</code> otherwise */ public boolean isSingleRootStructure() { - isSingleJavaOutputNonSource = false; - StructureEdit edit = null; - try { - edit = StructureEdit.getStructureEditForRead(getProject()); - if (edit == null || edit.getComponent() == null) - return false; - WorkbenchComponent wbComp = edit.getComponent(); - List resourceMaps = wbComp.getResources(); - - // 229650 - check to see if the property 'useSingleRoot' is defined. If it is set and - // the value of the property is true then it will override the logic checks below - final List componentProperties = wbComp.getProperties(); - if (componentProperties != null) { - final Iterator componentPropertiesIterator = componentProperties.iterator(); - while (componentPropertiesIterator.hasNext()) { - Property wbProperty = (Property) componentPropertiesIterator.next(); - if (J2EEFlexProjDeployable.USE_SINGLE_ROOT_PROPERTY.equals(wbProperty.getName())) { - boolean useSingleRoot = Boolean.valueOf(wbProperty.getValue()).booleanValue(); - if (useSingleRoot) { - return true; - } - } - } - } - - if (J2EEProjectUtilities.isEARProject(getProject())) { - // Always return false for EARs so that members for EAR are always calculated and j2ee modules - // are filtered out - return false; - } else if (J2EEProjectUtilities.isDynamicWebProject(getProject())) { - // if there are any linked resources then this is not a singleroot module - if (this.rootFoldersHaveLinkedContent()) { - return false; - } - // Ensure there are only basic component resource mappings -- one for the content folder - // and any for src folders mapped to WEB-INF/classes - if (hasDefaultWebResourceMappings(resourceMaps)) { - // Verify only one java output folder - if (getJavaOutputFolders().length==1) { - // Verify the java output folder is to <content root>/WEB-INF/classes - IPath javaOutputPath = getJavaOutputFolders()[0].getProjectRelativePath(); - IPath compRootPath = component.getRootFolder().getUnderlyingFolder().getProjectRelativePath(); - if (compRootPath.append(J2EEConstants.WEB_INF_CLASSES).equals(javaOutputPath)) - return true; - } - } - return false; - } else if (JavaEEProjectUtilities.isEJBProject(getProject()) || JavaEEProjectUtilities.isJCAProject(getProject()) - || JavaEEProjectUtilities.isApplicationClientProject(getProject()) || JavaEEProjectUtilities.isUtilityProject(getProject())) { - // if there are any linked resources then this is not a singleroot module - if (this.rootFoldersHaveLinkedContent()) { - return false; - } - // Ensure there are only source folder component resource mappings to the root content folder - if (isRootResourceMapping(resourceMaps,false)) { - IContainer[] javaOutputFolders = getJavaOutputFolders(); - // Verify only one java outputfolder - if (javaOutputFolders.length==1) { - // By the time we get here we know: for any folders defined as source in the - // .component file that they are also java source folders. - if (JavaEEProjectUtilities.isUtilityProject(getProject()) || - JavaEEProjectUtilities.isEJBProject(getProject()) || - JavaEEProjectUtilities.isApplicationClientProject(getProject())) { - if (! isSourceContainer(javaOutputFolders[0].getFullPath())) { - // The single output folder is NOT a source folder so this is single-rooted. Since the - // output folder (something like classes or bin) is not a source folder, JDT copies all files - // (including non Java files) to this folder, so every resource needed at runtime is located - // in a single directory. - isSingleJavaOutputNonSource = true; - return true; - } else { -// Don't implement at this time. Currently, we claim single-rooted when ejbModlule is the output folder. However, -// we know this is not true because it cannot contain non Java files unless it is the only source folder. But, fixing -// at this time would break all current users. -// // The single output folder IS a source folder. If there is more than one source folder -// // then this cannot be single-rooted because JDT does NOTcopy non Java resources into the -// // output folder when it is a source folder. -// if (getSourceContainers().length > 1) { -// return false; -// } else { -// // There is only one source folder and since the output folder is a source folder -// // this is single-rooted. -// return true; -// } - } - } -// // At this point for utility projects, this project is optimized, we can just use the output folder -// if (J2EEProjectUtilities.isUtilityProject(getProject())) -// return true; - // Verify the java output folder is the same as one of the content roots - IPath javaOutputPath = getJavaOutputFolders()[0].getProjectRelativePath(); - IContainer[] rootFolders = component.getRootFolder().getUnderlyingFolders(); - for (int i=0; i<rootFolders.length; i++) { - IPath compRootPath = rootFolders[i].getProjectRelativePath(); - if (javaOutputPath.equals(compRootPath)) - return true; - } - } - } - return false; - } - return true; - } finally { - if (edit !=null) - edit.dispose(); - } + boolean isSingleRoot = getSingleUtil().isSingleRoot(); + isSingleJavaOutputNonSource = getSingleUtil().isSingleJavaOutputNonSource(); + return isSingleRoot; } - /** - * Ensure that any component resource mappings are for source folders and - * that they map to the root content folder - * - * @param resourceMaps - * @return boolean - */ - private boolean isRootResourceMapping(List resourceMaps, boolean isForEAR) { - // If the list is empty, return false - if (resourceMaps.size()<1) - return false; - - for (int i=0; i<resourceMaps.size(); i++) { - ComponentResource resourceMap = (ComponentResource) resourceMaps.get(i); - // Verify it maps to "/" for the content root - if (!resourceMap.getRuntimePath().equals(Path.ROOT)) - return false; - // If this is not for an EAR, verify it is also a src container - if (!isForEAR) { - IResource sourceResource = getProject().findMember(resourceMap.getSourcePath()); - if(sourceResource != null && sourceResource.exists()){ - IPath sourcePath = getProject().getFullPath().append(resourceMap.getSourcePath()); - if (!isSourceContainer(sourcePath)) - return false; - } - } + private SingleRootUtil getSingleUtil() { + if (singleUtil == null) { + singleUtil = new SingleRootUtil(component); } - return true; - } - - /** - * Checks if the path argument is to a source container for the project. - * - * @param a workspace relative full path - * @return is path a source container? - */ - private boolean isSourceContainer(IPath path) { - IPackageFragmentRoot[] srcContainers = getSourceContainers(); - for (int i=0; i<srcContainers.length; i++) { - if (srcContainers[i].getPath().equals(path)) - return true; - } - return false; + return singleUtil; } - /** - * Checks if the path argument exists relative to this workspace root. - * - * @param a workspace relative full path - * @return is path in the workspace? - */ - private boolean exists(IPath path) { - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - return workspaceRoot.exists(path); - } /** - * Ensure the default web setup is correct with one resource map and any number of java - * resource maps to WEB-INF/classes - * - * @param resourceMaps - * @return boolean - */ - private boolean hasDefaultWebResourceMappings(List resourceMaps) { - int rootValidMaps = 0; - int javaValidRoots = 0; - - // If there aren't at least 2 maps, return false - if (resourceMaps.size()<2) - return false; - - IPath webInfClasses = new Path(J2EEConstants.WEB_INF_CLASSES).makeAbsolute(); - for (int i=0; i<resourceMaps.size(); i++) { - ComponentResource resourceMap = (ComponentResource) resourceMaps.get(i); - IPath sourcePath = getProject().getFullPath().append(resourceMap.getSourcePath()); - - // Verify if the map is for the content root - if (resourceMap.getRuntimePath().equals(Path.ROOT)) { - rootValidMaps++; - // Verify if the map is for a java src folder and is mapped to "WEB-INF/classes" - } else if (resourceMap.getRuntimePath().equals(webInfClasses) && isSourceContainer(sourcePath)) { - javaValidRoots++; - // Otherwise we bail because we have a non optimized map - // Except if the source path is to a nonexistent resource then just ignore the map and keep trying - } else if (exists(sourcePath)) { - return false; - } - } - // Make sure only one of the maps is the content root, and that at least one is for the java folder - return rootValidMaps==1 && javaValidRoots>0; - } - - /** * This method is added for performance reasons. It can ONLY be called when the project is single root. * @see isSingleRootStructure(). If the project has an output folder that is also a source folder then, * it assumes the virtual component is not using any flexible features and is in a standard J2EE format @@ -1115,7 +867,7 @@ */ private IModuleResource[] getOptimizedMembers() throws CoreException { if (component != null) { - if (isSingleJavaOutputNonSource) { + if (isSingleJavaOutputNonSource ) { // We determined when testing for a single root structure that this project has // one output folder and that output folder is not a source folder. Since the // output folder (for example, classes or bin) is not a source folder, JDT copies all files