merge validation editor branch to trunk
authorAndreas Müller <a.mueller@bgbm.org>
Thu, 8 Jan 2015 23:47:10 +0000 (23:47 +0000)
committerAndreas Müller <a.mueller@bgbm.org>
Thu, 8 Jan 2015 23:47:10 +0000 (23:47 +0000)
15 files changed:
.gitattributes
eu.etaxonomy.taxeditor.editor/plugin.xml
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/internal/TaxeditorEditorPlugin.java
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/MarkerManager.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/ValidationContextListener.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/ValidationDaemon.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/EntityClassMarkerField.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/EntityIdMarkerField.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/InvalidValueMarkerField.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyDescriptionMarkerField.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyFieldNameMarkerField.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyTypeNameMarkerField.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidationProblemsView.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidatorClassMarkerField.java [new file with mode: 0644]
eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidatorMessageMarkerField.java [new file with mode: 0644]

index 396ab0ba90ba786e25f256ad953501ffd03d8d3a..b2a24af4fe061fa70d579ceb108075cee1a4ffa8 100644 (file)
@@ -481,6 +481,9 @@ eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/name/o
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/name/operation/MoveSynonymToAnotherAcceptedTaxonOperation.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/name/operation/RemoveHomotypicalGroupBasionymOperation.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/name/operation/SwapSynonymAndAcceptedOperation.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/name/operation/MoveSynonymToAnotherAcceptedTaxonOperation.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/name/operation/RemoveHomotypicalGroupBasionymOperation.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/name/operation/SwapSynonymAndAcceptedOperation.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/MarkerManager.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/ValidationContextListener.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/ValidationDaemon.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/checklist/ChecklistContentProvider.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/checklist/ChecklistEditor.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/checklist/ChecklistEditorComparator.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/checklist/ChecklistContentProvider.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/checklist/ChecklistEditor.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/checklist/ChecklistEditorComparator.java -text
@@ -599,6 +602,15 @@ eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/u
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/uses/operation/CreateTaxonUseOperation.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/uses/operation/CreateUseRecordOperation.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/uses/operation/CreateUseSummaryOperation.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/uses/operation/CreateTaxonUseOperation.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/uses/operation/CreateUseRecordOperation.java -text
 eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/uses/operation/CreateUseSummaryOperation.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/EntityClassMarkerField.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/EntityIdMarkerField.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/InvalidValueMarkerField.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyDescriptionMarkerField.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyFieldNameMarkerField.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyTypeNameMarkerField.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidationProblemsView.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidatorClassMarkerField.java -text
+eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidatorMessageMarkerField.java -text
 eu.etaxonomy.taxeditor.editor/src/main/resources/TaonDescriptionEditor.screen -text
 eu.etaxonomy.taxeditor.editor/src/main/resources/log4j.properties -text
 eu.etaxonomy.taxeditor.editor/src/test/java/eu/etaxonomy/taxeditor/editor/Application.java -text
 eu.etaxonomy.taxeditor.editor/src/main/resources/TaonDescriptionEditor.screen -text
 eu.etaxonomy.taxeditor.editor/src/main/resources/log4j.properties -text
 eu.etaxonomy.taxeditor.editor/src/test/java/eu/etaxonomy/taxeditor/editor/Application.java -text
index eb2bcb9ba477b9339d9d214fe88f89ef5dd4efa5..97d74efb4c4717136cc4d3293b3c7f0c249eba3e 100644 (file)
                name="%view.name.5">
          </view>
       </extension>
                name="%view.name.5">
          </view>
       </extension>
