| /******************************************************************************* |
| * Copyright (c) 2001, 2004 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.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.logging.Level; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceDelta; |
| import org.eclipse.core.resources.IWorkspaceRunnable; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.wst.common.frameworks.operations.IHeadlessRunnableWithProgress; |
| import org.eclipse.wst.validation.core.FileDelta; |
| import org.eclipse.wst.validation.core.IFileDelta; |
| import org.eclipse.wst.validation.core.IReporter; |
| import org.eclipse.wst.validation.core.IValidator; |
| import org.eclipse.wst.validation.core.Message; |
| import org.eclipse.wst.validation.core.MessageLimitException; |
| import org.eclipse.wst.validation.core.SeverityEnum; |
| import org.eclipse.wst.validation.core.ValidationException; |
| import org.eclipse.wst.validation.core.ValidatorLauncher; |
| import org.eclipse.wst.validation.internal.FilterUtil; |
| import org.eclipse.wst.validation.internal.InternalValidatorManager; |
| import org.eclipse.wst.validation.internal.ReferencialFileValidatorRegistryReader; |
| import org.eclipse.wst.validation.internal.RegistryConstants; |
| import org.eclipse.wst.validation.internal.ResourceConstants; |
| import org.eclipse.wst.validation.internal.ResourceHandler; |
| import org.eclipse.wst.validation.internal.VThreadManager; |
| import org.eclipse.wst.validation.internal.ValidationRegistryReader; |
| import org.eclipse.wst.validation.internal.ValidatorMetaData; |
| import org.eclipse.wst.validation.internal.plugin.TimeEntry; |
| import org.eclipse.wst.validation.internal.plugin.ValidationPlugin; |
| |
| import com.ibm.wtp.common.logger.LogEntry; |
| import com.ibm.wtp.common.logger.proxy.Logger; |
| |
| /** |
| * Implemented Validators methods must not be called directly by anyone other than this class, since |
| * some initialization of the validator is done here (via the getProject() method). The |
| * initialization is separated because the IProject isn't known until runtime. |
| * |
| * This operation is not intended to be subclassed outside of the validation framework. |
| */ |
| public abstract class ValidationOperation implements IWorkspaceRunnable, IHeadlessRunnableWithProgress { |
| public static final int NO_DELTA_CHANGE = -1; // Since IResourceConstants |
| // doesn't have a "no delta" |
| // flag, let this constant be |
| // the flag. |
| private static final String DELTA_AS_STRING = "IFileDelta[{0}] '{'{1}'}'"; //$NON-NLS-1$ |
| private static final String COMMA = ", "; //$NON-NLS-1$ |
| protected static final boolean DEFAULT_ASYNC = false; // For the deprecated |
| // constructors, by |
| // default the |
| // operation will not |
| // fork. |
| protected static final boolean DEFAULT_FORCE = true; // By default, run the |
| // operation whether |
| // or not it needs to |
| /** |
| * @deprecated Will be removed in Milestone 3. Use DEFAULT_ASYNC |
| */ |
| protected static final boolean DEFAULT_FORK = false; // @deprecated |
| private IProject _project = null; // project to be validated |
| private int _ruleGroup = RegistryConstants.ATT_RULE_GROUP_DEFAULT; // which |
| // pass |
| // should |
| // the |
| // validation |
| // invoke |
| private boolean _fork = DEFAULT_ASYNC; // do not fork the validation into a |
| // different thread by default |
| private Map _fileDeltas = null; // To reduce object creation, |
| private IResourceDelta _delta = null; |
| // the resource delta tree to be processed, or null if a full build/menu |
| // option was triggered. This value is cached so that validation can be run |
| // either from a builder, or from a menu item. (The Operation interface |
| // doesn't allow any parameter on execute except the IProgressMonitor.) |
| private Set _enabledValidators = null; |
| private boolean _force = DEFAULT_FORCE; // force this operation to run even |
| // if it doesn't need to? |
| private boolean _isFullValidate = false; // Run a full validation or an |
| // incremental? (true = full) |
| private Boolean _isAutoBuild = null; // Is the global auto-build preference |
| // enabled? |
| private Set _launchedValidators = null; // A list of the validators that |
| |
| // are enabled and were launched |
| // (i.e., that have input to |
| // validate). For internal |
| // validation framework use only; |
| // it's needed for the automatic |
| // tests. |
| /** |
| * This method is used for FINEST logging, to report exactly what deltas were about to be |
| * validated. |
| */ |
| private static final String getDeltaAsString(IFileDelta[] delta) { |
| String args = ""; //$NON-NLS-1$ |
| int numArgs = 0; |
| if (delta != null) { |
| numArgs = delta.length; |
| StringBuffer buffer = new StringBuffer(); |
| for (int i = 0; i < delta.length; i++) { |
| buffer.append(COMMA); |
| buffer.append(delta[i].toString()); |
| } |
| buffer.replace(0, 1, ""); //$NON-NLS-1$ // magic numbers 0 and 1 => Remove first COMMA from the list (hence index 0); length of COMMA is 2, hence index 0, 1. |
| args = buffer.toString(); |
| } |
| return MessageFormat.format(DELTA_AS_STRING, new String[]{String.valueOf(numArgs), args}); |
| } |
| |
| protected static void checkCanceled(WorkbenchReporter reporter) throws OperationCanceledException { |
| if (reporter == null) { |
| return; |
| } else if (reporter.getProgressMonitor().isCanceled()) { |
| throw new OperationCanceledException(""); //$NON-NLS-1$ |
| } |
| } |
| |
| protected static boolean shouldForce(IResourceDelta delta) { |
| return ((delta == null) ? DEFAULT_FORCE : false); |
| } |
| |
| protected static boolean shouldForce(Object[] changedResources) { |
| return (((changedResources == null) || (changedResources.length == 0)) ? DEFAULT_FORCE : false); |
| } |
| |
| /** |
| * @deprecated. Will be removed in Milestone 3. Use ValidationOperation(project, boolean) |
| */ |
| public ValidationOperation(IProject project) { |
| this(project, DEFAULT_ASYNC, DEFAULT_FORCE); |
| } |
| |
| /** |
| * Internal. |
| */ |
| public ValidationOperation(IProject project, boolean force, boolean async) { |
| this(project, null, null, RegistryConstants.ATT_RULE_GROUP_DEFAULT, force, async); |
| } |
| |
| /** |
| * @deprecated. Will be removed in Milestone 3. Use ValidationOperation(project, int, boolean) |
| */ |
| public ValidationOperation(IProject project, int ruleGroup) { |
| this(project, null, null, ruleGroup, DEFAULT_FORCE, DEFAULT_ASYNC); |
| } |
| |
| /** |
| * @deprecated. Will be removed in Milestone 3. Use ValidationOperation(IProject, |
| * IResourceDelta, Boolean, int, boolean, boolean) |
| */ |
| public ValidationOperation(IProject project, IResourceDelta delta, boolean isAutoBuild, int ruleGroup, boolean force, boolean fork) { |
| this(project, delta, ((isAutoBuild) ? Boolean.TRUE : Boolean.FALSE), ruleGroup, fork, force); |
| } |
| |
| /** |
| * Internal. |
| */ |
| protected ValidationOperation(IProject project, IResourceDelta delta, Boolean isAutoBuild, int ruleGroup, boolean force, boolean fork) { |
| super(); |
| _project = project; |
| _delta = delta; |
| _isAutoBuild = isAutoBuild; |
| _ruleGroup = ruleGroup; |
| _fork = fork; |
| _force = force; |
| _enabledValidators = new HashSet(); |
| } |
| |
| /** |
| * @deprecated Will be removed in Milestone 3. |
| */ |
| protected void terminateCleanup(WorkbenchReporter reporter) { |
| Set enabledValidators = getEnabledValidators(); |
| Iterator iterator = enabledValidators.iterator(); |
| ValidatorMetaData vmd = null; |
| try { |
| while (iterator.hasNext()) { |
| vmd = (ValidatorMetaData) iterator.next(); |
| reporter.displaySubtask(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_VALIDATOR_CLEANUP, new String[]{vmd.getValidatorDisplayName()})); |
| try { |
| reporter.removeAllMessages(vmd.getValidator()); |
| } catch (InstantiationException exc) { |
| // Remove the vmd from the reader's list |
| ValidationRegistryReader.getReader().disableValidator(vmd); |
| // Log the reason for the disabled validator |
| final Logger logger = ValidationPlugin.getPlugin().getMsgLogger(); |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation::terminateCleanup"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| } |
| continue; |
| } |
| addCancelTask(vmd); |
| reporter.displaySubtask(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_VALIDATOR_TERMINATED, new String[]{getProject().getName(), vmd.getValidatorDisplayName()})); |
| } |
| } catch (MessageLimitException e) { |
| ValidatorManager.getManager().addMessageLimitExceeded(getProject()); |
| } |
| } |
| |
| /** |
| * @deprecated Will be removed in Milestone 3. Should not be called outside of the validation |
| * framework. |
| */ |
| protected final void launchValidator(WorkbenchReporter reporter, ValidatorMetaData vmd, IWorkbenchHelper helper, IFileDelta[] delta) { |
| if (reporter == null) { |
| return; |
| } |
| checkCanceled(reporter); |
| Logger logger = ValidationPlugin.getPlugin().getMsgLogger(); |
| // Check to see if a full build must be performed, or if a delta |
| // build is to be performed, if there are files to verify for that |
| // validator. (If it's delta, but there are no files, calling |
| // validate on that validator starts a full build, instead of just |
| // returning.) |
| try { |
| // Validate the resource; this step will add errors/warnings to the |
| // task list, and remove errors/warnings from the task list. |
| if (helper instanceof AWorkbenchHelper) { |
| // Initialize the "loadRuleGroup" method with the group of |
| // rules |
| // which the validator should validate. |
| ((AWorkbenchHelper) helper).setRuleGroup(getRuleGroup()); |
| } |
| long start = System.currentTimeMillis(); |
| String message = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_STARTING_VALIDATION, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(message); |
| ValidatorLauncher.getLauncher().start(helper, vmd.getValidator(), reporter, delta); |
| if (logger.isLoggingLevel(Level.INFO)) { |
| logValidationInfo(vmd, delta, logger, start); |
| } |
| message = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_ENDING_VALIDATION, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(message); |
| } catch (MessageLimitException exc) { |
| throw exc; |
| } catch (OperationCanceledException exc) { |
| throw exc; |
| } catch (ValidationException exc) { |
| handleValidationExceptions(reporter, vmd, logger, exc); |
| } catch (Throwable exc) { |
| handleThrowables(reporter, vmd, logger, exc); |
| } finally { |
| try { |
| vmd.getValidator().cleanup(reporter); |
| } catch (MessageLimitException e) { |
| throw e; |
| } catch (OperationCanceledException e) { |
| throw e; |
| } catch (Throwable exc) { |
| handleThrowables(reporter, vmd, logger, exc); |
| return; |
| } |
| try { |
| helper.cleanup(reporter); |
| } catch (MessageLimitException e) { |
| throw e; |
| } catch (Throwable exc) { |
| handleHelperCleanupExceptions(reporter, vmd, logger, exc); |
| return; |
| } finally { |
| // Now that cleanup has been called, set the project to null. |
| // This project's |
| // resources have been freed so this project should also be |
| // cleared on the helper. |
| // If it isn't set to null, then the next time that the helper |
| // is retrieved from |
| // the ValidatorMetaData, the resources allocated for this |
| // project, in the |
| // helper's initialize method, will not be reallocated if the |
| // project is the same. |
| helper.setProject(null); |
| } |
| // Tell the progress monitor that we've completed n units of work |
| // (i.e., n resources validated by one validator). |
| reporter.getProgressMonitor().worked(delta.length); // One unit of |
| // work = 1 |
| // (i.e., 1 |
| // resource) |
| } |
| } |
| |
| /** |
| * @param vmd |
| * @param delta |
| * @param logger |
| * @param start |
| */ |
| private void logValidationInfo(ValidatorMetaData vmd, IFileDelta[] delta, Logger logger, long start) { |
| long finish = System.currentTimeMillis(); |
| TimeEntry entry = ValidationPlugin.getTimeEntry(); |
| entry.setSourceID("ValidationOperation.launchValidator"); //$NON-NLS-1$ |
| entry.setProjectName(getProject().getName()); |
| entry.setToolName(vmd.getValidatorUniqueName()); |
| entry.setElapsedTime(finish - start); |
| if (logger.isLoggingLevel(Level.FINE)) { |
| StringBuffer buffer = new StringBuffer(); |
| if (isFullValidate()) { |
| buffer.append("EVERYTHING"); //$NON-NLS-1$ |
| } else { |
| if (delta.length == 0) { |
| buffer.append("NOTHING"); //$NON-NLS-1$ |
| } else { |
| buffer.append(getDeltaAsString(delta)); |
| } |
| } |
| entry.setDetails(buffer.toString()); |
| } |
| logger.write(Level.INFO, entry); |
| } |
| |
| /** |
| * @param reporter |
| * @param vmd |
| * @param logger |
| * @param exc |
| */ |
| private void handleThrowables(WorkbenchReporter reporter, ValidatorMetaData vmd, Logger logger, Throwable exc) { |
| // If a runtime exception has occured, e.g. NullPointer or ClassCast, |
| // display it with the "A runtime exception has occurred " messsage. |
| // This will provide more information to the user when he/she calls IBM |
| // Service. |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation::launchValidator"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| } |
| String[] msgParm = {exc.getClass().getName(), vmd.getValidatorDisplayName(), (exc.getMessage() == null ? "" : exc.getMessage())}; //$NON-NLS-1$ |
| Message message = ValidationPlugin.getMessage(); |
| message.setSeverity(SeverityEnum.NORMAL_SEVERITY); |
| message.setId(ResourceConstants.VBF_EXC_RUNTIME); |
| message.setParams(msgParm); |
| try { |
| reporter.addMessage(vmd.getValidator(), message); |
| } catch (InstantiationException exc2) { |
| handleInstantiationException(vmd, logger, exc2); |
| } catch (MessageLimitException e) { |
| throw e; |
| } |
| return; |
| } |
| |
| /** |
| * @param vmd |
| * @param logger |
| * @param exc2 |
| */ |
| private void handleInstantiationException(ValidatorMetaData vmd, Logger logger, InstantiationException exc2) { |
| // Remove the vmd from the reader's list |
| ValidationRegistryReader.getReader().disableValidator(vmd); |
| // Log the reason for the disabled validator |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation::launchValidator (deprecated)"); //$NON-NLS-1$ |
| entry.setTargetException(exc2); |
| logger.write(Level.SEVERE, entry); |
| } |
| } |
| |
| /** |
| * @param reporter |
| * @param vmd |
| * @param logger |
| * @param exc |
| */ |
| private void handleValidationExceptions(WorkbenchReporter reporter, ValidatorMetaData vmd, Logger logger, ValidationException exc) { |
| // First, see if a validator just caught all Throwables and |
| // accidentally wrapped a MessageLimitException instead of propagating |
| // it. |
| if (exc.getAssociatedException() != null) { |
| if (exc.getAssociatedException() instanceof MessageLimitException) { |
| MessageLimitException mssgExc = (MessageLimitException) exc.getAssociatedException(); |
| throw mssgExc; |
| } else if (exc.getAssociatedException() instanceof ValidationException) { |
| try { |
| ValidationException vexc = (ValidationException) exc.getAssociatedException(); |
| vexc.setClassLoader(vmd.getValidator().getClass().getClassLoader()); // first, |
| // set the class loader,so that the exception's getMessage() method can retrieve |
| // the resource bundle |
| } catch (InstantiationException exc2) { |
| handleInstantiationException(vmd, logger, exc2); |
| } |
| } |
| } |
| // If there is a problem with this particular validator, log the error |
| // and continue |
| // with the next validator. |
| try { |
| exc.setClassLoader(vmd.getValidator().getClass().getClassLoader()); // first, |
| // set the class loader,so that the exception's getMessage() method can retrieve the |
| // resource bundle |
| } catch (InstantiationException exc2) { |
| handleInstantiationException(vmd, logger, exc2); |
| } |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation.validate(WorkbenchMonitor)"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| if (exc.getAssociatedException() != null) { |
| entry.setTargetException(exc.getAssociatedException()); |
| logger.write(Level.SEVERE, entry); |
| } |
| } |
| String message = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_ENDING_VALIDATION_ABNORMALLY, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(message); |
| if (exc.getAssociatedMessage() != null) { |
| try { |
| reporter.addMessage(vmd.getValidator(), exc.getAssociatedMessage()); |
| } catch (InstantiationException exc2) { |
| handleInstantiationException(vmd, logger, exc2); |
| } |
| } |
| } |
| |
| /** |
| * @param reporter |
| * @param vmd |
| * @param logger |
| * @param exc |
| */ |
| private void handleHelperCleanupExceptions(WorkbenchReporter reporter, ValidatorMetaData vmd, Logger logger, Throwable exc) { |
| // If a runtime exception has occured, e.g. NullPointer or ClassCast, |
| // display it with the "A runtime exception has occurred " messsage. |
| // This will provide more information to the user when he/she calls IBM |
| // Service. |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation::launchValidator"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| } |
| String[] msgParm = {exc.getClass().getName(), vmd.getValidatorDisplayName(), (exc.getMessage() == null ? "" : exc.getMessage())}; //$NON-NLS-1$ |
| Message message = ValidationPlugin.getMessage(); |
| message.setSeverity(SeverityEnum.NORMAL_SEVERITY); |
| message.setId(ResourceConstants.VBF_EXC_RUNTIME); |
| message.setParams(msgParm); |
| try { |
| reporter.addMessage(vmd.getValidator(), message); |
| } catch (InstantiationException exc2) { |
| handleInstantiationException(vmd, logger, exc2); |
| } catch (MessageLimitException e) { |
| throw e; |
| } |
| return; |
| } |
| |
| public boolean isFork() { |
| return _fork; |
| } |
| |
| public boolean isForce() { |
| return _force; |
| } |
| |
| public void setForce(boolean force) { |
| _force = force; |
| } |
| |
| /** |
| * If the code that invoked this operation suspended auto-build before invoking this operation, |
| * the user's auto-build setting is stored in the following methods. |
| */ |
| public boolean isAutoBuild() { |
| if (_isAutoBuild == null) { |
| return ValidatorManager.getManager().isGlobalAutoBuildEnabled(); |
| } |
| return _isAutoBuild.booleanValue(); |
| } |
| |
| protected void setAutoBuild(boolean autoOn) { |
| _isAutoBuild = ((autoOn) ? Boolean.TRUE : Boolean.FALSE); |
| } |
| |
| protected boolean isFullValidate() { |
| return _isFullValidate; |
| } |
| |
| private void setFullValidate(boolean b) { |
| _isFullValidate = b; |
| } |
| |
| protected int getRuleGroup() { |
| return _ruleGroup; |
| } |
| |
| /** |
| * Return true if the given validator must run (i.e., it has changes to validate, and it was not |
| * run automatically.) |
| */ |
| private boolean isValidationNecessary(ValidatorMetaData vmd, IFileDelta[] delta) { |
| // Validation is not necessary if: |
| // 1. auto-validation has run and the validator is incremental, |
| // 2. There are no files for the validator to validate. |
| // There are files to validate if this is a full validation or if the |
| // validator filtered in some of the deltas. |
| boolean autoValidateRan = false; |
| if (_isAutoBuild != null) { |
| // User set the autoBuild default, so check if validation is |
| // necessary or not. |
| autoValidateRan = ValidatorManager.getManager().isAutoValidate(getProject(), _isAutoBuild.booleanValue()) && vmd.isIncremental(); |
| } |
| boolean hasFiles = (isFullValidate() || (delta.length > 0)); |
| return (!autoValidateRan && hasFiles); |
| } |
| |
| /** |
| * Return true if, given the enabled validators and file deltas, there is work for this |
| * operation to do. |
| */ |
| public boolean isNecessary(IProgressMonitor monitor) throws CoreException, OperationCanceledException { |
| Set enabledValidators = getEnabledValidators(); |
| if ((enabledValidators == null) || (enabledValidators.size() == 0)) { |
| return false; |
| } |
| if (isFullValidate()) { |
| return true; |
| } |
| Iterator iterator = enabledValidators.iterator(); |
| while (iterator.hasNext()) { |
| ValidatorMetaData vmd = (ValidatorMetaData) iterator.next(); |
| if (isValidationNecessary(vmd, getFileDeltas(monitor, vmd))) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private Map getFileDeltas(IProgressMonitor monitor) throws CoreException { |
| if (_fileDeltas == null) { |
| loadFileDeltas(monitor); |
| } |
| return _fileDeltas; |
| } |
| |
| private IFileDelta[] getFileDeltas(IProgressMonitor monitor, ValidatorMetaData vmd) throws CoreException { |
| Set result = (Set) getFileDeltas(monitor).get(vmd); |
| if (result == null) { |
| return new IFileDelta[0]; |
| } |
| IFileDelta[] temp = new IFileDelta[result.size()]; |
| result.toArray(temp); |
| return temp; |
| } |
| |
| /** |
| * Store the file deltas (VMD <=>Set[IFileDelta]) if the file deltas haven't been loaded. If the |
| * deltas have already been loaded, return without doing anything. |
| */ |
| private void loadFileDeltas(IProgressMonitor monitor) throws CoreException { |
| // Although, for a full build, we don't build up a list of changed |
| // files, we do need to notify each IWorkbenchHelper that an |
| // IResource has been filtered in. |
| // It's a full validation if the IResourceDelta is null and the |
| // Object[] (or IResource[]) is also null. |
| // i.e., it's a full validation if no incremental input has been set. |
| setFullValidate((getDelta() == null) && (_fileDeltas == null)); |
| if (isFullValidate()) { |
| _fileDeltas = FilterUtil.loadDeltas(monitor, getEnabledValidators(), getProject()); |
| } else { |
| _fileDeltas = FilterUtil.loadDeltas(monitor, getEnabledValidators(), getDelta()); // traverse, |
| // and process, each resource in the delta tree |
| } |
| } |
| |
| protected void setFileDeltas(Map deltas) { |
| _fileDeltas = deltas; |
| } |
| |
| protected IResourceDelta getDelta() { |
| return _delta; |
| } |
| |
| protected void setDelta(IResourceDelta delta) { |
| _delta = delta; |
| } |
| |
| protected boolean areValidatorsEnabled() { |
| return (getEnabledValidators().size() != 0); |
| } |
| |
| /** |
| * Return the validators which are both configured on this type of project, (as stored in |
| * getProject()), and enabled by the user on this project. |
| */ |
| public Set getEnabledValidators() { |
| return _enabledValidators; |
| } |
| |
| /** |
| * This is an internal method, subject to change without notice. It is provided only for the |
| * automated validation framework tests. |
| */ |
| public Set getLaunchedValidators() { |
| if (_launchedValidators == null) { |
| _launchedValidators = new HashSet(); |
| } |
| return _launchedValidators; |
| } |
| |
| protected void setEnabledValidators(Set evmds) { |
| // Check that every VMD in the set is configured on this project. |
| // Necessary because the user can manually choose which validators |
| // to launch, and the validator may not be installed. |
| _enabledValidators.clear(); |
| Iterator iterator = evmds.iterator(); |
| while (iterator.hasNext()) { |
| ValidatorMetaData vmd = (ValidatorMetaData) iterator.next(); |
| if (ValidationRegistryReader.getReader().isConfiguredOnProject(vmd, getProject())) { |
| _enabledValidators.add(vmd); |
| } |
| } |
| } |
| |
| /** |
| * This method returns the IProject that this ValidationOperation was created with. |
| */ |
| public IProject getProject() { |
| return _project; |
| } |
| |
| protected int getUnitsOfWork() { |
| /* |
| * // Let one unit of work equal one resource. number of enabled validators // i.e., each |
| * enabled validator must process (at most) each resource in the project; count each process |
| * as one unit of work // Note that this is a ceiling number, because if we're doing an |
| * incremental validation, not all resources will // be validated. |
| * setNumResources(countResources(getProject())); getEnabledValidators().size(); |
| */ |
| // Until the validators can report units-of-work complete, |
| // initialize the monitor with an unknown amount of work. |
| // (So the user will see movement in the progress bar, even |
| // if the movement doesn't indicate the amount of work done.) |
| return IProgressMonitor.UNKNOWN; |
| } |
| |
| /** |
| * If the user is cancelling validation on the current project/resource, Add an information task |
| * to the task list informing the user that validation has not been run on the current project. |
| */ |
| protected void addCancelTask(ValidatorMetaData vmd) { |
| InternalValidatorManager.getManager().addOperationTask(getProject(), vmd, ResourceConstants.VBF_STATUS_VALIDATOR_TERMINATED, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| } |
| |
| /** |
| * This method starts the validation of each configured enabled validator on the current |
| * project. |
| * |
| * The IProgressMonitor passed in must not be null. |
| */ |
| public void run(IProgressMonitor progressMonitor) throws OperationCanceledException { |
| long start = System.currentTimeMillis(); |
| final Logger logger = ValidationPlugin.getPlugin().getMsgLogger(); |
| try { |
| // In order to check whether or not the monitor has been cancelled, |
| // the monitor must not be null. |
| if (progressMonitor == null) { |
| return; |
| } |
| if (ValidatorManager.getManager().isSuspended(getProject())) { |
| return; |
| } |
| if (!areValidatorsEnabled()) { |
| // save some processing time... |
| return; |
| } |
| if (ValidatorManager.getManager().getMaximumMessagesAllowed(getProject()) == 0) { |
| // save some processing time |
| return; |
| } |
| final WorkbenchReporter reporter = new WorkbenchReporter(getProject(), progressMonitor); |
| |
| try { |
| // Periodically check if the user has cancelled the operation |
| checkCanceled(reporter); |
| preValidate(reporter); |
| validate(reporter); |
| validateReferencialFiles(reporter); |
| } catch (CoreException exc) { |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation.run"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| } |
| } |
| } finally { |
| if (logger.isLoggingLevel(Level.FINE)) { |
| long finish = System.currentTimeMillis(); |
| TimeEntry entry = ValidationPlugin.getTimeEntry(); |
| entry.setSourceID("ValidationOperation.run(WorkbenchMonitor)"); //$NON-NLS-1$ |
| entry.setProjectName(getProject().getName()); |
| entry.setToolName("ValidationOperation"); //$NON-NLS-1$ |
| entry.setElapsedTime(finish - start); |
| logger.write(Level.FINE, entry); |
| } |
| } |
| } |
| |
| /** |
| * @param reporter |
| */ |
| private void validateReferencialFiles(WorkbenchReporter reporter) { |
| ReferencialFileValidatorRegistryReader reader = ReferencialFileValidatorRegistryReader.getInstance(); |
| if (reader != null) { |
| reader.readRegistry(); |
| ReferencialFileValidator refFileValidator = reader.getReferencialFileValidator(); |
| if (refFileValidator != null) { |
| if (_delta != null) { |
| refFileValidateFileDelta(reporter, refFileValidator); |
| } else if (_project != null) { |
| postValidateProject(reporter, refFileValidator); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @param reporter |
| * @param referencialFileValidator |
| */ |
| private void refFileValidateFileDelta(WorkbenchReporter reporter, ReferencialFileValidator refFileValidator) { |
| IResourceDelta[] resourceDelta = _delta.getAffectedChildren(IResourceDelta.ADDED | IResourceDelta.CHANGED | IResourceDelta.REMOVED); |
| List inputFiles = new ArrayList(); |
| List referencingFiles = new ArrayList(); |
| if (resourceDelta != null && resourceDelta.length > 0) { |
| for (int i = 0; i < resourceDelta.length; i++) { |
| IResource resource = resourceDelta[i].getResource(); |
| if (resource instanceof IFolder) { |
| getFileResourceDeltaInFolder(resourceDelta[i], inputFiles); |
| } else if (resource instanceof IFile) |
| inputFiles.add(resource); |
| } |
| List rFilesToValidate = refFileValidator.getReferencedFile(inputFiles); |
| if (rFilesToValidate != null && !rFilesToValidate.isEmpty()) |
| referencingFiles.addAll(rFilesToValidate); |
| try { |
| if (!referencingFiles.isEmpty()) |
| validateReferencingFiles(reporter, referencingFiles); |
| } catch (Exception e) { |
| Logger.getLogger().log(e); |
| } |
| } |
| } |
| |
| /** |
| * @param delta |
| * @return |
| */ |
| private void getFileResourceDeltaInFolder(IResourceDelta delta, List inputFiles) { |
| IResourceDelta[] resourceDelta = delta.getAffectedChildren(); |
| for (int i = 0; i < resourceDelta.length; i++) { |
| IResource resource = resourceDelta[i].getResource(); |
| if (resource instanceof IFile) { |
| inputFiles.add(resource); |
| } else if (resource instanceof IFolder) |
| getFileResourceDeltaInFolder(resourceDelta[i], inputFiles); |
| } |
| } |
| |
| /** |
| * @param reporter |
| * @param referencialFileValidator |
| */ |
| private void postValidateProject(WorkbenchReporter reporter, ReferencialFileValidator refFileValidator) { |
| Set set = ValidationRegistryReader.getReader().getValidatorMetaData(_project); |
| Iterator it = set.iterator(); |
| while (it.hasNext()) { |
| ValidatorMetaData data = (ValidatorMetaData) it.next(); |
| List filters = data.getNameFilters(); |
| List files = getAllFilesForFilter(filters); |
| if (!files.isEmpty()) { |
| List fileForValidation = refFileValidator.getReferencedFile(files); |
| try { |
| validateReferencingFiles(reporter, fileForValidation); |
| } catch (Exception e) { |
| Logger.getLogger().log(e); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @param filters |
| * @return |
| */ |
| private List getAllFilesForFilter(List filters) { |
| if (!filters.isEmpty()) { |
| List allProjectFiles = ReferencialFileValidatorHelper.getAllProjectFiles(_project); |
| List filterFiles = new ArrayList(); |
| for (int i = 0; i < filters.size(); i++) { |
| String fileName = (String) filters.get(i); |
| if (fileName == null) |
| continue; |
| for (int j = 0; j < allProjectFiles.size(); j++) { |
| IFile projectFile = (IFile) allProjectFiles.get(j); |
| if (fileName.charAt(0) == '*') { |
| String extName = fileName.substring(2, fileName.length()); |
| String ext = projectFile.getFileExtension(); |
| if (ext != null && ext.equals(extName)) |
| filterFiles.add(projectFile); |
| } else if (fileName.equals(projectFile.getName())) |
| filterFiles.add(projectFile); |
| } |
| |
| } |
| return filterFiles; |
| } |
| return Collections.EMPTY_LIST; |
| } |
| |
| private void validateReferencingFiles(IReporter reporter, List referencingFiles) throws Exception { |
| HashSet validatedFiles = new HashSet(); |
| for (int i = 0; i < referencingFiles.size(); i++) { |
| IFile refFile = (IFile) referencingFiles.get(i); |
| if (!validatedFiles.contains(refFile)) { |
| IResource resource = refFile.getParent(); |
| IProject project = null; |
| if (resource != null && !(resource instanceof IProject)) |
| project = getProjectContainer(resource); |
| else |
| project = (IProject) resource; |
| if (project != null) { |
| Set set = ValidationRegistryReader.getReader().getValidatorMetaData(project); |
| IFileDelta[] changedfiles = new FileDelta[]{new WorkbenchFileDelta(refFile.getProjectRelativePath().toString(), IFileDelta.CHANGED, refFile)}; |
| Iterator it = set.iterator(); |
| while (it.hasNext()) { |
| ValidatorMetaData data = (ValidatorMetaData) it.next(); |
| if (data.isApplicableTo(refFile)) { |
| IValidator validator = data.getValidator(); |
| validator.validate(data.getHelper(project), reporter, changedfiles); |
| validatedFiles.add(refFile); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private IProject getProjectContainer(IResource resource) { |
| IResource pResource = resource.getParent(); |
| if (!(pResource instanceof IProject)) |
| return getProjectContainer(pResource); |
| return (IProject) pResource; |
| } |
| |
| protected void preValidate(WorkbenchReporter reporter) throws CoreException, OperationCanceledException { |
| // Load the input. |
| getFileDeltas(reporter.getProgressMonitor()); |
| } |
| |
| /** |
| * Iterate over all of the enabled validators and run the thread-safe validators in a background |
| * thread, and the not-thread-safe validators in this thread. |
| */ |
| protected void validate(WorkbenchReporter reporter) throws OperationCanceledException { |
| if (reporter == null) { |
| return; |
| } |
| checkCanceled(reporter); |
| reporter.getProgressMonitor().beginTask(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_PROGRESSMONITOR_TITLE), getUnitsOfWork()); |
| IWorkbenchHelper helper = null; |
| IValidator validator = null; |
| ValidatorMetaData vmd = null; |
| Iterator iterator = null; |
| WorkbenchReporter nullReporter = new WorkbenchReporter(getProject(), new NullProgressMonitor()); |
| final Logger logger = ValidationPlugin.getPlugin().getMsgLogger(); |
| IFileDelta[] delta = null; |
| try { |
| iterator = getEnabledValidators().iterator(); |
| // In order to allow validators to run, must first check if there's |
| // space for new markers. |
| // But we don't want the old markers to prevent validation from |
| // running again, so delete all |
| // of the old markers first, and then run validation. |
| while (iterator.hasNext()) { |
| vmd = (ValidatorMetaData) iterator.next(); |
| // Is validation about to be run on this validator? |
| // Validation will run either if this operation forces |
| // regardless |
| // of need, or if the validator was not run automatically. |
| // If validation is not about to be run, then don't activate |
| // the plugin |
| try { |
| delta = getFileDeltas(reporter.getProgressMonitor(), vmd); |
| boolean willRun = (isForce() || isValidationNecessary(vmd, delta)); |
| if (logger.isLoggingLevel(Level.FINEST)) { |
| TimeEntry entry = ValidationPlugin.getTimeEntry(); |
| entry.setSourceID("ValidationOperation.validate(WorkbenchReporter)"); //$NON-NLS-1$ |
| entry.setProjectName(getProject().getName()); |
| entry.setToolName(vmd.getValidatorUniqueName()); |
| entry.setElapsedTime(0); |
| StringBuffer buffer = new StringBuffer(); |
| buffer.append("will run? "); //$NON-NLS-1$ |
| buffer.append(willRun); |
| buffer.append(" "); //$NON-NLS-1$ |
| buffer.append("is force? "); //$NON-NLS-1$ |
| buffer.append(isForce()); |
| buffer.append(" "); //$NON-NLS-1$ |
| buffer.append("isAutoBuild? "); //$NON-NLS-1$ |
| buffer.append(_isAutoBuild); |
| buffer.append(" "); //$NON-NLS-1$ |
| buffer.append("isAutoValidate? "); //$NON-NLS-1$ |
| boolean autoBuild = (_isAutoBuild == null) ? ValidatorManager.getManager().isGlobalAutoBuildEnabled() : _isAutoBuild.booleanValue(); |
| buffer.append(ValidatorManager.getManager().isAutoValidate(getProject(), autoBuild)); |
| buffer.append(" "); //$NON-NLS-1$ |
| buffer.append("isIncremental? "); //$NON-NLS-1$ |
| buffer.append(vmd.isIncremental()); |
| buffer.append(" "); //$NON-NLS-1$ |
| if (isFullValidate()) { |
| buffer.append("EVERYTHING"); //$NON-NLS-1$ |
| } else { |
| if (delta.length == 0) { |
| buffer.append("NOTHING"); //$NON-NLS-1$ |
| } else { |
| buffer.append(getDeltaAsString(delta)); |
| } |
| } |
| entry.setDetails(buffer.toString()); |
| logger.write(Level.FINEST, entry); |
| } |
| if (!willRun) { |
| continue; |
| } |
| } catch (CoreException exc) { |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation.validate(WorkbenchReporter)"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| } |
| String mssg = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_ENDING_VALIDATION_ABNORMALLY, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(mssg); |
| String[] msgParm = {exc.getClass().getName(), vmd.getValidatorDisplayName(), (exc.getMessage() == null ? "" : exc.getMessage())}; //$NON-NLS-1$ |
| Message message = ValidationPlugin.getMessage(); |
| message.setSeverity(SeverityEnum.NORMAL_SEVERITY); |
| message.setId(ResourceConstants.VBF_EXC_RUNTIME); |
| message.setParams(msgParm); |
| reporter.addMessage(validator, message); |
| continue; |
| } |
| try { |
| helper = vmd.getHelper(getProject()); |
| validator = vmd.getValidator(); |
| } catch (InstantiationException exc) { |
| // Remove the vmd from the reader's list |
| ValidationRegistryReader.getReader().disableValidator(vmd); |
| // Log the reason for the disabled validator |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation::validate(WorkbenchReporter)"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| } |
| continue; |
| } |
| if (isFork() && vmd.isAsync()) { |
| // Don't appear to run in the foreground by sending |
| // progress to the IProgressMonitor in the |
| // WorkbenchMonitor. Suppress the status messages by |
| // changing the IProgressMonitor to a |
| // NullProgressMonitor. |
| VThreadManager.getManager().queue(wrapInRunnable(nullReporter, validator, vmd, helper, delta, iterator)); |
| } else { |
| internalValidate(reporter, validator, vmd, helper, delta); |
| } |
| } |
| } catch (OperationCanceledException exc) { |
| handleOperationCancelledValidateException(reporter, validator, vmd, iterator, logger, exc); |
| } |
| } |
| |
| /** |
| * @param reporter |
| * @param validator |
| * @param vmd |
| * @param iterator |
| * @param logger |
| * @param exc |
| */ |
| private void handleOperationCancelledValidateException(WorkbenchReporter reporter, IValidator validator, ValidatorMetaData vmd, Iterator iterator, final Logger logger, OperationCanceledException exc) { |
| /* |
| * If the user terminates validation (i.e., presses "cancel" on the progress monitor) before |
| * the validation completes, perform clean up on each configured enabled validator. |
| * |
| * To clean up, several steps are performed: 1. call <code></code> on each configured |
| * enabled validator, so that each validator can perform cleanup that it knows is necessary. |
| * 2. remove all tasks that this validator has added to the task list 3. add another task to |
| * the task list to say that validation, using this validator on this project, was |
| * terminated. |
| * |
| * Steps 2 and 3 are done so that it's clear what has, and has not, been validated. If these |
| * steps weren't performed, validation could be done on some items in the project, but not |
| * others; and the user could mistakenly believe that those are the only problems with the |
| * project. Unless the user knows that a full verification needs to be done, he/she could |
| * continue to rely on automatic verification, and never know that there are problems with a |
| * resource which hasn't been validated. |
| */ |
| reporter.displaySubtask(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_VALIDATOR_CLEANUP, new String[]{vmd.getValidatorDisplayName()})); |
| reporter.removeAllMessages(validator); |
| addCancelTask(vmd); |
| reporter.displaySubtask(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_VALIDATOR_TERMINATED, new String[]{getProject().getName(), vmd.getValidatorDisplayName()})); |
| while (iterator.hasNext()) { |
| vmd = (ValidatorMetaData) iterator.next(); |
| try { |
| validator = vmd.getValidator(); |
| } catch (InstantiationException exc2) { |
| // Remove the vmd from the reader's list |
| ValidationRegistryReader.getReader().disableValidator(vmd); |
| // Log the reason for the disabled validator |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation::validate(WorkbenchReporter)"); //$NON-NLS-1$ |
| entry.setTargetException(exc2); |
| logger.write(Level.SEVERE, entry); |
| } |
| continue; |
| } |
| reporter.displaySubtask(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_VALIDATOR_CLEANUP, new String[]{vmd.getValidatorDisplayName()})); |
| reporter.removeAllMessages(validator); |
| addCancelTask(vmd); |
| reporter.displaySubtask(ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_VALIDATOR_TERMINATED, new String[]{getProject().getName(), vmd.getValidatorDisplayName()})); |
| } |
| throw exc; // propagate the exception up to the framework so that |
| // the framework can display the correct "cancelled" |
| // message in the dialog |
| |
| } |
| |
| /* package */ |
| void internalValidate(final WorkbenchReporter reporter, final IValidator validator, final ValidatorMetaData vmd, final IWorkbenchHelper helper, final IFileDelta[] delta) throws OperationCanceledException { |
| final Logger logger = ValidationPlugin.getPlugin().getMsgLogger(); |
| try { |
| checkCanceled(reporter); |
| removeOldMessages(reporter, validator, vmd, delta); |
| // Do NOT check if the message limit is exceeded before launching |
| // the validator. |
| // Even if the limit is exceeded when the messages are removed from |
| // the delta |
| // files, it could be that the validator itself will remove |
| // messages before |
| // proceeding. Let the validator run so that it can remove messages |
| // if it |
| // needs to, and if it tries to add a message when the limit is |
| // exceeded, let |
| // the WorkbenchReporter take care of it. |
| launchValidator(reporter, validator, vmd, helper, delta); |
| } catch (OperationCanceledException exc) { |
| // This is handled in the validate(WorkbenchReporter) method. |
| throw exc; |
| } catch (MessageLimitException exc) { |
| // Let the finally block handle this case. |
| // handleMessageLimit(); |
| } catch (Throwable exc) { |
| // If there is a problem with this particular validator, log the |
| // error and continue |
| // with the next validator. |
| // If a runtime exception has occured, e.g. NullPointer or |
| // ClassCast, display it with the "A runtime exception has occurred |
| // " messsage. |
| // This will provide more information to the user when he/she calls |
| // IBM Service. |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation.internalValidate"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| } |
| String mssg = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_ENDING_VALIDATION_ABNORMALLY, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(mssg); |
| String[] msgParm = {exc.getClass().getName(), vmd.getValidatorDisplayName(), (exc.getMessage() == null ? "" : exc.getMessage())}; //$NON-NLS-1$ |
| Message message = ValidationPlugin.getMessage(); |
| message.setSeverity(SeverityEnum.NORMAL_SEVERITY); |
| message.setId(ResourceConstants.VBF_EXC_RUNTIME); |
| message.setParams(msgParm); |
| reporter.addMessage(validator, message); |
| } finally { |
| // If user fixes problem, and limit exceeded, add "exceeded" |
| // message, or |
| // if limit not exceeded any more, remove "exceeded" message. |
| ValidatorManager.getManager().checkMessageLimit(getProject(), true); |
| reporter.getProgressMonitor().done(); |
| } |
| } |
| |
| /** |
| * In order to allow validators to run, must first check if there's space for new markers. But |
| * the old markers must not prevent validation from running again (limit exceeded), so delete |
| * all of the old markers first, and then run validation. |
| */ |
| private final void removeOldMessages(WorkbenchReporter reporter, IValidator validator, ValidatorMetaData vmd, IFileDelta[] delta) { |
| if (reporter == null) { |
| return; |
| } |
| // If the validator has been enabled, remove the "cancel" task. |
| // If the validator, on the last run, threw a Throwable, remove the |
| // "internal error" task. (For the same reasons we remove the "cancel" |
| // task. |
| InternalValidatorManager.getManager().removeOperationTasks(getProject(), vmd); |
| checkCanceled(reporter); |
| Logger logger = ValidationPlugin.getPlugin().getMsgLogger(); |
| try { |
| // Check to see if a full build must be performed, or if a delta |
| // build is to be performed, if there are files to verify for that |
| // validator. (If it's delta, but there are no files, calling |
| // validate on that validator starts a full build, instead of just |
| // returning.) |
| if (isFullValidate()) { |
| String message = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_START_REMOVING_OLD_MESSAGES, new String[]{vmd.getValidatorDisplayName(), getProject().getName()}); |
| reporter.displaySubtask(message); |
| reporter.removeAllMessages(validator); |
| message = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_FINISH_REMOVING_OLD_MESSAGES, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(message); |
| } else { |
| // Don't need to check that there are deltas to validate |
| // because that's already checked in isValidationNecessary |
| String message = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_START_REMOVING_OLD_MESSAGES, new String[]{vmd.getValidatorDisplayName(), getProject().getName()}); |
| reporter.displaySubtask(message); |
| for (int i = 0; i < delta.length; i++) { |
| WorkbenchFileDelta fd = (WorkbenchFileDelta) delta[i]; |
| if (fd.getDeltaType() != IFileDelta.DELETED) { |
| // If the file has been deleted, eclipse erases all |
| // markers on the file. |
| // Also, when a resource doesn't exist, |
| // WorkbenchReporter's getMessageResource() |
| // returns the IProject, which means that removing the |
| // messages from this |
| // file removes all of this validator's messages on |
| // this IProject (aix defect 206157) |
| IResource resource = reporter.getMessageResource(validator, fd); |
| if (fd.getObject().equals(fd.getResource())) { |
| WorkbenchReporter.removeAllMessages(resource, validator); // remove |
| // all |
| // messages |
| // from |
| // this |
| // resource |
| } else { |
| reporter.removeAllMessages(validator, fd.getObject()); |
| } |
| } |
| } |
| message = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_FINISH_REMOVING_OLD_MESSAGES, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(message); |
| } |
| } catch (OperationCanceledException exc) { |
| throw exc; |
| } catch (Throwable exc) { |
| // If there is a problem with this particular validator, log the |
| // error and continue |
| // with the next validator. |
| // If a runtime exception has occured, e.g. NullPointer or |
| // ClassCast, display it with the "A runtime exception has occurred |
| // " messsage. |
| // This will provide more information to the user when he/she calls |
| // IBM Service. |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation.validate(WorkbenchMonitor)"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| } |
| String mssg = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_ENDING_VALIDATION_ABNORMALLY, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(mssg); |
| String[] msgParm = {exc.getClass().getName(), vmd.getValidatorDisplayName(), (exc.getMessage() == null ? "" : exc.getMessage())}; //$NON-NLS-1$ |
| Message message = ValidationPlugin.getMessage(); |
| message.setSeverity(SeverityEnum.NORMAL_SEVERITY); |
| message.setId(ResourceConstants.VBF_EXC_RUNTIME); |
| message.setParams(msgParm); |
| reporter.addMessage(validator, message); |
| return; |
| } |
| } |
| |
| /** |
| * Whether a full verification or a delta verification is in progress, both will call this |
| * method to process the resource. This method calls the current Validator to filter the |
| * resource (i.e., this method returns if the resource fails the filter test). |
| * <code>process</code> also sends output to the <code>IProgressMonitor</code>, and calls |
| * the current Validator to validate the resource. |
| * |
| * To process a resource, there are several steps: 1. check if the resource is registered for |
| * this validator (i.e., the validator has either specified it in a filter, or has not filtered |
| * it out explicitly) 2. call <code>isValidationSource</code> on the current validator with |
| * the current resource. This method performs further filtering by the Validator itself, in |
| * addition to the static filtering done by the framework, based on the information in |
| * plugin.xml. 3. If the resource passes both filters, call <code>validate</code> on the |
| * validator, with the resource. 4. When complete (either by failing to pass a filter, or by the |
| * completion of the <code>validate</code>), increment the IProgressMonitor's status by one |
| * (i.e., one resource has been processed.) |
| */ |
| private final void launchValidator(WorkbenchReporter reporter, IValidator validator, ValidatorMetaData vmd, IWorkbenchHelper helper, IFileDelta[] delta) { |
| if (reporter == null) { |
| return; |
| } |
| checkCanceled(reporter); |
| Logger logger = ValidationPlugin.getPlugin().getMsgLogger(); |
| // Check to see if a full build must be performed, or if a delta |
| // build is to be performed, if there are files to verify for that |
| // validator. (If it's delta, but there are no files, calling |
| // validate on that validator starts a full build, instead of just |
| // returning.) |
| try { |
| // Validate the resource; this step will add errors/warnings to the |
| // task list, and remove errors/warnings from the task list. |
| if (helper instanceof AWorkbenchHelper) { |
| // Initialize the "loadRuleGroup" method with the group of |
| // rules |
| // which the validator should validate. |
| ((AWorkbenchHelper) helper).setRuleGroup(getRuleGroup()); |
| } |
| long start = System.currentTimeMillis(); |
| String message = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_STARTING_VALIDATION, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(message); |
| if (logger.isLoggingLevel(Level.FINEST)) { |
| // This internal "launched validators" value is used only in |
| // tests. |
| getLaunchedValidators().add(vmd); |
| } |
| ValidatorLauncher.getLauncher().start(helper, validator, reporter, delta); |
| long finish = System.currentTimeMillis(); |
| if (logger.isLoggingLevel(Level.INFO)) { |
| TimeEntry entry = ValidationPlugin.getTimeEntry(); |
| entry.setSourceID("ValidationOperation.launchValidator"); //$NON-NLS-1$ |
| entry.setProjectName(getProject().getName()); |
| entry.setToolName(vmd.getValidatorUniqueName()); |
| entry.setElapsedTime(finish - start); |
| if (logger.isLoggingLevel(Level.FINE)) { |
| StringBuffer buffer = new StringBuffer(); |
| if (isFullValidate()) { |
| buffer.append("EVERYTHING"); //$NON-NLS-1$ |
| } else { |
| if (delta.length == 0) { |
| buffer.append("NOTHING"); //$NON-NLS-1$ |
| } else { |
| buffer.append(getDeltaAsString(delta)); |
| } |
| } |
| entry.setDetails(buffer.toString()); |
| } |
| logger.write(Level.INFO, entry); |
| } |
| message = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_ENDING_VALIDATION, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(message); |
| } catch (MessageLimitException exc) { |
| throw exc; |
| } catch (OperationCanceledException exc) { |
| throw exc; |
| } catch (ValidationException exc) { |
| // First, see if a validator just caught all Throwables and |
| // accidentally wrapped a MessageLimitException instead of |
| // propagating it. |
| if (exc.getAssociatedException() != null) { |
| if (exc.getAssociatedException() instanceof MessageLimitException) { |
| MessageLimitException mssgExc = (MessageLimitException) exc.getAssociatedException(); |
| throw mssgExc; |
| } else if (exc.getAssociatedException() instanceof ValidationException) { |
| ValidationException vexc = (ValidationException) exc.getAssociatedException(); |
| vexc.setClassLoader(validator.getClass().getClassLoader()); // first, |
| // set |
| // the |
| // class |
| // loader, |
| // so |
| // that |
| // the |
| // exception's |
| // getMessage() |
| // method |
| // can |
| // retrieve |
| // the |
| // resource |
| // bundle |
| } |
| } |
| // If there is a problem with this particular validator, log the |
| // error and continue |
| // with the next validator. |
| exc.setClassLoader(validator.getClass().getClassLoader()); // first, |
| // set |
| // the |
| // class |
| // loader, |
| // so |
| // that |
| // the |
| // exception's |
| // getMessage() |
| // method |
| // can |
| // retrieve |
| // the |
| // resource |
| // bundle |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation.validate(WorkbenchMonitor)"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| if (exc.getAssociatedException() != null) { |
| entry.setTargetException(exc.getAssociatedException()); |
| logger.write(Level.SEVERE, entry); |
| } |
| } |
| String message = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_ENDING_VALIDATION_ABNORMALLY, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(message); |
| if (exc.getAssociatedMessage() != null) { |
| reporter.addMessage(validator, exc.getAssociatedMessage()); |
| } |
| } catch (Throwable exc) { |
| // If there is a problem with this particular validator, log the |
| // error and continue |
| // with the next validator. |
| // If a runtime exception has occured, e.g. NullPointer or |
| // ClassCast, display it with the "A runtime exception has occurred |
| // " messsage. |
| // This will provide more information to the user when he/she calls |
| // IBM Service. |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation.validate(WorkbenchMonitor)"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| } |
| String mssg = ResourceHandler.getExternalizedMessage(ResourceConstants.VBF_STATUS_ENDING_VALIDATION_ABNORMALLY, new String[]{getProject().getName(), vmd.getValidatorDisplayName()}); |
| reporter.displaySubtask(mssg); |
| String[] msgParm = {exc.getClass().getName(), vmd.getValidatorDisplayName(), (exc.getMessage() == null ? "" : exc.getMessage())}; //$NON-NLS-1$ |
| Message message = ValidationPlugin.getMessage(); |
| message.setSeverity(SeverityEnum.NORMAL_SEVERITY); |
| message.setId(ResourceConstants.VBF_EXC_RUNTIME); |
| message.setParams(msgParm); |
| reporter.addMessage(validator, message); |
| } finally { |
| try { |
| validator.cleanup(reporter); |
| } catch (MessageLimitException e) { |
| throw e; |
| } catch (OperationCanceledException e) { |
| throw e; |
| } catch (Throwable exc) { |
| // If a runtime exception has occured, e.g. NullPointer or |
| // ClassCast, display it with the "A runtime exception has |
| // occurred " messsage. |
| // This will provide more information to the user when he/she |
| // calls IBM Service. |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation::launchValidator"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| } |
| String[] msgParm = {exc.getClass().getName(), vmd.getValidatorDisplayName(), (exc.getMessage() == null ? "" : exc.getMessage())}; //$NON-NLS-1$ |
| Message message = ValidationPlugin.getMessage(); |
| message.setSeverity(SeverityEnum.NORMAL_SEVERITY); |
| message.setId(ResourceConstants.VBF_EXC_RUNTIME); |
| message.setParams(msgParm); |
| try { |
| reporter.addMessage(validator, message); |
| } catch (MessageLimitException e) { |
| throw e; |
| } |
| return; |
| } |
| try { |
| helper.cleanup(reporter); |
| } catch (MessageLimitException e) { |
| throw e; |
| } catch (OperationCanceledException e) { |
| throw e; |
| } catch (Throwable exc) { |
| // If a runtime exception has occured, e.g. NullPointer or |
| // ClassCast, display it with the "A runtime exception has |
| // occurred " messsage. |
| // This will provide more information to the user when he/she |
| // calls IBM Service. |
| if (logger.isLoggingLevel(Level.SEVERE)) { |
| LogEntry entry = ValidationPlugin.getLogEntry(); |
| entry.setSourceID("ValidationOperation::launchValidator"); //$NON-NLS-1$ |
| entry.setTargetException(exc); |
| logger.write(Level.SEVERE, entry); |
| } |
| String[] msgParm = {exc.getClass().getName(), vmd.getValidatorDisplayName(), (exc.getMessage() == null ? "" : exc.getMessage())}; //$NON-NLS-1$ |
| Message message = ValidationPlugin.getMessage(); |
| message.setSeverity(SeverityEnum.NORMAL_SEVERITY); |
| message.setId(ResourceConstants.VBF_EXC_RUNTIME); |
| message.setParams(msgParm); |
| try { |
| reporter.addMessage(validator, message); |
| } catch (MessageLimitException e) { |
| throw e; |
| } |
| return; |
| } finally { |
| // Now that cleanup has been called, set the project to null. |
| // This project's |
| // resources have been freed so this project should also be |
| // cleared on the helper. |
| // If it isn't set to null, then the next time that the helper |
| // is retrieved from |
| // the ValidatorMetaData, the resources allocated for this |
| // project, in the |
| // helper's initialize method, will not be reallocated if the |
| // project is the same. |
| helper.setProject(null); |
| } |
| // Tell the progress monitor that we've completed n units of work |
| // (i.e., n resources validated by one validator). |
| reporter.getProgressMonitor().worked(((delta == null) ? 1 : delta.length)); // One |
| // unit |
| // of |
| // work |
| // = 1 |
| // (i.e., |
| // 1 |
| // resource) |
| } |
| } |
| |
| private Runnable wrapInRunnable(final WorkbenchReporter reporter, final IValidator validator, final ValidatorMetaData vmd, final IWorkbenchHelper helper, final IFileDelta[] delta, final Iterator iterator) { |
| // Need to create a new Runnable each time because several Runnable |
| // instances may exist at the same time. |
| Runnable runnable = new ProjectRunnable(reporter, validator, vmd, helper, delta, iterator); |
| return runnable; |
| } |
| |
| /* |
| * // For convenience, keep this method in the class but commented out. // When async needs to |
| * be tested, this method may be needed again. private static void debug(String prefix, |
| * IWorkbenchHelper helper) { IProject hProject = helper.getProject(); System.err.println(prefix + |
| * "Start ValidationOperation "+Thread.currentThread().getName() + "::" + hProject.getName()); |
| * if( Thread.currentThread().getName().equals("ValidationThread") && |
| * (hProject.getName().indexOf("noFork") > -1)) { Thread.dumpStack(); } else |
| * if((!Thread.currentThread().getName().equals("ValidationThread")) && |
| * (hProject.getName().indexOf("fork") > -1)) { Thread.dumpStack(); } System.err.println(prefix + |
| * "End ValidationOperation"); } |
| */ |
| public class ProjectRunnable implements Runnable { |
| private WorkbenchReporter _reporter = null; |
| private IValidator _validator = null; |
| private ValidatorMetaData _vmd = null; |
| private IWorkbenchHelper _helper = null; |
| private IFileDelta[] __delta = null; |
| |
| public ProjectRunnable(WorkbenchReporter reporter, IValidator validator, ValidatorMetaData vmd, IWorkbenchHelper helper, IFileDelta[] delta, Iterator iterator) { |
| _reporter = reporter; |
| _validator = validator; |
| _vmd = vmd; |
| _helper = helper; |
| __delta = delta; |
| } |
| |
| public void run() { |
| try { |
| internalValidate(_reporter, _validator, _vmd, _helper, __delta); |
| } catch (OperationCanceledException exc) { |
| // User can't cancel a job in a background thread, so ignore |
| // this exception. |
| } |
| } |
| |
| public IProject getProject() { |
| return _reporter.getProject(); |
| } |
| } |
| } |