blob: 5aafeee9850dc04b479bed3852a9f9213da87ebc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 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;
import java.util.LinkedList;
import java.util.Queue;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.wst.validation.DependentResource;
import org.eclipse.wst.validation.Friend;
import org.eclipse.wst.validation.IDependencyIndex;
import org.eclipse.wst.validation.ValidationEvent;
import org.eclipse.wst.validation.ValidationFramework;
import org.eclipse.wst.validation.ValidationState;
import org.eclipse.wst.validation.Validator;
import org.eclipse.wst.validation.internal.model.IValidatorVisitor;
import org.eclipse.wst.validation.internal.operations.ValidationBuilder;
import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
/**
* Run all the v2 validators through this job.
* <p>
* This is the main class for supporting build based validation. When triggered it looks at all of the
* resource changes and determines what needs to be validated.
* </p>
* @author karasiuk
*
*/
public final class ValBuilderJob extends WorkspaceJob {
private static ValBuilderJob _job;
private static Queue<ValidationRequest> _work = new LinkedList<ValidationRequest>();
private final ValOperation _operation = new ValOperation();
/** The types of changes we are interested in. */
private final static int InterestedFlags = IResourceDelta.CONTENT | IResourceDelta.ENCODING |
IResourceDelta.MOVED_FROM | IResourceDelta.MOVED_TO;
public static synchronized void validateProject(IProject project, IResourceDelta delta, int buildKind){
ValidationRequest request = new ValidationRequest(project, delta, buildKind);
if (_job == null){
_job = new ValBuilderJob();
_job.add(request);
_job.schedule();
}
else {
_job.add(request);
}
}
private static synchronized ValidationRequest getRequest(){
ValidationRequest request = _work.poll();
if (request == null){
_job = null;
}
return request;
}
/**
* Each validation run is done in it's own job.
*
* @param project the project that is being validated
* @param delta the delta that is being validated. This may be null, in which case we do a
* full validation of the project.
*
* @param buildKind the kind of build.
* @see org.eclipse.core.resources.IncrementalProjectBuilder#AUTO_BUILD
* @see org.eclipse.core.resources.IncrementalProjectBuilder#CLEAN_BUILD
* @see org.eclipse.core.resources.IncrementalProjectBuilder#FULL_BUILD
* @see org.eclipse.core.resources.IncrementalProjectBuilder#INCREMENTAL_BUILD
*
* @param operation some global context for the validation operation
*
*/
private ValBuilderJob(){
super(ValMessages.JobName);
}
private void add(ValidationRequest request){
_work.add(request);
}
@Override
public boolean belongsTo(Object family) {
if (family == ResourcesPlugin.FAMILY_MANUAL_BUILD)return true;
if (family == ValidationBuilder.FAMILY_VALIDATION_JOB){
return true;
}
return super.belongsTo(family);
}
@Override
public IStatus runInWorkspace(IProgressMonitor monitor) {
Tracing.log("ValBuilderJob-01: Starting"); //$NON-NLS-1$
try {
startingValidation(monitor);
ValidationRequest request = getRequest();
while(request != null){
run(request, monitor);
request = getRequest();
}
}
finally {
finishingValidation(monitor);
}
Tracing.log("ValBuilderJob-02: Finished"); //$NON-NLS-1$
return Status.OK_STATUS;
}
private void startingValidation(IProgressMonitor monitor) {
IValidatorVisitor startingVisitor = new IValidatorVisitor(){
public void visit(Validator validator, IProject project, ValType valType,
ValOperation operation, IProgressMonitor monitor) {
validator.validationStarting(project, operation.getState(), monitor);
}
};
ValManager.getDefault().accept(startingVisitor, null, ValType.Build, getOperation(), monitor);
}
private void finishingValidation(IProgressMonitor monitor) {
IValidatorVisitor finishedVisitor = new IValidatorVisitor(){
public void visit(Validator validator, IProject project, ValType valType,
ValOperation operation, IProgressMonitor monitor) {
validator.validationFinishing(project, operation.getState(), monitor);
}
};
ValManager.getDefault().accept(finishedVisitor, null, ValType.Build, getOperation(), monitor);
}
private void run(ValidationRequest request, IProgressMonitor monitor){
setName(ValMessages.JobName + " " + request.getProject().getName()); //$NON-NLS-1$
try {
IValidatorVisitor startingVisitor = new IValidatorVisitor(){
public void visit(Validator validator, IProject project, ValType valType,
ValOperation operation, IProgressMonitor monitor) {
validator.validationStarting(project, operation.getState(), monitor);
}
};
ValManager.getDefault().accept(startingVisitor, request.getProject(), ValType.Build, getOperation(), monitor);
if (request.getDelta() == null)fullBuild(request, monitor);
else deltaBuild(request, monitor);
}
catch (ProjectUnavailableError e){
ValidationPlugin.getPlugin().handleProjectUnavailableError(e);
}
catch (ResourceUnavailableError e){
ValidationPlugin.getPlugin().handleResourceUnavailableError(e);
}
catch (CoreException e){
ValidationPlugin.getPlugin().handleException(e);
}
finally {
IValidatorVisitor finishedVisitor = new IValidatorVisitor(){
public void visit(Validator validator, IProject project, ValType valType,
ValOperation operation, IProgressMonitor monitor) {
validator.validationFinishing(project, operation.getState(), monitor);
}
};
ValManager.getDefault().accept(finishedVisitor, request.getProject(), ValType.Build, getOperation(), monitor);
}
}
private void deltaBuild(ValidationRequest request, IProgressMonitor monitor) throws CoreException {
ResourceCounter counter = new ResourceCounter();
request.getDelta().accept(counter);
SubMonitor subMonitor = SubMonitor.convert(monitor, counter.getCount());
Visitor vistitor = new Visitor(request, subMonitor, monitor, getOperation());
request.getDelta().accept(vistitor);
}
private void fullBuild(ValidationRequest request, IProgressMonitor monitor) throws CoreException {
ResourceCounter counter = new ResourceCounter();
request.getProject().accept(counter, 0);
SubMonitor subMonitor = SubMonitor.convert(monitor, counter.getCount());
Visitor vistitor = new Visitor(request, subMonitor, monitor, getOperation());
request.getProject().accept(vistitor);
}
private ValOperation getOperation(){
return _operation;
}
static final class ResourceCounter implements IResourceProxyVisitor, IResourceDeltaVisitor {
private int _count;
public int getCount() {
return _count;
}
public boolean visit(IResourceProxy proxy) throws CoreException {
_count++;
return true;
}
public boolean visit(IResourceDelta delta) throws CoreException {
_count++;
return true;
}
}
static final class ValidationRequest {
/** The project that is being built. */
private final IProject _project;
/** The resource delta that triggered the build, it will be null for a full build. */
private final IResourceDelta _delta;
/**
* The kind of build.
*
* @see org.eclipse.core.resources.IncrementalProjectBuilder
*/
private final int _buildKind;
public ValidationRequest(IProject project, IResourceDelta delta, int buildKind){
_project = project;
_delta = delta;
_buildKind = buildKind;
}
public IProject getProject() {
return _project;
}
public IResourceDelta getDelta() {
return _delta;
}
public int getBuildKind() {
return _buildKind;
}
}
private final static class Visitor implements IResourceDeltaVisitor, IResourceVisitor{
private final ValidationRequest _request;
private final SubMonitor _subMonitor;
private final IProgressMonitor _monitor;
private final ValOperation _operation;
public Visitor(ValidationRequest request, SubMonitor subMonitor, IProgressMonitor monitor, ValOperation operation){
_request = request;
_subMonitor = subMonitor;
_monitor = monitor;
_operation = operation;
}
public boolean visit(IResource resource) throws CoreException {
try {
if (DisabledResourceManager.getDefault().isDisabled(resource)){
MarkerManager.getDefault().deleteMarkers(resource, _operation.getStarted(), IResource.DEPTH_INFINITE);
return false;
}
ValManager.getDefault().validate(_request.getProject(), resource, IResourceDelta.NO_CHANGE, ValType.Build,
_request.getBuildKind(), _operation, _subMonitor.newChild(1));
}
catch (ResourceUnavailableError e){
if (Tracing.isLogging())Tracing.log("ValBuilderJob-02: " + e.toString()); //$NON-NLS-1$
return false;
}
return true;
}
@SuppressWarnings("deprecation")
public boolean visit(IResourceDelta delta) throws CoreException {
IResource resource = delta.getResource();
if (DisabledResourceManager.getDefault().isDisabled(resource)){
MarkerManager.getDefault().deleteMarkers(resource, _operation.getStarted(), IResource.DEPTH_INFINITE);
return false;
}
int kind = delta.getKind();
boolean isChanged = (kind & IResourceDelta.CHANGED) != 0;
if (isChanged && (delta.getFlags() & InterestedFlags) == 0)return true;
if ((kind & (IResourceDelta.ADDED | IResourceDelta.CHANGED)) != 0){
ValManager.getDefault().validate(_request.getProject(), resource, delta.getKind(), ValType.Build,
_request.getBuildKind(), _operation, _subMonitor.newChild(1));
}
IDependencyIndex index = ValidationFramework.getDefault().getDependencyIndex();
if (index.isDependedOn(resource)){
MarkerManager mm = MarkerManager.getDefault();
for (DependentResource dr : index.get(resource)){
Validator val = dr.getValidator();
if (Friend.shouldValidate(val, dr.getResource(), ValType.Build, new ContentTypeWrapper())){
_operation.getState().put(ValidationState.TriggerResource, resource);
ValidationEvent event = new ValidationEvent(dr.getResource(), IResourceDelta.NO_CHANGE, delta);
if (val.shouldClearMarkers(event))mm.clearMarker(dr.getResource(), val);
ValManager.getDefault().validate(val, _operation, dr.getResource(),
IResourceDelta.NO_CHANGE, _monitor, event);
}
}
}
return true;
}
}
}