-   <extension
+      
+       <!-- VALIDATION RELATED STUFF -->
+       <extension point="org.eclipse.ui.menus">
+       <menuContribution locationURI="menu:eu.etaxonomy.taxeditor.menu.showView?after=org.eclipse.ui.views.showView.problems">
+                       <command
+                             commandId="org.eclipse.ui.views.showView"
+                             label="Validation Problems"
+                             style="push">
+                          <parameter
+                                name="org.eclipse.ui.views.showView.viewId"
+                                value="eu.etaxonomy.taxeditor.editor.view.validation.problems">
+                          </parameter>
+                       </command>
+               </menuContribution>
+       </extension>
+        <extension point="org.eclipse.ui.views">
+               <view
+            allowMultiple="false"
+            category="eu.etaxonomy.taxeditor.editor.category"
+               class="eu.etaxonomy.taxeditor.editor.view.validation.ValidationProblemsView"
+               icon="icons/edit_16x16.gif"
+               id="eu.etaxonomy.taxeditor.editor.view.validation.problems"
+               name="Validation problems">
+           </view>
+       </extension>
+       <extension point="org.eclipse.core.resources.markers" name="Validation Error" id="eu.etaxonomy.taxeditor.markers.validationerror">
+               <super type="org.eclipse.core.resources.problemmarker"/>
+               <attribute name="databaseId"/>
+               <attribute name="userFriendlyTypeName"/>
+               <attribute name="userFriendlyDescription"/>
+               <attribute name="userFriendlyFieldName"/>
+               <attribute name="validatorMessage"/>
+               <attribute name="invalidValue"/>
+               <attribute name="validatorClass"/>
+               <attribute name="entityClass"/>
+               <attribute name="entityId"/>
+               <persistent value="false"/>
+       </extension>
+
+       <extension point="org.eclipse.ui.ide.markerSupport">
+           <markerContentGenerator
+                   id="eu.etaxonomy.taxeditor.editor.validation.ValidationProblemsMarkerGenerator" 
+                   name="Validation Problems Marker Generator">  
+               <markerTypeReference id="eu.etaxonomy.taxeditor.markers.validationerror" />
+               
+               <markerFieldReference id="eu.etaxonomy.taxeditor.markers.validation.userFriendlyTypeName" visible="true" />
+               <markerFieldReference id="eu.etaxonomy.taxeditor.markers.validation.userFriendlyDescription" visible="true" />
+               <markerFieldReference id="eu.etaxonomy.taxeditor.markers.validation.userFriendlyFieldName" visible="true" />
+               <markerFieldReference id="eu.etaxonomy.taxeditor.markers.validation.validatorMessage" visible="true" />
+               <markerFieldReference id="eu.etaxonomy.taxeditor.markers.validation.invalidValue" visible="true" />
+               <markerFieldReference id="eu.etaxonomy.taxeditor.markers.validation.validatorClass" visible="false" />
+               <markerFieldReference id="eu.etaxonomy.taxeditor.markers.validation.entityClass" visible="false" />
+               <markerFieldReference id="eu.etaxonomy.taxeditor.markers.validation.entityId" visible="false" />
+           </markerContentGenerator>
+           
+               <markerField
+                       class="eu.etaxonomy.taxeditor.editor.view.validation.UserFriendlyTypeNameMarkerField"
+                       id="eu.etaxonomy.taxeditor.markers.validation.userFriendlyTypeName"
+                       name="Object Type">
+               </markerField>
+               <markerField
+                       class="eu.etaxonomy.taxeditor.editor.view.validation.UserFriendlyDescriptionMarkerField"
+                       id="eu.etaxonomy.taxeditor.markers.validation.userFriendlyDescription"
+                       name="Object">
+               </markerField>
+               <markerField
+                       class="eu.etaxonomy.taxeditor.editor.view.validation.UserFriendlyFieldNameMarkerField"
+                       id="eu.etaxonomy.taxeditor.markers.validation.userFriendlyFieldName"
+                       name="Attribute">
+               </markerField>
+               <markerField
+                       class="eu.etaxonomy.taxeditor.editor.view.validation.InvalidValueMarkerField"
+                       id="eu.etaxonomy.taxeditor.markers.validation.invalidValue"
+                       name="Problematic Value">
+               </markerField>
+               <markerField
+                       class="eu.etaxonomy.taxeditor.editor.view.validation.ValidatorMessageMarkerField"
+                       id="eu.etaxonomy.taxeditor.markers.validation.validatorMessage"
+                       name="Problem description">
+               </markerField>
+               <markerField
+                       class="eu.etaxonomy.taxeditor.editor.view.validation.ValidatorClassMarkerField"
+                       id="eu.etaxonomy.taxeditor.markers.validation.validatorClass"
+                       name="Validator">
+               </markerField>
+               <markerField
+                       class="eu.etaxonomy.taxeditor.editor.view.validation.EntityClassMarkerField"
+                       id="eu.etaxonomy.taxeditor.markers.validation.entityClass"
+                       name="Entity Class">
+               </markerField>
+               <markerField
+                       class="eu.etaxonomy.taxeditor.editor.view.validation.EntityIdMarkerField"
+                       id="eu.etaxonomy.taxeditor.markers.validation.entityId"
+                       name="Entity Id">
+               </markerField>
+       </extension>
+       
+  <extension
          point="org.eclipse.ui.elementFactories">
       <factory
             class="eu.etaxonomy.taxeditor.editor.TaxonEditorInputFactory"
          point="org.eclipse.ui.elementFactories">
       <factory
             class="eu.etaxonomy.taxeditor.editor.TaxonEditorInputFactory"
