| /******************************************************************************* |
| * Copyright (c) 2001, 2007 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.html.internal.validation; |
| |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.wst.html.ui.internal.HTMLUIPlugin; |
| import org.eclipse.wst.validation.internal.provisional.core.IMessage; |
| |
| /** |
| * This class must be called only by the validation framework. |
| * |
| * This singleton interacts with the eclipse workbench's Task list. |
| * TaskListUtility adds and removes tasks from the list. |
| * |
| * This class must not be called outside of an IWorkspaceRunnable or |
| * IRunnableWithProgress. Many resource deltas can be generated by the methods |
| * in this class. |
| * |
| * This came from TaskListUtility |
| */ |
| public class TaskListUtility { |
| // private static final String PLUGIN_ID = ValidationPlugin.PLUGIN_ID; |
| private static final String PLUGIN_ID = HTMLUIPlugin.ID; |
| private static final String VALIDATION_MARKER = PLUGIN_ID + ".problemmarker"; //$NON-NLS-1$ // The extension which is used to add validation markers to the task list |
| private static final String VALIDATION_MARKER_OWNER = "owner"; //$NON-NLS-1$ // The IValidator who owns the IMarker on the task list |
| private static final String VALIDATION_MARKER_SEVERITY = "validationSeverity"; //$NON-NLS-1$ // one of the IMessage values |
| private static final String VALIDATION_MARKER_TARGETOBJECT = "targetObject"; //$NON-NLS-1$ // When more than one target object resolves to the same IResource, this field identifies which targetObject owns a particular message. |
| private static final String VALIDATION_MARKER_GROUP = "groupName"; //$NON-NLS-1$ // For incremental validation, this field associates a message with a group, so that a subset of messages may be removed from a file. |
| private static final String VALIDATION_MARKER_MESSAGEID = "messageId"; //$NON-NLS-1$ // Persist the message id of the message, not just the translated text. |
| private static final int DEPTH_INFINITE = IResource.DEPTH_INFINITE; |
| private static final int DEPTH_ZERO = IResource.DEPTH_ZERO; |
| private final static IMarker[] NO_MARKERS = new IMarker[0]; |
| |
| /** |
| * This method adds a message to a resource in the task list. |
| */ |
| public static IMarker addTask(String pluginId, IResource resource, String location, String messageId, String message, int markerType, String targetObjectName, String groupName, int offset, int length) throws CoreException { |
| if ((message == null) || (resource == null)) { |
| return null; |
| } |
| |
| int severity = getSeverity(markerType); |
| |
| // Allow duplicate entries in the task list. |
| // Prior to a full validation, the validation framework will remove |
| // all messages owned |
| // by a validator before it is executed. |
| // Prior to an incremental validation, the validation framework will |
| // remove all messages, |
| // on each of the changed resources, owned by a validator before it is |
| // invoked. |
| // |
| // It is up to the validator to make sure that it is not adding the |
| // same message |
| // in more than one place, and also to clear out any old messages |
| // which are not cleared |
| // by the validation framework. |
| IMarker item = resource.createMarker(VALIDATION_MARKER); // add a |
| // validation |
| // marker |
| |
| // For performance reasons, replace the multiple setAttribute |
| // calls above with a single setAttributes call. |
| boolean offsetSet = ((offset != IMessage.OFFSET_UNSET) && (length != IMessage.OFFSET_UNSET)); |
| int size = (offsetSet) ? 10 : 8; // add CHAR_START, CHAR_END only |
| // if the offset is set. If the |
| // offset is set, it takes |
| // precendence over the line |
| // number. (eclipse's rule, not |
| // mine.) |
| String[] attribNames = new String[size]; |
| Object[] attribValues = new Object[size]; |
| |
| // Very first thing, add the owner. That way, if the code dies |
| // before things are persisted, hopefully this marker will be |
| // persisted. |
| // Hopefully, eclipse WILL persist this field, as requested. |
| attribNames[0] = VALIDATION_MARKER_OWNER; |
| attribValues[0] = pluginId; |
| attribNames[1] = VALIDATION_MARKER_SEVERITY; // this validation |
| // severity is stored, |
| // in addition to the |
| // marker severity, to |
| // enable more than |
| // one severity of |
| // message to be |
| // displayed. e.g. |
| // ERROR | WARNING |
| // (using binary OR). |
| // The IMarker |
| // constants are |
| // regular decimal |
| // constants. |
| attribValues[1] = new Integer(markerType); |
| attribNames[2] = VALIDATION_MARKER_TARGETOBJECT; // to distinguish |
| // between |
| // messages which |
| // are registered |
| // on an |
| // IResource, but |
| // against |
| // different |
| // target objects |
| attribValues[2] = ((targetObjectName == null) ? "" : targetObjectName); //$NON-NLS-1$ |
| attribNames[3] = VALIDATION_MARKER_GROUP; |
| attribValues[3] = ((groupName == null) ? "" : groupName); //$NON-NLS-1$ |
| attribNames[4] = IMarker.MESSAGE; |
| attribValues[4] = message; |
| attribNames[5] = VALIDATION_MARKER_MESSAGEID; |
| attribValues[5] = messageId; |
| |
| attribNames[6] = IMarker.SEVERITY; // IMarker.SEVERITY_ERROR, |
| // IMarker.SEVERITY_WARNING, |
| // IMarker.SEVERITY_INFO |
| attribValues[6] = new Integer(severity); |
| try { |
| // If the location is a line number, store it as a line number |
| Integer lineNumber = Integer.valueOf(location); |
| attribNames[7] = IMarker.LINE_NUMBER; |
| attribValues[7] = lineNumber; |
| } |
| catch (NumberFormatException exc) { |
| // Otherwise, store it as a text location |
| attribNames[7] = IMarker.LOCATION; |
| attribValues[7] = location; |
| } |
| |
| if (offsetSet) { |
| attribNames[8] = IMarker.CHAR_START; |
| attribValues[8] = new Integer(offset); |
| attribNames[9] = IMarker.CHAR_END; |
| attribValues[9] = new Integer(offset + length); |
| } |
| |
| item.setAttributes(attribNames, attribValues); |
| |
| return item; |
| } |
| |
| /** |
| * Given one of the SeverityEnum severities, return the IMarker severity |
| * int that is its equivalent. |
| */ |
| private static int getSeverity(int severityEnumValue) { |
| switch (severityEnumValue) { |
| case (IMessage.HIGH_SEVERITY) : { |
| return IMarker.SEVERITY_ERROR; |
| } |
| |
| case (IMessage.LOW_SEVERITY) : { |
| return IMarker.SEVERITY_INFO; |
| } |
| |
| case (IMessage.NORMAL_SEVERITY) : { |
| return IMarker.SEVERITY_WARNING; |
| } |
| |
| case (IMessage.ALL_MESSAGES) : |
| case (IMessage.ERROR_AND_WARNING) : |
| default : { |
| // assume it's a warning. |
| return IMarker.SEVERITY_WARNING; |
| } |
| } |
| } |
| |
| private static int getDepth(IResource resource) { |
| if (resource instanceof IProject) { |
| return DEPTH_INFINITE; // DEPTH_INFINITE means get this project's |
| // markers, and the markers belonging to |
| // the project's children. |
| } |
| else if (resource instanceof IWorkspaceRoot) { |
| // Needed for the ValidationMigrator when it checks for orphan |
| // tasks. |
| return DEPTH_INFINITE; // DEPTH_INFINITE means get all of the |
| // markers in the workspace |
| } |
| |
| return DEPTH_ZERO; // DEPTH_ZERO means just this resource, not its |
| // children |
| } |
| |
| private static IMarker[] getValidationTasks(IResource resource, int severity, int depth) { |
| IMarker[] tempMarkers = null; |
| int validCount = 0; |
| try { |
| IMarker[] allMarkers = null; |
| try { |
| allMarkers = resource.findMarkers(VALIDATION_MARKER, false, depth); // false |
| // means |
| // only |
| // consider |
| // PROBLEM_MARKER, |
| // not |
| // variants |
| // of |
| // PROBLEM_MARKER. |
| // Since |
| // addTask |
| // only |
| // adds |
| // PROBLEM_MARKER, |
| // we |
| // don't |
| // need |
| // to |
| // consider |
| // its |
| // subtypes. |
| } |
| catch (CoreException exc) { |
| // Logger logger = |
| // ValidationPlugin.getPlugin().getMsgLogger(); |
| // if (logger.isLoggingLevel(Level.SEVERE)) { |
| // LogEntry entry = ValidationPlugin.getLogEntry(); |
| // entry.setSourceID("TaskListUtility.getValidationTasks(IResource, |
| // int)"); //$NON-NLS-1$ |
| // entry.setTargetException(exc); |
| // logger.write(Level.SEVERE, entry); |
| // } |
| return NO_MARKERS; |
| } |
| |
| // Now filter in the markers, based on severity type. |
| if (allMarkers.length != 0) { |
| tempMarkers = new IMarker[allMarkers.length]; |
| for (int i = 0; i < allMarkers.length; i++) { |
| IMarker marker = allMarkers[i]; |
| Integer filterSeverity = (Integer) marker.getAttribute(VALIDATION_MARKER_SEVERITY); |
| if (filterSeverity == null) { |
| // odd...marker wasn't created correctly. How could |
| // this happen? |
| // Default to the current severity and add it to the |
| // list. |
| try { |
| marker.setAttribute(IMarker.SEVERITY, getSeverity(severity)); |
| } |
| catch (CoreException exc) { |
| // Logger logger = |
| // ValidationPlugin.getPlugin().getMsgLogger(); |
| // if (logger.isLoggingLevel(Level.SEVERE)) { |
| // LogEntry entry = |
| // ValidationPlugin.getLogEntry(); |
| // entry.setSourceID("TaskListUtility.getValidationTasks(int, |
| // IResource, int)"); //$NON-NLS-1$ |
| // entry.setTargetException(exc); |
| // logger.write(Level.SEVERE, entry); |
| // } |
| continue; |
| } |
| catch (Exception exc) { |
| // Logger logger = |
| // ValidationPlugin.getPlugin().getMsgLogger(); |
| // if (logger.isLoggingLevel(Level.SEVERE)) { |
| // LogEntry entry = |
| // ValidationPlugin.getLogEntry(); |
| // entry.setSourceID("TaskListUtility.getValidationTasks(int, |
| // IResource, int)"); //$NON-NLS-1$ |
| // entry.setTargetException(exc); |
| // logger.write(Level.SEVERE, entry); |
| // } |
| continue; |
| } |
| } |
| else if ((severity & filterSeverity.intValue()) == 0) { |
| continue; |
| } |
| tempMarkers[validCount++] = marker; |
| } |
| } |
| } |
| catch (CoreException exc) { |
| // Logger logger = ValidationPlugin.getPlugin().getMsgLogger(); |
| // if (logger.isLoggingLevel(Level.SEVERE)) { |
| // LogEntry entry = ValidationPlugin.getLogEntry(); |
| // entry.setSourceID("TaskListUtility.getValidationTasks(int, |
| // IResource, int)"); //$NON-NLS-1$ |
| // entry.setTargetException(exc); |
| // logger.write(Level.SEVERE, entry); |
| // } |
| } |
| |
| if (validCount == 0) { |
| return NO_MARKERS; |
| } |
| |
| IMarker[] validMarkers = new IMarker[validCount]; |
| System.arraycopy(tempMarkers, 0, validMarkers, 0, validCount); |
| return validMarkers; |
| } |
| |
| private static IMarker[] getValidationTasks(IResource resource, String[] messageOwners, int depth) { |
| IMarker[] markers = getValidationTasks(resource, IMessage.ALL_MESSAGES, depth); |
| if (markers.length == 0) { |
| return NO_MARKERS; |
| } |
| |
| IMarker[] temp = new IMarker[markers.length]; |
| int validCount = 0; |
| for (int i = 0; i < markers.length; i++) { |
| IMarker marker = markers[i]; |
| |
| try { |
| Object owner = marker.getAttribute(VALIDATION_MARKER_OWNER); |
| if ((owner == null) || !(owner instanceof String)) { |
| // The ValidationMigrator will remove any "unowned" |
| // validation markers. |
| continue; |
| } |
| |
| for (int j = 0; j < messageOwners.length; j++) { |
| String messageOwner = messageOwners[j]; |
| if (((String) owner).equals(messageOwner)) { |
| temp[validCount++] = marker; |
| break; |
| } |
| } |
| } |
| catch (CoreException exc) { |
| // Logger logger = |
| // ValidationPlugin.getPlugin().getMsgLogger(); |
| // if (logger.isLoggingLevel(Level.SEVERE)) { |
| // LogEntry entry = ValidationPlugin.getLogEntry(); |
| // entry.setSourceID("TaskListUtility.getValidationTasks(project, |
| // String[])"); //$NON-NLS-1$ |
| // entry.setTargetException(exc); |
| // logger.write(Level.SEVERE, entry); |
| // } |
| return NO_MARKERS; |
| } |
| } |
| |
| IMarker[] result = new IMarker[validCount]; |
| System.arraycopy(temp, 0, result, 0, validCount); |
| return result; |
| } |
| |
| /** |
| * This method retrieves all validation tasks from the resource. If depth |
| * is INFINITE, child tasks are returned as well. Only the tasks which are |
| * owned by the specified messageOwner, and apply to the named IMessage's |
| * target object (objectName) will be returned. |
| */ |
| private static IMarker[] getValidationTasks(IResource resource, String[] messageOwner, String objectName, String groupName, int depth) throws CoreException { |
| if ((messageOwner == null) || (resource == null)) { |
| return NO_MARKERS; |
| } |
| |
| int validCount = 0; |
| IMarker[] validList = null; |
| IMarker[] markers = getValidationTasks(resource, messageOwner, depth); |
| if (markers != null) { |
| validList = new IMarker[markers.length]; |
| for (int i = 0; i < markers.length; i++) { |
| IMarker marker = markers[i]; |
| |
| // If more than one target object resolves to the same |
| // resource, removing one target's |
| // messages should not remove the other target object's |
| // messages. |
| if (objectName != null) { |
| Object targetObject = marker.getAttribute(VALIDATION_MARKER_TARGETOBJECT); |
| if ((targetObject == null) || !(targetObject instanceof String) || !(((String) targetObject).equals(objectName))) { |
| continue; |
| } |
| } |
| |
| if (groupName != null) { |
| Object group = marker.getAttribute(VALIDATION_MARKER_GROUP); |
| if ((group == null) || !(group instanceof String) || !(((String) group).equals(groupName))) { |
| continue; |
| } |
| } |
| |
| validList[validCount++] = marker; |
| } |
| } |
| |
| if (validCount == 0) { |
| return NO_MARKERS; |
| } |
| |
| IMarker[] result = new IMarker[validCount]; |
| System.arraycopy(validList, 0, result, 0, validCount); |
| return result; |
| } |
| |
| /** |
| * This method removes all messages from a resource in the task list. |
| */ |
| public static void removeAllTasks(IResource resource, String owner, String objectName) throws CoreException { |
| removeAllTasks(resource, new String[]{owner}, objectName); |
| } |
| |
| public static void removeAllTasks(IResource resource, String[] owners, String objectName) throws CoreException { |
| removeAllTasks(resource, owners, objectName, getDepth(resource)); |
| } |
| |
| protected static void removeAllTasks(IResource resource, String[] owners, String objectName, int depth) throws CoreException { |
| removeTaskSubset(resource, owners, objectName, null, depth); // null |
| // means |
| // no |
| // group |
| // name |
| } |
| |
| /** |
| * This method removes a subset of tasks from the project, including child |
| * tasks. Every task which belongs to the group, identified by groupName, |
| * will be removed. |
| */ |
| protected static void removeTaskSubset(IResource resource, String[] owners, String objectName, String groupName, int depth) throws CoreException { |
| if ((owners == null) || (resource == null)) { |
| return; |
| } |
| |
| IMarker[] allTasks = getValidationTasks(resource, owners, objectName, groupName, depth); |
| if (allTasks.length > 0) { |
| ResourcesPlugin.getWorkspace().deleteMarkers(allTasks); |
| } |
| } |
| } |