blob: ff12d458d6f57182e6ee31e2fdedd23d9d5e7cd9 [file] [log] [blame]
/*******************************************************************************
* 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()]);
}
}