| /******************************************************************************* |
| * Copyright (c) 2009, 2012 Red Hat 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: |
| * Red Hat - Initial API and implementation |
| * Roberto Sanchez Herrera - [371907] Do not always treat EARs as non single root |
| *******************************************************************************/ |
| package org.eclipse.jst.j2ee.internal.common.exportmodel; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.jst.common.internal.modulecore.AddClasspathFoldersParticipant; |
| import org.eclipse.jst.common.internal.modulecore.AddClasspathLibReferencesParticipant; |
| import org.eclipse.jst.common.internal.modulecore.AddClasspathLibRefsProviderParticipant; |
| import org.eclipse.jst.common.internal.modulecore.ISingleRootStatus; |
| import org.eclipse.jst.common.internal.modulecore.ReplaceManifestExportParticipant; |
| import org.eclipse.jst.common.internal.modulecore.SingleRootUtil; |
| import org.eclipse.jst.common.internal.modulecore.SingleRootExportParticipant.SingleRootParticipantCallback; |
| import org.eclipse.jst.j2ee.internal.J2EEConstants; |
| import org.eclipse.jst.j2ee.internal.classpathdep.ClasspathDependencyEnablement; |
| import org.eclipse.jst.j2ee.project.JavaEEProjectUtilities; |
| import org.eclipse.wst.common.componentcore.internal.ComponentResource; |
| import org.eclipse.wst.common.componentcore.internal.flat.FilterResourceParticipant; |
| import org.eclipse.wst.common.componentcore.internal.flat.IFlattenParticipant; |
| import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; |
| |
| public class JavaEESingleRootCallback implements SingleRootParticipantCallback { |
| //Warnings |
| public static final int UNNECESSARY_RESOURCE_MAP = 100; |
| |
| //Errors |
| public static final int EAR_PROJECT_FOUND = 10100; |
| public static final int ATLEAST_1_RESOURCE_MAP_MISSING = 10101; |
| public static final int JAVA_OUTPUT_NOT_WEBINF_CLASSES = 10102; |
| public static final int RUNTIME_PATH_NOT_ROOT_OR_WEBINF_CLASSES = 10103; |
| public static final int ONLY_1_CONTENT_ROOT_ALLOWED = 10104; |
| public static final int ONE_CONTENT_ROOT_REQUIRED = 10105; |
| public static final int ATLEAST_1_JAVA_SOURCE_REQUIRED = 10106; |
| public static final int CLASSPATH_DEPENDENCIES_FOUND = 10107; |
| public static final int SOURCE_PATH_OUTSIDE_CONTENT_ROOT = 10108; |
| |
| private static final int CANCEL = 0x0; |
| private String[] filteredSuffixes = new String[]{}; |
| public JavaEESingleRootCallback() { |
| // intentionally blank |
| } |
| |
| public JavaEESingleRootCallback(String[] filtered) { |
| this.filteredSuffixes = filtered; |
| } |
| |
| public void setFilteredSuffixes(String[] filtered) { |
| this.filteredSuffixes = filtered; |
| } |
| |
| public boolean canValidate(IVirtualComponent vc) { |
| return JavaEEProjectUtilities.usesJavaEEComponent(vc); |
| } |
| |
| public void validate(SingleRootUtil util, IVirtualComponent vc, IProject project, List resourceMaps) { |
| |
| if (resourceMaps.size() == 1) { |
| ComponentResource mapping = (ComponentResource)resourceMaps.get(0); |
| if (util.isRootMapping(mapping)) { |
| IResource sourceResource = project.findMember(mapping.getSourcePath()); |
| if (sourceResource != null && sourceResource.exists()) { |
| if (sourceResource instanceof IContainer && !util.isSourceContainer((IContainer) sourceResource)) { |
| util.reportStatus(ISingleRootStatus.SINGLE_ROOT_CONTAINER_FOUND, (IContainer) sourceResource); |
| util.setValidateFlag(CANCEL); |
| return; |
| } |
| } |
| } |
| } |
| |
| if (JavaEEProjectUtilities.isEARProject(project)) { |
| validateEARProject(util, vc, resourceMaps); |
| util.setValidateFlag(CANCEL); |
| return; |
| } |
| |
| //validate web projects for single root |
| if (JavaEEProjectUtilities.isDynamicWebProject(project)) { |
| validateWebProject(util, vc, resourceMaps); |
| util.setValidateFlag(CANCEL); |
| } |
| |
| } |
| |
| |
| private void validateEARProject(SingleRootUtil util, IVirtualComponent vc, List resourceMaps) { |
| /* |
| * If we are here, we know we have more than one resource mapping, so let's check if the EAR is single root. |
| * The algorithm is the following: |
| * Go through all the mappings, |
| * If we find more than one mapping to root, then this EAR is not single root. |
| * If we find only one mapping to root, |
| * Check if the other mappings' source path is part of the source path of the mapping to root. |
| * If at least one mapping has a source path that is not in the mapping to root, then the EAR is not single root. |
| * else, report the only mapping found as the root container. |
| */ |
| |
| List<ComponentResource> rootMappings = new ArrayList<ComponentResource>(); |
| List<ComponentResource> nonRootMappings = new ArrayList<ComponentResource>(); |
| for (int i = 0; i < resourceMaps.size(); i++) { |
| ComponentResource resourceMap = (ComponentResource) resourceMaps.get(i); |
| // Verify if the map is for the content root |
| if (util.isRootMapping(resourceMap)) { |
| rootMappings.add(resourceMap); |
| } |
| else { |
| nonRootMappings.add(resourceMap); |
| } |
| } |
| |
| if (rootMappings.size() > 1){ |
| util.reportStatus(ONLY_1_CONTENT_ROOT_ALLOWED); |
| return; |
| } |
| if (rootMappings.size() < 1) |
| { |
| util.reportStatus(ONE_CONTENT_ROOT_REQUIRED); |
| return; |
| } |
| |
| // We have one mapping to root. Let's check if there are other mappings |
| |
| ComponentResource rootMapping = rootMappings.get(0); |
| boolean reportNonSingleRoot = false; |
| for (ComponentResource otherMapping:nonRootMappings){ |
| IPath otherMappingSourcePath = otherMapping.getSourcePath(); |
| if (!rootMapping.getSourcePath().isPrefixOf(otherMappingSourcePath)){ |
| reportNonSingleRoot = true; |
| break; |
| } |
| } |
| if (reportNonSingleRoot){ |
| util.reportStatus(SOURCE_PATH_OUTSIDE_CONTENT_ROOT); |
| return; |
| } |
| // At this moment, we know there is only one mapping to root (and possibly one or more |
| // other mappings that do not break the single root condition of the project), so let's see |
| // if we can find the root container |
| IResource sourceResource = util.getProject().findMember(rootMappings.get(0).getSourcePath()); |
| if (sourceResource != null && sourceResource.exists()) { |
| if (sourceResource instanceof IContainer && !util.isSourceContainer((IContainer) sourceResource)) { |
| util.reportStatus(ISingleRootStatus.SINGLE_ROOT_CONTAINER_FOUND, (IContainer) sourceResource); |
| return; |
| } |
| } |
| // If we get here, it means that we have only one mapping to root (and possibly one or more |
| // other mappings that do not break the single root condition of the project), but the container for |
| // the root mapping was not found. |
| } |
| |
| |
| private void validateWebProject(SingleRootUtil util, IVirtualComponent vc, List resourceMaps) { |
| // 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(util, resourceMaps)) { |
| IContainer[] javaOutputFolders = util.getJavaOutputFolders(); |
| // Verify only one java output folder |
| if (javaOutputFolders.length == 1) { |
| // Verify the java output folder is to <content root>/WEB-INF/classes |
| IPath javaOutputPath = util.getJavaOutputFolders()[0].getProjectRelativePath(); |
| IContainer rootContainer = vc.getRootFolder().getUnderlyingFolder(); |
| IPath compRootPath = rootContainer.getProjectRelativePath(); |
| if (compRootPath.append(J2EEConstants.WEB_INF_CLASSES).equals(javaOutputPath)) { |
| util.reportStatus(ISingleRootStatus.SINGLE_ROOT_CONTAINER_FOUND, rootContainer); |
| return; |
| } |
| util.reportStatus(JAVA_OUTPUT_NOT_WEBINF_CLASSES); |
| } |
| else { |
| util.reportStatus(ISingleRootStatus.JAVA_OUTPUT_GREATER_THAN_1); |
| } |
| } |
| } |
| |
| /** |
| * 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(SingleRootUtil util, List resourceMaps) { |
| int rootValidMaps = 0; |
| IPath pathMappedToContentRoot = null; |
| List<ComponentResource> tmpResources = new ArrayList<ComponentResource>(); |
| |
| 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 = resourceMap.getSourcePath(); |
| IPath runtimePath = resourceMap.getRuntimePath(); |
| IResource sourceResource = util.getProject().findMember(sourcePath); |
| |
| // Verify if the map is for the content root |
| if (util.isRootMapping(resourceMap)) { |
| rootValidMaps++; |
| if (pathMappedToContentRoot == null) //we are interested only if the first resource mapped to root |
| pathMappedToContentRoot = sourcePath; |
| } |
| // Verify if the map is for a java src folder and is mapped to "WEB-INF/classes" |
| else if (runtimePath.equals(webInfClasses)) { |
| if (sourceResource != null && sourceResource.exists()) { |
| if (sourceResource instanceof IContainer && !util.isSourceContainer((IContainer) sourceResource)) { |
| util.reportStatus(ISingleRootStatus.SOURCE_NOT_JAVA_CONTAINER, sourcePath); |
| } |
| } |
| else { |
| util.reportStatus(ISingleRootStatus.SOURCE_PATH_NOT_FOUND, sourcePath); |
| } |
| } |
| else { |
| // Do not report status yet. Below we do some extra validation |
| tmpResources.add(resourceMap); |
| } |
| if (util.getValidateFlag() == CANCEL) return false; |
| } |
| |
| if (pathMappedToContentRoot != null){ |
| for (ComponentResource res:tmpResources){ |
| IPath completePath = pathMappedToContentRoot.append(res.getRuntimePath()); |
| if (completePath.equals(res.getSourcePath())){ |
| // This mapping is redundant, because there is already a mapping that includes this resource |
| util.reportStatus(UNNECESSARY_RESOURCE_MAP, res.getSourcePath()); |
| } |
| else{ |
| // Not root, not WEB-INF/classes and not redundant, report status |
| util.reportStatus(RUNTIME_PATH_NOT_ROOT_OR_WEBINF_CLASSES, res.getRuntimePath()); |
| } |
| if (util.getValidateFlag() == CANCEL) return false; |
| } |
| tmpResources = null; |
| } |
| |
| // 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) { |
| util.reportStatus(ONE_CONTENT_ROOT_REQUIRED); |
| } |
| else if (rootValidMaps > 1) { |
| util.reportStatus(ONLY_1_CONTENT_ROOT_ALLOWED); |
| } |
| } |
| return util.getValidateFlag() == CANCEL ? false : true; |
| } |
| |
| public IFlattenParticipant[] getDelegateParticipants() { |
| List<IFlattenParticipant> participants = new ArrayList<IFlattenParticipant>(); |
| |
| participants.add(new JEEHeirarchyExportParticipant()); |
| participants.add(FilterResourceParticipant.createSuffixFilterParticipant(filteredSuffixes)); |
| participants.add(new AddClasspathLibReferencesParticipant()); |
| participants.add(new AddClasspathLibRefsProviderParticipant()); |
| participants.add(new AddClasspathFoldersParticipant()); |
| if (ClasspathDependencyEnablement.isAllowClasspathComponentDependency()) { |
| participants.add(new ReplaceManifestExportParticipant(new Path(J2EEConstants.MANIFEST_URI))); |
| } |
| |
| return participants.toArray(new IFlattenParticipant[participants.size()]); |
| } |
| |
| |
| } |