org.eclipse.wst.validation.internal.operations.ValidationBuilder Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (c) 2001, 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.wst.validation.internal.operations;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.wst.validation.ValidationFramework;
import org.eclipse.wst.validation.internal.ConfigurationManager;
import org.eclipse.wst.validation.internal.InternalValidatorManager;
import org.eclipse.wst.validation.internal.ProjectConfiguration;
import org.eclipse.wst.validation.internal.ResourceConstants;
import org.eclipse.wst.validation.internal.ResourceHandler;
import org.eclipse.wst.validation.internal.Tracing;
import org.eclipse.wst.validation.internal.ValBuilderJob;
import org.eclipse.wst.validation.internal.ValManager;
import org.eclipse.wst.validation.internal.ValidatorMetaData;
import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
/**
* Validation Framework Builder.
*
* This builder is configured on J2EE IProjects automatically, and can be added to other types of
* projects through the Properties page. It launches validation on the project if the project has
* build validation enabled.
*
*
* This launches a Job for the new V2 validators and also a Job for each of the Job based V1
* validators. If there are any "in-line" V1 validations they are done as part of this builder.
* Because of all the jobs that this builder spawns, the build will usually be finished long before
* all the validation has finished.
*
*/
public class ValidationBuilder extends IncrementalProjectBuilder {
/*
* GRK - This class serves as a main entry point into the framework. There is one instance of this class for every
* project that has a validation builder configured for it. Typically if you had ten projects in your workspace you would have
* ten of these objects. They are created early in the life cycle of the workbench, and then are reused.
*
* My observation was that they are run serially by the same thread.
*/
public static final int NO_DELTA_CHANGE = -1;
protected List referencedProjects;
protected IWorkbenchContext workbenchContext = null;
/**
* All the jobs that the validation framework spawns will belong to this family.
*/
public static final Object FAMILY_VALIDATION_JOB = new Object();
public ValidationBuilder() {
}
private IProject[] getAllReferencedProjects(IProject project, Set visitedProjects) {
if (visitedProjects == null)visitedProjects = new HashSet();
else if (visitedProjects.contains(project))return getReferencedProjects();
else visitedProjects.add(project);
if (referencedProjects == null)referencedProjects = new ArrayList();
try {
if (project.isAccessible()) {
IProject[] refProjArray = project.getReferencedProjects();
collectReferecedProject(refProjArray);
for (IProject refProject : refProjArray) {
getAllReferencedProjects(refProject, visitedProjects);
}
}
return getReferencedProjects();
} catch (CoreException e) {
ValidationPlugin.getPlugin().handleException(e);
}
return null;
}
public IWorkbenchContext getWorkbenchContext() {
if(workbenchContext == null) {
workbenchContext = new WorkbenchContext();
workbenchContext.setProject(getProject());
}
return workbenchContext;
}
/**
* Add the projects from refProjArray to the list of referenced projects (if they are not
* already in the list).
* @param refProjArray
*/
private void collectReferecedProject(IProject[] refProjArray) {
for (IProject project : refProjArray) {
if (!referencedProjects.contains(project))referencedProjects.add(project);
}
}
protected void clean(IProgressMonitor monitor) throws CoreException {
IProject currentProject = getProject();
Tracing.log("ValidationBuilder-02 clean ", currentProject); //$NON-NLS-1$
newClean(monitor);
if (currentProject == null || !currentProject.isAccessible())return;
try {
ProjectConfiguration prjp = ConfigurationManager.getManager().getProjectConfiguration(currentProject);
ValidatorMetaData[] vmds = prjp.getValidators();
for (int i = 0; i < vmds.length; i++) {
ValidatorMetaData vmd = vmds[i];
// For validators who aren't going to run, clear their messages from the task list.
// Don't need to check for duplicate entries because each Validator must be unique.
// The uniqueness of each Validator is checked by the plugin registry.
WorkbenchReporter.removeAllMessages(currentProject, vmd.getValidatorNames(), null);
}
} catch (InvocationTargetException e) {
ValidationPlugin.getPlugin().handleException(e);
ValidationPlugin.getPlugin().handleException(e.getTargetException());
}
}
private IProject[] getReferencedProjects() {
IProject[] refProjArray = new IProject[referencedProjects.size()];
return referencedProjects.toArray(refProjArray);
}
@SuppressWarnings("unchecked")
public IProject[] build(int kind, Map parameters, IProgressMonitor monitor) {
IResourceDelta delta = null;
IProject project = getProject();
Tracing.log("ValidationBuilder-01 build ", kind, project); //$NON-NLS-1$
if (Tracing.isLogging(1)){
Tracing.logResourceDeltas(getDelta(project), 50);
}
// GRK I wonder why this builder needs to know about all the other referenced projects?
// won't they have builders of their own.
IProject[] referenced = getAllReferencedProjects(project, null);
if (ValidationFramework.getDefault().isSuspended(project) ||
ValManager.getDefault().isDisabled(project))return referenced;
try {
newBuild(kind, monitor);
ProjectConfiguration prjp = ConfigurationManager.getManager().getProjectConfiguration(project);
delta = getDelta(project);
boolean doFullBuild = (kind == FULL_BUILD);
// It is possible for kind to == AUTO_BUILD while delta is null
// (saw this when creating a project by copying another project.)
// However, a "Rebuild Project" will invoke this builder with
// kind==FULL_BUILD and a null delta, and validation should run in that case.
if (!doFullBuild && delta == null) {
if (isReferencedProjectInDelta(referenced)) {
performFullBuildForReferencedProjectChanged(monitor, prjp);
} else {
String[] msgParms = new String[]{project.getName()};
monitor.subTask(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_NULL_DELTA, msgParms));
// A null delta means that a full build must be performed,
// but this builder was invoked with an incremental or automatic
// build kind. Return without doing anything so that the user
// doesn't have to wait forever.
}
return referenced;
}
if (doFullBuild) {
cleanupReferencedProjectsMarkers(prjp, referenced);
performFullBuild(monitor, prjp);
} else {
if (delta.getAffectedChildren().length == 0) {
if (isReferencedProjectInDelta(referenced)){
cleanupReferencedProjectsMarkers(prjp, referenced);
performFullBuildForReferencedProjectChanged(monitor, prjp);
}
return referenced;
}
EnabledIncrementalValidatorsOperation operation = new EnabledIncrementalValidatorsOperation(project, delta, true);
operation.run(monitor);
}
return referenced;
} catch (InvocationTargetException e) {
ValidationPlugin.getPlugin().handleException(e);
ValidationPlugin.getPlugin().handleException(e.getTargetException());
return referenced;
} catch (Exception e) {
ValidationPlugin.getPlugin().handleException(e);
return referenced;
} finally {
referencedProjects = null;
}
}
private void cleanupReferencedProjectsMarkers(final ProjectConfiguration prjp, IProject[] referenced){
//When a project references one or more project, performing a clean build on referenced
//causes delta to be invoked on referencee, aka, parent. This causes following code to
//be invoked.
//The following code is trying to fix a case where Ejb project references a utility project,
//and the clean build on utility project causes the code to come here, the ejb validator runs
//on the ejb project due to performFullBuildForReferencedProjectChanged() below, but it also
//causes marker to be generated for the util project, but the markers for util project are not
//cleaned up.
if( referenced == null || referenced.length == 0 )return;
try{
ValidatorMetaData[] enabledValidators = prjp.getEnabledFullBuildValidators(true, false);
Set set = new HashSet();
set.addAll( Arrays.asList( enabledValidators ) );
for (IProject p : referenced) {
if (!p.isAccessible())continue;
ProjectConfiguration refProjectCfg = ConfigurationManager.getManager().getProjectConfiguration(p);
ValidatorMetaData[] refEnabledValidators = refProjectCfg.getEnabledFullBuildValidators(true, false);
//remove from the set the validators which are also in child
for(ValidatorMetaData vmd : refEnabledValidators)set.remove(vmd);
for(ValidatorMetaData vmd : set)WorkbenchReporter.removeAllMessages(p, vmd.getValidator());
}
}catch (Exception exc) {
ValidationPlugin.getPlugin().logMessage(IStatus.ERROR, exc.toString());
}
}
private boolean isReferencedProjectInDelta(IProject[] referenced) {
IProject p = null;
for (int i = 0; i < referenced.length; i++) {
p = referenced[i];
IResourceDelta delta = getDelta(p);
if (delta != null && delta.getAffectedChildren().length > 0)
return true;
}
return false;
}
private void performFullBuildForReferencedProjectChanged(IProgressMonitor monitor, ProjectConfiguration prjp) throws InvocationTargetException {
performFullBuild(monitor, prjp, true);
}
private void performFullBuild(IProgressMonitor monitor, ProjectConfiguration prjp) throws InvocationTargetException {
performFullBuild(monitor, prjp, false);
}
private void performFullBuild(IProgressMonitor monitor, ProjectConfiguration prjp, boolean onlyDependentValidators) throws InvocationTargetException {
ValidatorMetaData[] enabledValidators = prjp.getEnabledFullBuildValidators(true, onlyDependentValidators);
if ((enabledValidators != null) && (enabledValidators.length > 0)) {
Set enabledValidatorsSet = InternalValidatorManager.wrapInSet(enabledValidators);
EnabledValidatorsOperation op = new EnabledValidatorsOperation(getProject(), enabledValidatorsSet, true);
op.run(monitor);
}
}
/**
* Run the new validation builder. This is a transition method, while we continue to have
* the old and new validation builders.
*
* @param kind the kind of build
*
* @see IncrementalProjectBuilder#AUTO_BUILD
* @see IncrementalProjectBuilder#CLEAN_BUILD
* @see IncrementalProjectBuilder#FULL_BUILD
* @see IncrementalProjectBuilder#INCREMENTAL_BUILD
*/
private void newBuild(int kind, IProgressMonitor monitor) throws CoreException {
IResourceDelta delta = null;
IProject project = getProject();
switch (kind){
case AUTO_BUILD:
case INCREMENTAL_BUILD:
delta = getDelta(project);
break;
}
ValBuilderJob.validateProject(project, delta, kind);
}
/**
* Run the new clean method. This is a transition method, while we continue to have
* the old and new validation builders.
*/
private void newClean(IProgressMonitor monitor) throws CoreException {
ValManager.getDefault().clean(getProject(), monitor);
}
}