index 7da4103c24ade1664baba8b9e114c6d6753fe38d..dd87e5ba54b89f4be7e5547f621733200e88f075 100644 (file)
@@ -6,6 +6,7 @@ import org.osgi.framework.BundleContext;
 
 import eu.etaxonomy.taxeditor.editor.EditorStateManager;
 import eu.etaxonomy.taxeditor.editor.UseObjectManager;
 
 import eu.etaxonomy.taxeditor.editor.EditorStateManager;
 import eu.etaxonomy.taxeditor.editor.UseObjectManager;
+import eu.etaxonomy.taxeditor.editor.validation.ValidationContextListener;
 import eu.etaxonomy.taxeditor.store.CdmStore;
 
 /**
 import eu.etaxonomy.taxeditor.store.CdmStore;
 
 /**
@@ -43,6 +44,9 @@ public class TaxeditorEditorPlugin extends AbstractUIPlugin {
                EditorStateManager stateManager = new EditorStateManager();
                CdmStore.getContextManager().addContextListener(stateManager);
                
                EditorStateManager stateManager = new EditorStateManager();
                CdmStore.getContextManager().addContextListener(stateManager);
                
+               ValidationContextListener vcl = new ValidationContextListener();
+               CdmStore.getContextManager().addContextListener(vcl);
+               
                plugin = this;
                logger.trace("Plugin started: " + this.getBundle().getSymbolicName());
        }
                plugin = this;
                logger.trace("Plugin started: " + this.getBundle().getSymbolicName());
        }
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/MarkerManager.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/MarkerManager.java
new file mode 100644 (file)
index 0000000..fa46f70
--- /dev/null
@@ -0,0 +1,290 @@
+package eu.etaxonomy.taxeditor.editor.validation;\r
+\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import javax.xml.validation.Validator;\r
+\r
+import org.eclipse.core.resources.IMarker;\r
+import org.eclipse.core.resources.IResource;\r
+import org.eclipse.core.resources.IWorkspaceRoot;\r
+import org.eclipse.core.resources.ResourcesPlugin;\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.Severity;\r
+\r
+/**\r
+ * A class responsible for refreshing problem markers coming from the CVI\r
+ * (Cdmlib Validation Infrastructure).\r
+ * \r
+ * @author ayco_holleman\r
+ * \r
+ */\r
+/*\r
+ * See following for problems with icons in Problems view\r
+ * http://stackoverflow.com\r
+ * /questions/13497258/markers-view-shows-my-marker-with-\r
+ * a-red-square-insted-of-error-warning-icon\r
+ * http://stackoverflow.com/questions/2888207\r
+ * /eclipse-plugin-custom-icon-for-a-marker\r
+ * http://www.eclipse.org/articles/Article-Mark%20My%20Words/mark-my-words.html\r
+ * http\r
+ * ://cubussapiens.hu/2010/11/markers-and-annotations-in-eclipse-for-error-feedback\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
+\r
+}\r
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/ValidationContextListener.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/ValidationContextListener.java
new file mode 100644 (file)
index 0000000..2c47e92
--- /dev/null
@@ -0,0 +1,76 @@
+package eu.etaxonomy.taxeditor.editor.validation;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.ui.IMemento;\r
+\r
+import eu.etaxonomy.taxeditor.editor.internal.TaxeditorEditorPlugin;\r
+import eu.etaxonomy.taxeditor.model.IContextListener;\r
+\r
+/**\r
+ * An {@code IContextListener} responsible for starting the\r
+ * {@link ValidationDaemon}.\r
+ * \r
+ * @see TaxeditorEditorPlugin#start(org.osgi.framework.BundleContext)\r
+ * \r
+ * @author ayco_holleman\r
+ * \r
+ */\r
+public class ValidationContextListener implements IContextListener {\r
+\r
+       @SuppressWarnings("unused")\r
+       private static final Logger logger = Logger.getLogger(ValidationContextListener.class);\r
+\r
+       private ValidationDaemon daemon;\r
+\r
+\r
+       public ValidationContextListener(){\r
+       }\r
+\r
+\r
+       @Override\r
+       public void contextAboutToStop(IMemento memento, IProgressMonitor monitor){\r
+               if (daemon != null) {\r
+                       daemon.cancel();\r
+                       daemon.setCancelRequested();\r
+               }\r
+       }\r
+\r
+\r
+       @Override\r
+       public void contextStop(IMemento memento, IProgressMonitor monitor){\r
+               if (daemon != null) {\r
+                       daemon.cancel();\r
+                       daemon.setCancelRequested();\r
+               }\r
+       }\r
+\r
+\r
+       @Override\r
+       public void contextStart(IMemento memento, IProgressMonitor monitor){\r
+               if (daemon == null) {\r
+                       daemon = new ValidationDaemon();\r
+               }\r
+               daemon.schedule();\r
+       }\r
+\r
+\r
+       @Override\r
+       public void contextRefresh(IProgressMonitor monitor){\r
+               if (daemon != null) {\r
+                       daemon.cancel();\r
+                       daemon.setCancelRequested();\r
+               }\r
+       }\r
+\r
+\r
+       @Override\r
+       public void workbenchShutdown(IMemento memento, IProgressMonitor monitor){\r
+               if (daemon != null) {\r
+                       daemon.cancel();\r
+                       daemon.setCancelRequested();\r
+                       daemon = null;\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/ValidationDaemon.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/validation/ValidationDaemon.java
new file mode 100644 (file)
index 0000000..466c220
--- /dev/null
@@ -0,0 +1,86 @@
+package eu.etaxonomy.taxeditor.editor.validation;\r
+\r
+import java.util.List;\r
+\r
+import org.apache.log4j.Logger;\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.core.runtime.jobs.Job;\r
+\r
+import eu.etaxonomy.cdm.api.service.IEntityConstraintViolationService;\r
+import eu.etaxonomy.cdm.api.service.IEntityValidationResultService;\r
+import eu.etaxonomy.cdm.model.validation.EntityValidationResult;\r
+import eu.etaxonomy.taxeditor.model.MessagingUtils;\r
+import eu.etaxonomy.taxeditor.store.CdmStore;\r
+\r
+/**\r
+ * A job that repeatedly checks the error tables and refreshes the problem\r
+ * markers created from them.\r
+ * \r
+ * @author ayco_holleman\r
+ * \r
+ */\r
+public class ValidationDaemon extends Job {\r
+\r
+       @SuppressWarnings("unused")\r
+       private static final Logger logger = Logger.getLogger(ValidationDaemon.class);\r
+\r
+       private final IEntityValidationResultService validationResultService;\r
+       \r
+       @SuppressWarnings("unused")\r
+       /* Not currently needed but present for future use if/when required */\r
+       private final IEntityConstraintViolationService constraintViolationService;\r
+\r
+       private boolean cancelRequested = false;\r
+\r
+       public ValidationDaemon(){\r
+               super("Initializing validation module");\r
+//             StoreUtil.info("Initializing validation module");\r
+               MessagingUtils.info("Initializing validation module");\r
+               constraintViolationService = CdmStore.getService(IEntityConstraintViolationService.class);\r
+               validationResultService = CdmStore.getService(IEntityValidationResultService.class);\r
+       }\r
+\r
+       \r
+       @Override\r
+       protected void canceling(){\r
+               cancelRequested = true;\r
+       }\r
+\r
+\r
+       /**\r
+        * This method is called by {@link ValidationContextListener} rather than\r
+        * {@link Job#cancel()}, because that method does not have the desired\r
+        * effect.\r
+        */\r
+       public void setCancelRequested(){\r
+               cancelRequested = true;\r
+       }\r
+\r
+\r
+       @Override\r
+       protected IStatus run(IProgressMonitor monitor){\r
+               MarkerManager markerManager;\r
+               List<EntityValidationResult> results;\r
+               try {\r
+                       while (!cancelRequested) {\r
+                               results = validationResultService.getValidationResults();\r
+                               markerManager = new MarkerManager(results);\r
+                               markerManager.deleteObsoleteMarkers();\r
+                               markerManager.createMarkers();\r
+                               // Might want to make this configurable:\r
+                               Thread.sleep(5000);\r
+                       }\r
+//                     StoreUtil.info("Validation module stopped");\r
+                       MessagingUtils.info("Validation module stopped");\r
+                       return Status.OK_STATUS;\r
+               }\r
+               catch (Throwable t) {\r
+//                     StoreUtil.info("Validation module terminated unexpectedly: " + t.getMessage());\r
+                       MessagingUtils.info("Validation module terminated unexpectedly: " + t.getMessage());\r
+                       return Status.CANCEL_STATUS;\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/EntityClassMarkerField.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/EntityClassMarkerField.java
new file mode 100644 (file)
index 0000000..6a13ceb
--- /dev/null
@@ -0,0 +1,22 @@
+package eu.etaxonomy.taxeditor.editor.view.validation;\r
+\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.ui.views.markers.MarkerField;\r
+import org.eclipse.ui.views.markers.MarkerItem;\r
+\r
+import eu.etaxonomy.taxeditor.editor.validation.MarkerManager;\r
+\r
+public class EntityClassMarkerField extends MarkerField {\r
+\r
+       @Override\r
+       public String getValue(MarkerItem item)\r
+       {\r
+               try {\r
+                       Object value = item.getMarker().getAttribute(MarkerManager.ATTRIB_ENTITY_CLASS);\r
+                       return value == null ? "" : value.toString();\r
+               }\r
+               catch (CoreException e) {\r
+                       throw new RuntimeException("Error while retrieving value for " + MarkerManager.ATTRIB_ENTITY_CLASS);\r
+               }\r
+       }\r
+}\r
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/EntityIdMarkerField.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/EntityIdMarkerField.java
new file mode 100644 (file)
index 0000000..40ec33c
--- /dev/null
@@ -0,0 +1,22 @@
+package eu.etaxonomy.taxeditor.editor.view.validation;\r
+\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.ui.views.markers.MarkerField;\r
+import org.eclipse.ui.views.markers.MarkerItem;\r
+\r
+import eu.etaxonomy.taxeditor.editor.validation.MarkerManager;\r
+\r
+public class EntityIdMarkerField extends MarkerField {\r
+\r
+       @Override\r
+       public String getValue(MarkerItem item)\r
+       {\r
+               try {\r
+                       Object value = item.getMarker().getAttribute(MarkerManager.ATTRIB_ENTITY_ID);\r
+                       return value == null ? "" : value.toString();\r
+               }\r
+               catch (CoreException e) {\r
+                       throw new RuntimeException("Error while retrieving value for " + MarkerManager.ATTRIB_ENTITY_ID);\r
+               }\r
+       }\r
+}\r
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/InvalidValueMarkerField.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/InvalidValueMarkerField.java
new file mode 100644 (file)
index 0000000..b82324f
--- /dev/null
@@ -0,0 +1,22 @@
+package eu.etaxonomy.taxeditor.editor.view.validation;\r
+\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.ui.views.markers.MarkerField;\r
+import org.eclipse.ui.views.markers.MarkerItem;\r
+\r
+import eu.etaxonomy.taxeditor.editor.validation.MarkerManager;\r
+\r
+public class InvalidValueMarkerField extends MarkerField {\r
+\r
+       @Override\r
+       public String getValue(MarkerItem item)\r
+       {\r
+               try {\r
+                       Object value = item.getMarker().getAttribute(MarkerManager.ATTRIB_INVALID_VALUE);\r
+                       return value == null ? "" : value.toString();\r
+               }\r
+               catch (CoreException e) {\r
+                       throw new RuntimeException("Error while retrieving value for " + MarkerManager.ATTRIB_INVALID_VALUE);\r
+               }\r
+       }\r
+}\r
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyDescriptionMarkerField.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyDescriptionMarkerField.java
new file mode 100644 (file)
index 0000000..0744a06
--- /dev/null
@@ -0,0 +1,23 @@
+package eu.etaxonomy.taxeditor.editor.view.validation;\r
+\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.ui.views.markers.MarkerField;\r
+import org.eclipse.ui.views.markers.MarkerItem;\r
+\r
+import eu.etaxonomy.taxeditor.editor.validation.MarkerManager;\r
+\r
+public class UserFriendlyDescriptionMarkerField extends MarkerField {\r
+\r
+       @Override\r
+       public String getValue(MarkerItem item)\r
+       {\r
+               try {\r
+                       Object value = item.getMarker().getAttribute(MarkerManager.ATTRIB_USER_FRIENDLY_DESCRIPTION);\r
+                       return value == null ? "" : value.toString();\r
+               }\r
+               catch (CoreException e) {\r
+                       throw new RuntimeException("Error while retrieving value for " + MarkerManager.ATTRIB_USER_FRIENDLY_DESCRIPTION);\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyFieldNameMarkerField.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyFieldNameMarkerField.java
new file mode 100644 (file)
index 0000000..97d3db5
--- /dev/null
@@ -0,0 +1,22 @@
+package eu.etaxonomy.taxeditor.editor.view.validation;\r
+\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.ui.views.markers.MarkerField;\r
+import org.eclipse.ui.views.markers.MarkerItem;\r
+\r
+import eu.etaxonomy.taxeditor.editor.validation.MarkerManager;\r
+\r
+public class UserFriendlyFieldNameMarkerField extends MarkerField {\r
+\r
+       @Override\r
+       public String getValue(MarkerItem item)\r
+       {\r
+               try {\r
+                       Object value = item.getMarker().getAttribute(MarkerManager.ATTRIB_USER_FRIENDLY_FIELD_NAME);\r
+                       return value == null ? "" : value.toString();\r
+               }\r
+               catch (CoreException e) {\r
+                       throw new RuntimeException("Error while retrieving value for " + MarkerManager.ATTRIB_USER_FRIENDLY_FIELD_NAME);\r
+               }\r
+       }\r
+}\r
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyTypeNameMarkerField.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/UserFriendlyTypeNameMarkerField.java
new file mode 100644 (file)
index 0000000..38419dc
--- /dev/null
@@ -0,0 +1,22 @@
+package eu.etaxonomy.taxeditor.editor.view.validation;\r
+\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.ui.views.markers.MarkerField;\r
+import org.eclipse.ui.views.markers.MarkerItem;\r
+\r
+import eu.etaxonomy.taxeditor.editor.validation.MarkerManager;\r
+\r
+public class UserFriendlyTypeNameMarkerField extends MarkerField {\r
+\r
+       @Override\r
+       public String getValue(MarkerItem item)\r
+       {\r
+               try {\r
+                       Object value = item.getMarker().getAttribute(MarkerManager.ATTRIB_USER_FRIENDLY_TYPE_NAME);\r
+                       return value == null ? "" : value.toString();\r
+               }\r
+               catch (CoreException e) {\r
+                       throw new RuntimeException("Error while retrieving value for " + MarkerManager.ATTRIB_USER_FRIENDLY_TYPE_NAME);\r
+               }\r
+       }\r
+}\r
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidationProblemsView.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidationProblemsView.java
new file mode 100644 (file)
index 0000000..d81f97b
--- /dev/null
@@ -0,0 +1,13 @@
+package eu.etaxonomy.taxeditor.editor.view.validation;\r
+\r
+import org.eclipse.ui.views.markers.MarkerSupportView;\r
+\r
+public class ValidationProblemsView extends MarkerSupportView {\r
+\r
+       public ValidationProblemsView()\r
+       {\r
+               super("eu.etaxonomy.taxeditor.editor.validation.ValidationProblemsMarkerGenerator");\r
+       }\r
+\r
+       \r
+}\r
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidatorClassMarkerField.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidatorClassMarkerField.java
new file mode 100644 (file)
index 0000000..9b8aa12
--- /dev/null
@@ -0,0 +1,23 @@
+package eu.etaxonomy.taxeditor.editor.view.validation;\r
+\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.ui.views.markers.MarkerField;\r
+import org.eclipse.ui.views.markers.MarkerItem;\r
+\r
+import eu.etaxonomy.taxeditor.editor.validation.MarkerManager;\r
+\r
+public class ValidatorClassMarkerField extends MarkerField {\r
+\r
+       @Override\r
+       public String getValue(MarkerItem item)\r
+       {\r
+               try {\r
+                       Object value = item.getMarker().getAttribute(MarkerManager.ATTRIB_VALIDATOR_CLASS);\r
+                       return value == null ? "" : value.toString();\r
+               }\r
+               catch (CoreException e) {\r
+                       throw new RuntimeException("Error while retrieving value for " + MarkerManager.ATTRIB_VALIDATOR_CLASS);\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidatorMessageMarkerField.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/validation/ValidatorMessageMarkerField.java
new file mode 100644 (file)
index 0000000..970f337
--- /dev/null
@@ -0,0 +1,23 @@
+package eu.etaxonomy.taxeditor.editor.view.validation;\r
+\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.ui.views.markers.MarkerField;\r
+import org.eclipse.ui.views.markers.MarkerItem;\r
+\r
+import eu.etaxonomy.taxeditor.editor.validation.MarkerManager;\r
+\r
+public class ValidatorMessageMarkerField extends MarkerField {\r
+\r
+       @Override\r
+       public String getValue(MarkerItem item)\r
+       {\r
+               try {\r
+                       Object value = item.getMarker().getAttribute(MarkerManager.ATTRIB_VALIDATOR_MESSAGE);\r
+                       return value == null ? "" : value.toString();\r
+               }\r
+               catch (CoreException e) {\r
+                       throw new RuntimeException("Error while retrieving value for " + MarkerManager.ATTRIB_VALIDATOR_MESSAGE);\r
+               }\r
+       }\r
+\r
+}\r