package eu.etaxonomy.taxeditor.editor.validation;\r
\r
-import java.util.HashMap;\r
+import java.util.ArrayList;\r
import java.util.List;\r
import java.util.Set;\r
\r
import org.eclipse.core.runtime.CoreException;\r
\r
import eu.etaxonomy.cdm.model.validation.EntityConstraintViolation;\r
-import eu.etaxonomy.cdm.model.validation.EntityValidationResult;\r
+import eu.etaxonomy.cdm.model.validation.EntityValidation;\r
import eu.etaxonomy.cdm.model.validation.Severity;\r
\r
/**\r
* A class responsible for refreshing problem markers coming from the CVI\r
* (Cdmlib Validation Infrastructure).\r
- * \r
+ *\r
* @author ayco_holleman\r
- * \r
+ *\r
*/\r
+\r
/*\r
* See following for problems with icons in Problems view\r
* http://stackoverflow.com\r
* http\r
* ://cubussapiens.hu/2010/11/markers-and-annotations-in-eclipse-for-error-feedback\r
* /\r
- * \r
+ *\r
* See here for difficulty of attaching markers to non-resources (files,\r
* folders):\r
* http://stackoverflow.com/questions/12493179/eclipse-virtual-resources\r
*/\r
public class MarkerManager {\r
\r
- public static final String MARKER_TYPE_ID = "eu.etaxonomy.taxeditor.markers.validationerror";\r
-\r
- /**\r
- * The primary key (id) of the EntityValidationResult record\r
- */\r
- public static final String ATTRIB_DATABASE_ID = "databaseId";\r
-\r
- // The values of the following constants must correspond to the attributes\r
- // defined for the org.eclipse.core.resources.markers extension point in\r
- // plugin.xml\r
-\r
- /**\r
- * A user-friendly description of the type of the entity\r
- */\r
- public static final String ATTRIB_USER_FRIENDLY_TYPE_NAME = "userFriendlyTypeName";\r
- /**\r
- * A user-friendly description of the entity\r
- */\r
- public static final String ATTRIB_USER_FRIENDLY_DESCRIPTION = "userFriendlyDescription";\r
- /**\r
- * The field whose value violated a constraint\r
- */\r
- public static final String ATTRIB_USER_FRIENDLY_FIELD_NAME = "userFriendlyFieldName";\r
- /**\r
- * The value violating a constraint\r
- */\r
- public static final String ATTRIB_INVALID_VALUE = "invalidValue";\r
- /**\r
- * The message from the {@link Validator} about what was wrong.\r
- */\r
- public static final String ATTRIB_VALIDATOR_MESSAGE = "validatorMessage";\r
- /**\r
- * The class of the {@link Validator} coding for the constraint\r
- */\r
- public static final String ATTRIB_VALIDATOR_CLASS = "validatorClass";\r
- /**\r
- * The class of the validated entity\r
- */\r
- public static final String ATTRIB_ENTITY_CLASS = "entityClass";\r
- /**\r
- * The id of the validated entity\r
- */\r
- public static final String ATTRIB_ENTITY_ID = "entityId";\r
-\r
- private final IWorkspaceRoot root;\r
- private final IMarker[] markers;\r
- private final List<EntityValidationResult> results;\r
- private final HashMap<Integer, EntityValidationResult> resultMap;\r
- private final HashMap<Integer, IMarker> markerMap;\r
-\r
-\r
- MarkerManager(List<EntityValidationResult> results) throws CoreException\r
- {\r
- this.root = ResourcesPlugin.getWorkspace().getRoot();\r
- this.markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE);\r
- this.markerMap = new HashMap<Integer, IMarker>();\r
- for (IMarker marker : markers) {\r
- markerMap.put(getDatabaseId(marker), marker);\r
- }\r
- this.results = results;\r
- this.resultMap = new HashMap<Integer, EntityValidationResult>();\r
- for (EntityValidationResult result : results) {\r
- resultMap.put(result.getId(), result);\r
- }\r
- }\r
-\r
-\r
- /**\r
- * Delete all markers that refer to errors that do not exist any longer\r
- * (i.e. the corresponding database record has been deleted).\r
- * \r
- * @return The number of deleted markers\r
- * \r
- * @throws CoreException\r
- */\r
- int deleteObsoleteMarkers() throws CoreException\r
- {\r
- int i = 0;\r
- IMarker[] markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE);\r
- for (IMarker marker : markers) {\r
- if (isObsoleteMarker(marker)) {\r
- ++i;\r
- marker.delete();\r
- }\r
- }\r
- return i;\r
- }\r
-\r
-\r
- /**\r
- * Create markers for new errors (i.e. no marker has been created for them\r
- * yet).\r
- * \r
- * @return The number of new markers\r
- * \r
- * @throws CoreException\r
- */\r
- int createMarkers() throws CoreException\r
- {\r
- int i = 0;\r
- IMarker[] markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE);\r
- for (EntityValidationResult result : results) {\r
- if (!isNewResult(result)) {\r
- continue;\r
- }\r
- Set<EntityConstraintViolation> problems = result.getEntityConstraintViolations();\r
- for (EntityConstraintViolation problem : problems) {\r
- if (markerExistsForProblem(problem, markers)) {\r
- continue;\r
- }\r
- IMarker marker = root.createMarker(MARKER_TYPE_ID);\r
- ++i;\r
- if (problem.getSeverity() == Severity.ERROR) {\r
- marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);\r
- }\r
- else if (problem.getSeverity() == Severity.WARNING) {\r
- marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);\r
- }\r
- else {\r
- marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);\r
- }\r
- marker.setAttribute(IMarker.MESSAGE, problem.getMessage());\r
- marker.setAttribute(ATTRIB_DATABASE_ID, result.getId());\r
- marker.setAttribute(ATTRIB_USER_FRIENDLY_TYPE_NAME, result.getUserFriendlyTypeName());\r
- marker.setAttribute(ATTRIB_USER_FRIENDLY_DESCRIPTION, result.getUserFriendlyDescription());\r
- marker.setAttribute(ATTRIB_USER_FRIENDLY_FIELD_NAME, problem.getUserFriendlyFieldName());\r
- marker.setAttribute(ATTRIB_VALIDATOR_MESSAGE, problem.getMessage());\r
- marker.setAttribute(ATTRIB_INVALID_VALUE, problem.getInvalidValue());\r
- marker.setAttribute(ATTRIB_VALIDATOR_CLASS, problem.getValidator());\r
- marker.setAttribute(ATTRIB_ENTITY_CLASS, result.getValidatedEntityClass());\r
- marker.setAttribute(ATTRIB_ENTITY_ID, result.getValidatedEntityId());\r
- }\r
- }\r
- return i;\r
- }\r
-\r
-\r
- /**\r
- * Is there a problem marker that captures the specified\r
- * {@link EntityConstraintViolation}? See\r
- * {@link #markerCapturesProblem(IMarker, EntityConstraintViolation)}.\r
- * \r
- * @param problem\r
- * @param markers\r
- * @return\r
- * @throws CoreException\r
- */\r
- private boolean markerExistsForProblem(EntityConstraintViolation problem, IMarker[] markers) throws CoreException\r
- {\r
- for (IMarker marker : markers) {\r
- if (markerCapturesProblem(marker, problem)) {\r
- return true;\r
- }\r
- }\r
- return false;\r
- }\r
-\r
-\r
- /**\r
- * <p>\r
- * This method determines whether the problem exposed by the specified\r
- * marker is <b>de facto</b> equivalent to the specified\r
- * {@code EntityConstraintViolation}. When the CVI validates an entity, it\r
- * first deletes previous validation results for that entity and only then\r
- * saves the new validation result. Thus you cannot rely on the database id\r
- * of the {@code EntityConstraintViolation} to determine equivalence. Maybe\r
- * later we can make the CVI more sophisticated in this respect. Or maybe\r
- * see if solving it through the equals() method of\r
- * {@code EntityValidationResult} and/or {@code EntityConstraintViolation}\r
- * is possible. But for now this is the easiest solution.\r
- * </p>\r
- * <p>\r
- * The reason we check for equivalence, is that we don't want to\r
- * unnecessarily update the Problems view. If a marker is there, we don't\r
- * want to replace it with an equivalent marker, because that might lead to\r
- * strange click behaviour for end users (e.g. selected problems will\r
- * disappear and re-appear unselected).\r
- * </p>\r
- * \r
- * @param marker\r
- * @param problem\r
- * @return\r
- * @throws CoreException\r
- */\r
- private static boolean markerCapturesProblem(IMarker marker, EntityConstraintViolation problem) throws CoreException\r
- {\r
- EntityValidationResult result = problem.getEntityValidationResult();\r
- if (!marker.getAttribute(ATTRIB_ENTITY_CLASS).equals(result.getValidatedEntityClass())) {\r
- return false;\r
- }\r
- if (!marker.getAttribute(ATTRIB_ENTITY_ID).equals(result.getValidatedEntityId())) {\r
- return false;\r
- }\r
- if (!marker.getAttribute(ATTRIB_USER_FRIENDLY_FIELD_NAME).equals(problem.getPropertyPath())) {\r
- return false;\r
- }\r
- if (!marker.getAttribute(ATTRIB_INVALID_VALUE).equals(problem.getInvalidValue())) {\r
- return false;\r
- }\r
- if (!marker.getAttribute(ATTRIB_VALIDATOR_CLASS).equals(problem.getValidator())) {\r
- return false;\r
- }\r
- return true;\r
- }\r
-\r
-\r
- /**\r
- * Is this a marker without a corresponding database record (\r
- * {@link EntityValidationResult})?\r
- * \r
- * @param marker\r
- * @return\r
- * @throws CoreException\r
- */\r
- private boolean isObsoleteMarker(IMarker marker) throws CoreException\r
- {\r
- return resultMap.get(getDatabaseId(marker)) == null;\r
- }\r
-\r
-\r
- /**\r
- * Is this an {@link EntityValidationResult} for which no marker has been\r
- * created yet?\r
- * \r
- * @param result\r
- * @return\r
- */\r
- private boolean isNewResult(EntityValidationResult result)\r
- {\r
- return markerMap.get(result.getId()) == null;\r
- }\r
-\r
-\r
- /**\r
- * Get the id of the {@link EntityValidationResult} that was stored as one\r
- * of the marker's attributes.\r
- * \r
- * @param marker\r
- * @return\r
- * @throws CoreException\r
- */\r
- private static Integer getDatabaseId(IMarker marker) throws CoreException\r
- {\r
- return (Integer) marker.getAttribute(ATTRIB_DATABASE_ID);\r
- }\r
+ public static final String MARKER_TYPE_ID = "eu.etaxonomy.taxeditor.markers.validationerror";\r
+\r
+ /**\r
+ * The primary key (id) of the EntityConstraintViolation record\r
+ */\r
+ public static final String ATTRIB_DATABASE_ID = "databaseId";\r
+\r
+ // The values of the following constants must correspond to the attributes\r
+ // defined for the org.eclipse.core.resources.markers extension point in\r
+ // plugin.xml\r
+\r
+ /**\r
+ * A user-friendly description of the type of the entity\r
+ */\r
+ public static final String ATTRIB_USER_FRIENDLY_TYPE_NAME = "userFriendlyTypeName";\r
+ /**\r
+ * A user-friendly description of the entity\r
+ */\r
+ public static final String ATTRIB_USER_FRIENDLY_DESCRIPTION = "userFriendlyDescription";\r
+ /**\r
+ * The field whose value violated a constraint\r
+ */\r
+ public static final String ATTRIB_USER_FRIENDLY_FIELD_NAME = "userFriendlyFieldName";\r
+ /**\r
+ * The value violating a constraint\r
+ */\r
+ public static final String ATTRIB_INVALID_VALUE = "invalidValue";\r
+ /**\r
+ * The message from the {@link Validator} about what was wrong.\r
+ */\r
+ public static final String ATTRIB_VALIDATOR_MESSAGE = "validatorMessage";\r
+ /**\r
+ * The class of the {@link Validator} coding for the constraint\r
+ */\r
+ public static final String ATTRIB_VALIDATOR_CLASS = "validatorClass";\r
+ /**\r
+ * The class of the validated entity\r
+ */\r
+ public static final String ATTRIB_ENTITY_CLASS = "entityClass";\r
+ /**\r
+ * The id of the validated entity\r
+ */\r
+ public static final String ATTRIB_ENTITY_ID = "entityId";\r
+\r
+ private final List<EntityConstraintViolation> problems;\r
+\r
+ MarkerManager(List<EntityValidation> results) {\r
+ this.problems = new ArrayList<EntityConstraintViolation>();\r
+ for (EntityValidation result : results) {\r
+ Set<EntityConstraintViolation> problemsPerEntity = result.getEntityConstraintViolations();\r
+ for (EntityConstraintViolation problem : problemsPerEntity) {\r
+ problem.setEntityValidation(result);\r
+ problems.add(problem);\r
+ }\r
+ }\r
+ //MessagingUtils.info("Number of validation errors: " + problems.size());\r
+ }\r
+\r
+ /**\r
+ * Delete all markers that refer to errors that do not exist any longer\r
+ * (i.e. the corresponding database record has been deleted).\r
+ *\r
+ * @return The number of deleted markers\r
+ *\r
+ * @throws CoreException\r
+ */\r
+ int deleteObsoleteMarkers() throws CoreException {\r
+ int i = 0;\r
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();\r
+ IMarker[] markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE);\r
+ for (IMarker marker : markers) {\r
+ if (isObsoleteMarker(marker)) {\r
+ ++i;\r
+ marker.delete();\r
+ }\r
+ }\r
+ //MessagingUtils.info("Obsolete markers: " + i);\r
+ return i;\r
+ }\r
+\r
+ /**\r
+ * Create markers for new errors (i.e. no marker has been created for them\r
+ * yet).\r
+ *\r
+ * @return The number of new markers\r
+ *\r
+ * @throws CoreException\r
+ */\r
+ int createMarkers() throws CoreException {\r
+ int i = 0;\r
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();\r
+ IMarker[] markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE);\r
+ for (EntityConstraintViolation problem : problems) {\r
+ if (isNewProblem(problem, markers)) {\r
+ ++i;\r
+ IMarker marker = root.createMarker(MARKER_TYPE_ID);\r
+ if (problem.getSeverity() == Severity.ERROR) {\r
+ marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);\r
+ } else if (problem.getSeverity() == Severity.WARNING) {\r
+ marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);\r
+ } else {\r
+ marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);\r
+ }\r
+ EntityValidation result = problem.getEntityValidation();\r
+ marker.setAttribute(IMarker.MESSAGE, problem.getMessage());\r
+ marker.setAttribute(ATTRIB_DATABASE_ID, new Integer(problem.getId()));\r
+ marker.setAttribute(ATTRIB_USER_FRIENDLY_TYPE_NAME, result.getUserFriendlyTypeName());\r
+ marker.setAttribute(ATTRIB_USER_FRIENDLY_DESCRIPTION, result.getUserFriendlyDescription());\r
+ marker.setAttribute(ATTRIB_USER_FRIENDLY_FIELD_NAME, problem.getUserFriendlyFieldName());\r
+ marker.setAttribute(ATTRIB_VALIDATOR_MESSAGE, problem.getMessage());\r
+ marker.setAttribute(ATTRIB_INVALID_VALUE, problem.getInvalidValue());\r
+ marker.setAttribute(ATTRIB_VALIDATOR_CLASS, problem.getValidator());\r
+ marker.setAttribute(ATTRIB_ENTITY_CLASS, result.getValidatedEntityClass());\r
+ marker.setAttribute(ATTRIB_ENTITY_ID, result.getValidatedEntityId());\r
+ }\r
+ }\r
+ //MessagingUtils.info("New problems: " + i);\r
+ return i;\r
+ }\r
+\r
+ private boolean isObsoleteMarker(IMarker marker) throws CoreException {\r
+ for (EntityConstraintViolation problem : problems) {\r
+ if (isMarkerForProblem(marker, problem)) {\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+\r
+ private static boolean isNewProblem(EntityConstraintViolation problem, IMarker[] markers) throws CoreException {\r
+ for (IMarker marker : markers) {\r
+ if (isMarkerForProblem(marker, problem)) {\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+\r
+ private static boolean isMarkerForProblem(IMarker marker, EntityConstraintViolation problem) throws CoreException {\r
+ if (isEqual(marker, ATTRIB_DATABASE_ID, new Integer(problem.getId()))) {\r
+ return true;\r
+ }\r
+ EntityValidation result = problem.getEntityValidation();\r
+ if (!isEqual(marker, ATTRIB_ENTITY_ID, result.getValidatedEntityId())) {\r
+ return false;\r
+ }\r
+ if (!isEqual(marker, ATTRIB_INVALID_VALUE, problem.getInvalidValue())) {\r
+ return false;\r
+ }\r
+ if (!isEqual(marker, ATTRIB_ENTITY_CLASS, result.getValidatedEntityClass())) {\r
+ return false;\r
+ }\r
+ if (!isEqual(marker, ATTRIB_USER_FRIENDLY_FIELD_NAME, problem.getUserFriendlyFieldName())) {\r
+ return false;\r
+ }\r
+ if (!isEqual(marker, ATTRIB_VALIDATOR_CLASS, problem.getValidator())) {\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ private static boolean isEqual(IMarker marker, String attribute, Object value) throws CoreException {\r
+ Object val = marker.getAttribute(attribute);\r
+ boolean equal;\r
+ if (val == null) {\r
+ equal = value == null;\r
+ } else {\r
+ equal = value != null && val.equals(value);\r
+ }\r
+ return equal;\r
+ }\r
\r
}\r