| package org.eclipse.wst.validation; |
| |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.wst.validation.internal.SummaryReporter; |
| import org.eclipse.wst.validation.internal.ValOperation; |
| import org.eclipse.wst.validation.internal.ValOperationManager; |
| import org.eclipse.wst.validation.internal.ValidationConfiguration; |
| import org.eclipse.wst.validation.internal.ValidatorMetaData; |
| import org.eclipse.wst.validation.internal.core.ValidatorLauncher; |
| import org.eclipse.wst.validation.internal.delegates.ValidatorDelegateDescriptor; |
| import org.eclipse.wst.validation.internal.delegates.ValidatorDelegatesRegistry; |
| import org.eclipse.wst.validation.internal.model.FilterGroup; |
| import org.eclipse.wst.validation.internal.operations.IWorkbenchContext; |
| import org.eclipse.wst.validation.internal.operations.WorkbenchContext; |
| import org.eclipse.wst.validation.internal.plugin.ValidationPlugin; |
| import org.eclipse.wst.validation.internal.provisional.core.IMessage; |
| import org.eclipse.wst.validation.internal.provisional.core.IValidator; |
| |
| /** |
| * Represents a validator. This gets instantiated through one of the validator extension points. |
| * |
| * @author karasiuk |
| * |
| */ |
| public abstract class Validator implements Comparable { |
| |
| protected boolean _buildValidation = true; |
| |
| /** If this is a delegating validator, then this field holds the validator that will be delegated to. */ |
| private String _delegatingId; |
| |
| /** |
| * If this validator is also used to control an ISource validator, the id of the ISource validator is |
| * registered here. |
| */ |
| private String _sourceId; |
| |
| protected boolean _manualValidation = true; |
| |
| /** |
| * Version of the filter definition. By increasing this number the framework can know that a plug-in has |
| * changed it's filters. |
| */ |
| private int _version = 1; |
| |
| public static Validator create(AbstractValidator validator) { |
| return new V2(validator); |
| } |
| |
| public static Validator create(ValidatorMetaData vmd, ValidationConfiguration config){ |
| return new V1(vmd, config); |
| } |
| |
| /** |
| * If you are a version 1 validator, answer yourself as one, otherwise answer null. |
| */ |
| public V1 asV1Validator(){ |
| return null; |
| } |
| |
| /** |
| * If you are a version 2 validator, answer yourself as one, otherwise answer null. |
| */ |
| public V2 asV2Validator() { |
| return null; |
| } |
| |
| /** |
| * The project is being cleaned, this method gives the validator a chance to do any special cleanup. |
| * The default is to do nothing. |
| * |
| * @param project the project being built. |
| * @param monitor the monitor that should be used for reporting progress if the clean takes a long time. |
| */ |
| public void clean(IProject project, IProgressMonitor monitor){ |
| } |
| |
| /** |
| * Compare yourself based on Validator name. |
| */ |
| public int compareTo(Object validator) { |
| if (validator instanceof Validator){ |
| Validator other = (Validator)validator; |
| return getName().compareTo(other.getName()); |
| } |
| return -1; |
| } |
| |
| /** Answer a deep copy of yourself. */ |
| public abstract Validator copy(); |
| |
| /** |
| * Update your direct, non transient fields from the fields in v. |
| */ |
| protected void copyLocal(Validator v){ |
| _buildValidation = v._buildValidation; |
| _delegatingId = v._delegatingId; |
| _manualValidation = v._manualValidation; |
| _version = v._version; |
| } |
| |
| /** |
| * Answer true if this validator, based on it's filters, should validate this resource. This method |
| * does not check to see if global validation or project validation has been suspended or not. |
| * |
| * @param resource the resource to be checked |
| * @param isManual if true then this validator must also be enabled for manual validation. |
| * @param isBuild if true then this validator must also be enabled for builder based validation. |
| * |
| * @return true if the resource should be validated. |
| */ |
| public boolean shouldValidate(IResource resource, boolean isManual, boolean isBuild){ |
| if (isManual && !_manualValidation)return false; |
| if (isBuild && !_buildValidation)return false; |
| |
| return shouldValidate(resource); |
| } |
| |
| /** |
| * Answer true if this validator, based on it's filters, should validate this project. This method |
| * does not check to see if global validation or project validation has been suspended or not. |
| * |
| * @param project the project to be checked |
| * @param isManual if true then this validator must also be enabled for manual validation. |
| * @param isBuild if true then this validator must also be enabled for builder based validation. |
| * |
| * @return true if the project should be validated. |
| */ |
| public boolean shouldValidateProject(IProject project, boolean isManual, boolean isBuild){ |
| if (isManual && !_manualValidation)return false; |
| if (isBuild && !_buildValidation)return false; |
| if (project == null || !project.isOpen())return false; |
| return shouldValidateProject(project); |
| } |
| /** |
| * Validate the resource. |
| * |
| * @param resource the resource to be validated |
| * @param kind the kind of resource change, see IResourceDelta for values. |
| * @param operation the operation that this validation is running under. This can be null. |
| * @param monitor a way to report progress. This can be null. |
| * |
| * @return the result of doing the validation, it can be, but usually isn't null. |
| */ |
| public abstract ValidationResult validate(IResource resource, int kind, ValOperation operation, IProgressMonitor monitor); |
| |
| /** |
| * This method will be called before any validation takes place. It allows validators to perform any |
| * initialization that they might need. |
| * |
| * @param project the project that is being validated. For the very first call in the validation phase, |
| * this will be null. That is the signal to the validator that a top level validation is starting. |
| * Subsequently, the project will be set, as each of the individual projects are validated. |
| * |
| * @param state a way to pass arbitrary, validator specific, data from one invocation of a validator to |
| * the next, during the validation phase. |
| * |
| * @param monitor the monitor that should be used for reporting progress if the clean takes a long time. |
| */ |
| public void validationStarting(IProject project, ValidationState state, IProgressMonitor monitor){ |
| // subclasses need to override this, if they wish to let their validators know about this event |
| } |
| |
| /** |
| * This method will be called when validation is complete. It allows validators to perform any |
| * cleanup that they might need to do. |
| * |
| * @param project the project that was validated. The very last call in the validation will set this to |
| * null so that the validator knows that all the projects have now been validated. |
| * |
| * @param state a way to pass arbitrary, validator specific, data from one invocation of a validator to |
| * the next, during the validation phase. |
| * |
| * @param monitor the monitor that should be used for reporting progress if the clean takes a long time. |
| */ |
| public void validationFinishing(IProject project, ValidationState state, IProgressMonitor monitor){ |
| // subclasses need to override this, if they wish to let their validators know about this event |
| } |
| |
| public IValidator asIValidator(){ |
| return null; |
| } |
| |
| |
| protected abstract boolean shouldValidate(IResource resource); |
| protected abstract boolean shouldValidateProject(IProject project); |
| |
| public abstract String getId(); |
| |
| public abstract String getName(); |
| |
| /** |
| * Answer the name of the class that implements the validator. |
| * @return |
| */ |
| public abstract String getValidatorClassname(); |
| |
| /** |
| * Is this validator currently enabled for validations that are triggered manually? |
| */ |
| public boolean isManualValidation() { |
| return _manualValidation; |
| } |
| |
| /** |
| * Set whether this validator should be triggered as part of a manual validation. |
| * |
| * @param manualValidation |
| */ |
| public void setManualValidation(boolean manualValidation) { |
| _manualValidation = manualValidation; |
| } |
| |
| /** |
| * Is this validator currently enabled for validations that are triggered by builds? |
| */ |
| public boolean isBuildValidation() { |
| return _buildValidation; |
| } |
| |
| /** |
| * Set whether this validator should be triggered by the build process. |
| * |
| * @param buildValidation |
| */ |
| public void setBuildValidation(boolean buildValidation) { |
| _buildValidation = buildValidation; |
| } |
| |
| /** |
| * Get the id of the "real" validator, that is the validator that will be called when this delegating |
| * validator is asked to validate something. If this isn't a delegating validator answer null. |
| */ |
| public String getDelegatingId() { |
| return _delegatingId; |
| } |
| |
| public String getDependencyId(){ |
| return getId(); |
| } |
| |
| /** |
| * Set the id of the "real" validator, that is the validator that will be called when this delegating |
| * validator is asked to validate something. |
| * |
| * @param delegating the id of the validator that is actually going to perform the validation. |
| */ |
| public void setDelegatingId(String delegating) { |
| _delegatingId = delegating; |
| } |
| |
| public int getVersion() { |
| return _version; |
| } |
| |
| public void setVersion(int version) { |
| _version = version; |
| } |
| |
| @Override |
| public String toString() { |
| return getName(); |
| } |
| |
| /** |
| * A validator that uses version 1 of the validation framework. |
| * @author karasiuk |
| * |
| */ |
| public final static class V1 extends Validator { |
| private ValidatorMetaData _vmd; |
| |
| /** |
| * Create a new version 1 validator. |
| * @param vmd |
| * @param config this is used to set the global enablement options. In some case this can be null. |
| */ |
| public V1(ValidatorMetaData vmd, ValidationConfiguration config){ |
| _vmd = vmd; |
| if (config != null){ |
| setBuildValidation(config.isBuildEnabled(vmd)); |
| setManualValidation(config.isManualEnabled(vmd)); |
| } |
| setDelegatingId(ValidatorDelegatesRegistry.getInstance().getDefaultDelegate(getValidatorClassname())); |
| } |
| |
| @Override |
| public IValidator asIValidator() { |
| IValidator v = null; |
| try { |
| v = _vmd.getValidator(); |
| } |
| catch (InstantiationException e){ |
| ValidationPlugin.getPlugin().handleException(e); |
| return null; |
| } |
| return v; |
| } |
| |
| public V1 asV1Validator() { |
| return this; |
| } |
| |
| public Validator copy() { |
| V1 v = new V1(_vmd, null); |
| v.copyLocal(this); |
| |
| return v; |
| } |
| |
| public String getName() { |
| return _vmd.getValidatorDisplayName(); |
| } |
| |
| public ValidatorMetaData getVmd(){ |
| return _vmd; |
| } |
| |
| public String getValidatorClassname(){ |
| String name = ""; //$NON-NLS-1$ |
| try { |
| name = _vmd.getValidator().getClass().getName(); |
| } |
| catch (Exception e){ |
| // eat it |
| } |
| return name; |
| } |
| public String getId() { |
| return _vmd.getValidatorUniqueName(); |
| } |
| |
| @Override |
| public void setBuildValidation(boolean buildValidation) { |
| super.setBuildValidation(buildValidation); |
| _vmd.setBuildValidation(buildValidation); |
| } |
| |
| @Override |
| public void setManualValidation(boolean manualValidation) { |
| super.setManualValidation(manualValidation); |
| _vmd.setManualValidation(manualValidation); |
| } |
| |
| @Override |
| protected boolean shouldValidate(IResource resource) { |
| return _vmd.isApplicableTo(resource); |
| } |
| |
| @Override |
| protected boolean shouldValidateProject(IProject project) { |
| // TODO determine if this can be optimized |
| return true; |
| } |
| |
| @Override |
| public ValidationResult validate(IResource resource, int kind, ValOperation operation, |
| IProgressMonitor monitor) { |
| |
| if (monitor == null)monitor = new NullProgressMonitor(); |
| |
| ValidationResult vr = new ValidationResult(); |
| IValidator v = asIValidator(); |
| if (v == null)return null; |
| |
| try { |
| IProject project = resource.getProject(); |
| SummaryReporter reporter = new SummaryReporter(project, monitor); |
| IWorkbenchContext helper = _vmd.getHelper(project); |
| if (helper instanceof WorkbenchContext){ |
| WorkbenchContext wc = (WorkbenchContext)helper; |
| List<String> files = new LinkedList<String>(); |
| // [213631] The JSP validator expects full paths not relative paths, but the XML validator |
| // expects relative paths. |
| files.add(wc.getPortableName(resource)); |
| wc.setValidationFileURIs(files); |
| } |
| ValidatorLauncher.getLauncher().start(helper, v, reporter); |
| |
| vr.incrementError(reporter.getSeverityHigh()); |
| vr.incrementWarning(reporter.getSeverityNormal()); |
| vr.incrementInfo(reporter.getSeverityLow()); |
| |
| } |
| catch (Exception e){ |
| ValidationPlugin.getPlugin().handleException(e); |
| } |
| return vr; |
| } |
| |
| } |
| |
| /** |
| * A validator that uses version 2 of the validation framework. |
| * @author karasiuk |
| * |
| */ |
| public final static class V2 extends Validator implements IAdaptable { |
| private AbstractValidator _validator; |
| |
| private List<FilterGroup> _groups = new LinkedList<FilterGroup>(); |
| private FilterGroup[] _groupsArray; |
| |
| /** The full id of the extension. */ |
| private String _id; |
| |
| /** Name of the validator. */ |
| private String _name; |
| |
| /** |
| * If this validator is a delegating validator, then this is the "real" validator (i.e. the one that |
| * does the work). |
| */ |
| private AbstractValidator _delegated; |
| |
| public V2(AbstractValidator base){ |
| _validator = base; |
| setDelegatingId(ValidatorDelegatesRegistry.getInstance().getDefaultDelegate(getValidatorClassname())); |
| } |
| |
| public synchronized void add(FilterGroup fg) { |
| _groupsArray = null; |
| _groups.add(fg); |
| } |
| |
| @Override |
| public IValidator asIValidator() { |
| AbstractValidator av = getDelegatedValidator(); |
| if (av instanceof IValidator)return (IValidator)av; |
| return super.asIValidator(); |
| } |
| |
| public V2 asV2Validator() { |
| return this; |
| } |
| |
| /** |
| * Let the validator know that a clean is about to happen. |
| * |
| * @param project the project that is being cleaned. This can be null which means that the workspace |
| * is being cleaned (in which case a separate call will be made for each open project). |
| */ |
| public void clean(IProject project, IProgressMonitor monitor) { |
| getDelegatedValidator().clean(project, ValOperationManager.getDefault().getOperation().getState(), monitor); |
| } |
| |
| public Validator copy() { |
| V2 v = new V2(_validator); |
| v.copyLocal(this); |
| |
| FilterGroup[] groups = getGroups(); |
| v._groupsArray = new FilterGroup[groups.length]; |
| for (int i=0; i<groups.length; i++){ |
| v._groupsArray[i] = groups[i].copy(); |
| v._groups.add(v._groupsArray[i]); |
| } |
| |
| v._id = _id; |
| v._name = _name; |
| |
| return v; |
| } |
| |
| public String getDependencyId(){ |
| String id = getDelegatedValidator().getDependencyId(); |
| if (id != null)return id; |
| return getId(); |
| } |
| |
| /** |
| * Answer the actual validator that is going to perform the validation. If this is a normal validator this |
| * method will simply answer itself. However if this is a delegating validator, then this will answer the |
| * "real" validator. |
| * |
| * @return |
| */ |
| public AbstractValidator getDelegatedValidator(){ |
| AbstractValidator delegated = _delegated; |
| if (delegated != null)return delegated; |
| else if (getDelegatingId() == null)return _validator; |
| try { |
| ValidatorDelegateDescriptor vdd = ValidatorDelegatesRegistry.getInstance() |
| .getDescriptor(getValidatorClassname(), getDelegatingId()); |
| if (vdd == null)return _validator; |
| delegated = vdd.getValidator2(); |
| } |
| catch (Exception e){ |
| ValidationPlugin.getPlugin().handleException(e); |
| } |
| if (delegated == null)return _validator; |
| _delegated = delegated; |
| return delegated; |
| } |
| |
| public String getId() { |
| return _id; |
| } |
| |
| /** |
| * Answer the validator's filter groups. |
| * |
| * @return an empty array if the validator does not have any filter groups. |
| */ |
| public synchronized FilterGroup[] getGroups(){ |
| FilterGroup[] groups = _groupsArray; |
| if (groups == null){ |
| groups = new FilterGroup[_groups.size()]; |
| _groups.toArray(groups); |
| _groupsArray = groups; |
| } |
| return groups; |
| } |
| |
| public String getName() { |
| return _name; |
| } |
| |
| public AbstractValidator getValidator() { |
| return _validator; |
| } |
| |
| public String getValidatorClassname(){ |
| return getValidator().getClass().getName(); |
| } |
| |
| /** |
| * Answer true if this validator, based on it's filters, should validate this resource. |
| * |
| * @return true if the resource should be validated. |
| */ |
| protected boolean shouldValidate(IResource resource) { |
| FilterGroup[] groups = getGroups(); |
| IProject project = resource.getProject(); |
| for (FilterGroup group : groups){ |
| if (!group.shouldValidate(project, resource))return false; |
| } |
| return true; |
| } |
| |
| |
| @Override |
| public void setDelegatingId(String delegating) { |
| super.setDelegatingId(delegating); |
| _delegated = null; |
| } |
| |
| public synchronized void setGroups(FilterGroup[] groups){ |
| _groups.clear(); |
| _groupsArray = null; |
| for (FilterGroup group : groups)_groups.add(group); |
| } |
| |
| public void setId(String id) { |
| _id = id; |
| } |
| |
| public void setName(String name) { |
| _name = name; |
| } |
| |
| @Override |
| public ValidationResult validate(IResource resource, int kind, ValOperation operation, IProgressMonitor monitor) { |
| ValidationResult vr = null; |
| if (operation == null)operation = new ValOperation(); |
| if (monitor == null)monitor = new NullProgressMonitor(); |
| try { |
| vr = getDelegatedValidator().validate(resource, kind, operation.getState(), monitor); |
| } |
| catch (Exception e){ |
| ValidationPlugin.getPlugin().handleException(e); |
| } |
| |
| if (vr != null){ |
| if (vr.getValidationException() != null){ |
| ValidationPlugin.getPlugin().handleException(vr.getValidationException()); |
| } |
| updateResults(vr); |
| if (vr.getDependsOn() != null){ |
| ValidationFramework.getDefault().getDependencyIndex().set(getDependencyId(), resource, vr.getDependsOn()); |
| } |
| IResource[] validated = vr.getValidated(); |
| if (validated != null){ |
| for (int i=0; i<validated.length; i++){ |
| operation.addValidated(getId(), validated[i]); |
| } |
| } |
| |
| ValidatorMessage[] msgs = vr.getMessages(); |
| for (int i=0; i<msgs.length; i++){ |
| ValidatorMessage m = msgs[i]; |
| try { |
| IMarker marker = m.getResource().createMarker(m.getType()); |
| marker.setAttributes(m.getAttributes()); |
| } |
| catch (CoreException e){ |
| ValidationPlugin.getPlugin().handleException(e); |
| } |
| } |
| } |
| return vr; |
| } |
| |
| private void updateResults(ValidationResult vr) { |
| ReporterHelper rh = vr.getReporterHelper(); |
| if (rh == null)return; |
| for (IMessage message : rh.getMessages()){ |
| Object target = message.getTargetObject(); |
| if (target != null){ |
| if (target instanceof IResource){ |
| IResource res = (IResource)target; |
| ValidatorMessage vm = ValidatorMessage.create(message.getText(), res); |
| vr.add(vm); |
| int markerSeverity = IMarker.SEVERITY_INFO; |
| int sev = message.getSeverity(); |
| if ((sev & IMessage.HIGH_SEVERITY) != 0)markerSeverity = IMarker.SEVERITY_ERROR; |
| else if ((sev & IMessage.NORMAL_SEVERITY) != 0)markerSeverity = IMarker.SEVERITY_WARNING; |
| vm.setAttribute(IMarker.SEVERITY, markerSeverity); |
| vm.setAttribute(IMarker.LINE_NUMBER, message.getLineNumber()); |
| int offset = message.getOffset(); |
| if (offset != IMessage.OFFSET_UNSET){ |
| vm.setAttribute(IMarker.CHAR_START, offset); |
| int len = message.getLength(); |
| if (len != IMessage.OFFSET_UNSET){ |
| vm.setAttribute(IMarker.CHAR_START, offset); |
| vm.setAttribute(IMarker.CHAR_END, offset+len); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void validationStarting(IProject project, ValidationState state, IProgressMonitor monitor) { |
| _validator.validationStarting(project, state, monitor); |
| } |
| |
| @Override |
| public void validationFinishing(IProject project, ValidationState state, IProgressMonitor monitor) { |
| _validator.validationFinishing(project, state, monitor); |
| } |
| |
| public Object getAdapter(Class adapter) { |
| return Platform.getAdapterManager().getAdapter(this, adapter); |
| } |
| |
| public synchronized void remove(FilterGroup group) { |
| _groups.remove(group); |
| _groupsArray = null; |
| } |
| |
| @Override |
| protected boolean shouldValidateProject(IProject project) { |
| FilterGroup[] groups = getGroups(); |
| for (FilterGroup group : groups){ |
| if (!group.shouldValidate(project, null))return false; |
| } |
| return true; |
| } |
| } |
| |
| public String getSourceId() { |
| return _sourceId; |
| } |
| |
| public void setSourceId(String sourceId) { |
| _sourceId = sourceId; |
| } |
| } |