From 21adfb988c818b391a32a6fb03835a1f470b9df4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andreas=20M=C3=BCller?= Date: Thu, 19 Mar 2015 21:36:16 +0000 Subject: [PATCH] --- .../editor/validation/MarkerManager.java | 427 ++++++++---------- .../editor/validation/ValidationDaemon.java | 42 +- .../TransientCdmRepository.java | 6 +- .../TransientOccurenceService.java | 12 - 4 files changed, 199 insertions(+), 288 deletions(-) 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 index fa46f7094..4a5f2cdf9 100644 --- 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 @@ -1,6 +1,6 @@ package eu.etaxonomy.taxeditor.editor.validation; -import java.util.HashMap; +import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -13,16 +13,17 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import eu.etaxonomy.cdm.model.validation.EntityConstraintViolation; -import eu.etaxonomy.cdm.model.validation.EntityValidationResult; +import eu.etaxonomy.cdm.model.validation.EntityValidation; import eu.etaxonomy.cdm.model.validation.Severity; /** * A class responsible for refreshing problem markers coming from the CVI * (Cdmlib Validation Infrastructure). - * + * * @author ayco_holleman - * + * */ + /* * See following for problems with icons in Problems view * http://stackoverflow.com @@ -34,257 +35,183 @@ import eu.etaxonomy.cdm.model.validation.Severity; * http * ://cubussapiens.hu/2010/11/markers-and-annotations-in-eclipse-for-error-feedback * / - * + * * See here for difficulty of attaching markers to non-resources (files, * folders): * http://stackoverflow.com/questions/12493179/eclipse-virtual-resources */ public class MarkerManager { - public static final String MARKER_TYPE_ID = "eu.etaxonomy.taxeditor.markers.validationerror"; - - /** - * The primary key (id) of the EntityValidationResult record - */ - public static final String ATTRIB_DATABASE_ID = "databaseId"; - - // The values of the following constants must correspond to the attributes - // defined for the org.eclipse.core.resources.markers extension point in - // plugin.xml - - /** - * A user-friendly description of the type of the entity - */ - public static final String ATTRIB_USER_FRIENDLY_TYPE_NAME = "userFriendlyTypeName"; - /** - * A user-friendly description of the entity - */ - public static final String ATTRIB_USER_FRIENDLY_DESCRIPTION = "userFriendlyDescription"; - /** - * The field whose value violated a constraint - */ - public static final String ATTRIB_USER_FRIENDLY_FIELD_NAME = "userFriendlyFieldName"; - /** - * The value violating a constraint - */ - public static final String ATTRIB_INVALID_VALUE = "invalidValue"; - /** - * The message from the {@link Validator} about what was wrong. - */ - public static final String ATTRIB_VALIDATOR_MESSAGE = "validatorMessage"; - /** - * The class of the {@link Validator} coding for the constraint - */ - public static final String ATTRIB_VALIDATOR_CLASS = "validatorClass"; - /** - * The class of the validated entity - */ - public static final String ATTRIB_ENTITY_CLASS = "entityClass"; - /** - * The id of the validated entity - */ - public static final String ATTRIB_ENTITY_ID = "entityId"; - - private final IWorkspaceRoot root; - private final IMarker[] markers; - private final List results; - private final HashMap resultMap; - private final HashMap markerMap; - - - MarkerManager(List results) throws CoreException - { - this.root = ResourcesPlugin.getWorkspace().getRoot(); - this.markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE); - this.markerMap = new HashMap(); - for (IMarker marker : markers) { - markerMap.put(getDatabaseId(marker), marker); - } - this.results = results; - this.resultMap = new HashMap(); - for (EntityValidationResult result : results) { - resultMap.put(result.getId(), result); - } - } - - - /** - * Delete all markers that refer to errors that do not exist any longer - * (i.e. the corresponding database record has been deleted). - * - * @return The number of deleted markers - * - * @throws CoreException - */ - int deleteObsoleteMarkers() throws CoreException - { - int i = 0; - IMarker[] markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE); - for (IMarker marker : markers) { - if (isObsoleteMarker(marker)) { - ++i; - marker.delete(); - } - } - return i; - } - - - /** - * Create markers for new errors (i.e. no marker has been created for them - * yet). - * - * @return The number of new markers - * - * @throws CoreException - */ - int createMarkers() throws CoreException - { - int i = 0; - IMarker[] markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE); - for (EntityValidationResult result : results) { - if (!isNewResult(result)) { - continue; - } - Set problems = result.getEntityConstraintViolations(); - for (EntityConstraintViolation problem : problems) { - if (markerExistsForProblem(problem, markers)) { - continue; - } - IMarker marker = root.createMarker(MARKER_TYPE_ID); - ++i; - if (problem.getSeverity() == Severity.ERROR) { - marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); - } - else if (problem.getSeverity() == Severity.WARNING) { - marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING); - } - else { - marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO); - } - marker.setAttribute(IMarker.MESSAGE, problem.getMessage()); - marker.setAttribute(ATTRIB_DATABASE_ID, result.getId()); - marker.setAttribute(ATTRIB_USER_FRIENDLY_TYPE_NAME, result.getUserFriendlyTypeName()); - marker.setAttribute(ATTRIB_USER_FRIENDLY_DESCRIPTION, result.getUserFriendlyDescription()); - marker.setAttribute(ATTRIB_USER_FRIENDLY_FIELD_NAME, problem.getUserFriendlyFieldName()); - marker.setAttribute(ATTRIB_VALIDATOR_MESSAGE, problem.getMessage()); - marker.setAttribute(ATTRIB_INVALID_VALUE, problem.getInvalidValue()); - marker.setAttribute(ATTRIB_VALIDATOR_CLASS, problem.getValidator()); - marker.setAttribute(ATTRIB_ENTITY_CLASS, result.getValidatedEntityClass()); - marker.setAttribute(ATTRIB_ENTITY_ID, result.getValidatedEntityId()); - } - } - return i; - } - - - /** - * Is there a problem marker that captures the specified - * {@link EntityConstraintViolation}? See - * {@link #markerCapturesProblem(IMarker, EntityConstraintViolation)}. - * - * @param problem - * @param markers - * @return - * @throws CoreException - */ - private boolean markerExistsForProblem(EntityConstraintViolation problem, IMarker[] markers) throws CoreException - { - for (IMarker marker : markers) { - if (markerCapturesProblem(marker, problem)) { - return true; - } - } - return false; - } - - - /** - *

- * This method determines whether the problem exposed by the specified - * marker is de facto equivalent to the specified - * {@code EntityConstraintViolation}. When the CVI validates an entity, it - * first deletes previous validation results for that entity and only then - * saves the new validation result. Thus you cannot rely on the database id - * of the {@code EntityConstraintViolation} to determine equivalence. Maybe - * later we can make the CVI more sophisticated in this respect. Or maybe - * see if solving it through the equals() method of - * {@code EntityValidationResult} and/or {@code EntityConstraintViolation} - * is possible. But for now this is the easiest solution. - *

- *

- * The reason we check for equivalence, is that we don't want to - * unnecessarily update the Problems view. If a marker is there, we don't - * want to replace it with an equivalent marker, because that might lead to - * strange click behaviour for end users (e.g. selected problems will - * disappear and re-appear unselected). - *

- * - * @param marker - * @param problem - * @return - * @throws CoreException - */ - private static boolean markerCapturesProblem(IMarker marker, EntityConstraintViolation problem) throws CoreException - { - EntityValidationResult result = problem.getEntityValidationResult(); - if (!marker.getAttribute(ATTRIB_ENTITY_CLASS).equals(result.getValidatedEntityClass())) { - return false; - } - if (!marker.getAttribute(ATTRIB_ENTITY_ID).equals(result.getValidatedEntityId())) { - return false; - } - if (!marker.getAttribute(ATTRIB_USER_FRIENDLY_FIELD_NAME).equals(problem.getPropertyPath())) { - return false; - } - if (!marker.getAttribute(ATTRIB_INVALID_VALUE).equals(problem.getInvalidValue())) { - return false; - } - if (!marker.getAttribute(ATTRIB_VALIDATOR_CLASS).equals(problem.getValidator())) { - return false; - } - return true; - } - - - /** - * Is this a marker without a corresponding database record ( - * {@link EntityValidationResult})? - * - * @param marker - * @return - * @throws CoreException - */ - private boolean isObsoleteMarker(IMarker marker) throws CoreException - { - return resultMap.get(getDatabaseId(marker)) == null; - } - - - /** - * Is this an {@link EntityValidationResult} for which no marker has been - * created yet? - * - * @param result - * @return - */ - private boolean isNewResult(EntityValidationResult result) - { - return markerMap.get(result.getId()) == null; - } - - - /** - * Get the id of the {@link EntityValidationResult} that was stored as one - * of the marker's attributes. - * - * @param marker - * @return - * @throws CoreException - */ - private static Integer getDatabaseId(IMarker marker) throws CoreException - { - return (Integer) marker.getAttribute(ATTRIB_DATABASE_ID); - } + public static final String MARKER_TYPE_ID = "eu.etaxonomy.taxeditor.markers.validationerror"; + + /** + * The primary key (id) of the EntityConstraintViolation record + */ + public static final String ATTRIB_DATABASE_ID = "databaseId"; + + // The values of the following constants must correspond to the attributes + // defined for the org.eclipse.core.resources.markers extension point in + // plugin.xml + + /** + * A user-friendly description of the type of the entity + */ + public static final String ATTRIB_USER_FRIENDLY_TYPE_NAME = "userFriendlyTypeName"; + /** + * A user-friendly description of the entity + */ + public static final String ATTRIB_USER_FRIENDLY_DESCRIPTION = "userFriendlyDescription"; + /** + * The field whose value violated a constraint + */ + public static final String ATTRIB_USER_FRIENDLY_FIELD_NAME = "userFriendlyFieldName"; + /** + * The value violating a constraint + */ + public static final String ATTRIB_INVALID_VALUE = "invalidValue"; + /** + * The message from the {@link Validator} about what was wrong. + */ + public static final String ATTRIB_VALIDATOR_MESSAGE = "validatorMessage"; + /** + * The class of the {@link Validator} coding for the constraint + */ + public static final String ATTRIB_VALIDATOR_CLASS = "validatorClass"; + /** + * The class of the validated entity + */ + public static final String ATTRIB_ENTITY_CLASS = "entityClass"; + /** + * The id of the validated entity + */ + public static final String ATTRIB_ENTITY_ID = "entityId"; + + private final List problems; + + MarkerManager(List results) { + this.problems = new ArrayList(); + for (EntityValidation result : results) { + Set problemsPerEntity = result.getEntityConstraintViolations(); + for (EntityConstraintViolation problem : problemsPerEntity) { + problem.setEntityValidation(result); + problems.add(problem); + } + } + //MessagingUtils.info("Number of validation errors: " + problems.size()); + } + + /** + * Delete all markers that refer to errors that do not exist any longer + * (i.e. the corresponding database record has been deleted). + * + * @return The number of deleted markers + * + * @throws CoreException + */ + int deleteObsoleteMarkers() throws CoreException { + int i = 0; + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IMarker[] markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE); + for (IMarker marker : markers) { + if (isObsoleteMarker(marker)) { + ++i; + marker.delete(); + } + } + //MessagingUtils.info("Obsolete markers: " + i); + return i; + } + + /** + * Create markers for new errors (i.e. no marker has been created for them + * yet). + * + * @return The number of new markers + * + * @throws CoreException + */ + int createMarkers() throws CoreException { + int i = 0; + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IMarker[] markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE); + for (EntityConstraintViolation problem : problems) { + if (isNewProblem(problem, markers)) { + ++i; + IMarker marker = root.createMarker(MARKER_TYPE_ID); + if (problem.getSeverity() == Severity.ERROR) { + marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); + } else if (problem.getSeverity() == Severity.WARNING) { + marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING); + } else { + marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO); + } + EntityValidation result = problem.getEntityValidation(); + marker.setAttribute(IMarker.MESSAGE, problem.getMessage()); + marker.setAttribute(ATTRIB_DATABASE_ID, new Integer(problem.getId())); + marker.setAttribute(ATTRIB_USER_FRIENDLY_TYPE_NAME, result.getUserFriendlyTypeName()); + marker.setAttribute(ATTRIB_USER_FRIENDLY_DESCRIPTION, result.getUserFriendlyDescription()); + marker.setAttribute(ATTRIB_USER_FRIENDLY_FIELD_NAME, problem.getUserFriendlyFieldName()); + marker.setAttribute(ATTRIB_VALIDATOR_MESSAGE, problem.getMessage()); + marker.setAttribute(ATTRIB_INVALID_VALUE, problem.getInvalidValue()); + marker.setAttribute(ATTRIB_VALIDATOR_CLASS, problem.getValidator()); + marker.setAttribute(ATTRIB_ENTITY_CLASS, result.getValidatedEntityClass()); + marker.setAttribute(ATTRIB_ENTITY_ID, result.getValidatedEntityId()); + } + } + //MessagingUtils.info("New problems: " + i); + return i; + } + + private boolean isObsoleteMarker(IMarker marker) throws CoreException { + for (EntityConstraintViolation problem : problems) { + if (isMarkerForProblem(marker, problem)) { + return false; + } + } + return true; + } + + private static boolean isNewProblem(EntityConstraintViolation problem, IMarker[] markers) throws CoreException { + for (IMarker marker : markers) { + if (isMarkerForProblem(marker, problem)) { + return false; + } + } + return true; + } + + private static boolean isMarkerForProblem(IMarker marker, EntityConstraintViolation problem) throws CoreException { + if (isEqual(marker, ATTRIB_DATABASE_ID, new Integer(problem.getId()))) { + return true; + } + EntityValidation result = problem.getEntityValidation(); + if (!isEqual(marker, ATTRIB_ENTITY_ID, result.getValidatedEntityId())) { + return false; + } + if (!isEqual(marker, ATTRIB_INVALID_VALUE, problem.getInvalidValue())) { + return false; + } + if (!isEqual(marker, ATTRIB_ENTITY_CLASS, result.getValidatedEntityClass())) { + return false; + } + if (!isEqual(marker, ATTRIB_USER_FRIENDLY_FIELD_NAME, problem.getUserFriendlyFieldName())) { + return false; + } + if (!isEqual(marker, ATTRIB_VALIDATOR_CLASS, problem.getValidator())) { + return false; + } + return true; + } + + private static boolean isEqual(IMarker marker, String attribute, Object value) throws CoreException { + Object val = marker.getAttribute(attribute); + boolean equal; + if (val == null) { + equal = value == null; + } else { + equal = value != null && val.equals(value); + } + return equal; + } } 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 index 466c22041..1a22142ea 100644 --- 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 @@ -8,43 +8,39 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; -import eu.etaxonomy.cdm.api.service.IEntityConstraintViolationService; -import eu.etaxonomy.cdm.api.service.IEntityValidationResultService; -import eu.etaxonomy.cdm.model.validation.EntityValidationResult; +import eu.etaxonomy.cdm.api.service.IEntityValidationService; +import eu.etaxonomy.cdm.model.validation.EntityValidation; import eu.etaxonomy.taxeditor.model.MessagingUtils; import eu.etaxonomy.taxeditor.store.CdmStore; /** * A job that repeatedly checks the error tables and refreshes the problem * markers created from them. - * + * * @author ayco_holleman - * + * */ public class ValidationDaemon extends Job { @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(ValidationDaemon.class); - private final IEntityValidationResultService validationResultService; - - @SuppressWarnings("unused") - /* Not currently needed but present for future use if/when required */ - private final IEntityConstraintViolationService constraintViolationService; + private final IEntityValidationService validationResultService; private boolean cancelRequested = false; - public ValidationDaemon(){ - super("Initializing validation module"); -// StoreUtil.info("Initializing validation module"); - MessagingUtils.info("Initializing validation module"); - constraintViolationService = CdmStore.getService(IEntityConstraintViolationService.class); - validationResultService = CdmStore.getService(IEntityValidationResultService.class); + + + public ValidationDaemon() + { + super("Running validation daemon"); + validationResultService = CdmStore.getService(IEntityValidationService.class); } - + @Override - protected void canceling(){ + protected void canceling() + { cancelRequested = true; } @@ -54,15 +50,17 @@ public class ValidationDaemon extends Job { * {@link Job#cancel()}, because that method does not have the desired * effect. */ - public void setCancelRequested(){ + public void setCancelRequested() + { cancelRequested = true; } @Override - protected IStatus run(IProgressMonitor monitor){ + protected IStatus run(IProgressMonitor monitor) + { MarkerManager markerManager; - List results; + List results; try { while (!cancelRequested) { results = validationResultService.getValidationResults(); @@ -72,12 +70,10 @@ public class ValidationDaemon extends Job { // Might want to make this configurable: Thread.sleep(5000); } -// StoreUtil.info("Validation module stopped"); MessagingUtils.info("Validation module stopped"); return Status.OK_STATUS; } catch (Throwable t) { -// StoreUtil.info("Validation module terminated unexpectedly: " + t.getMessage()); MessagingUtils.info("Validation module terminated unexpectedly: " + t.getMessage()); return Status.CANCEL_STATUS; } diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientCdmRepository.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientCdmRepository.java index 5a29a76f3..caa699189 100644 --- a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientCdmRepository.java +++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientCdmRepository.java @@ -24,7 +24,7 @@ import eu.etaxonomy.cdm.api.service.ICommonService; import eu.etaxonomy.cdm.api.service.IDatabaseService; import eu.etaxonomy.cdm.api.service.IDescriptionService; import eu.etaxonomy.cdm.api.service.IEntityConstraintViolationService; -import eu.etaxonomy.cdm.api.service.IEntityValidationResultService; +import eu.etaxonomy.cdm.api.service.IEntityValidationService; import eu.etaxonomy.cdm.api.service.IFeatureNodeService; import eu.etaxonomy.cdm.api.service.IFeatureTreeService; import eu.etaxonomy.cdm.api.service.IGrantedAuthorityService; @@ -406,7 +406,7 @@ public class TransientCdmRepository implements ICdmApplicationConfiguration { } @Override - public IEntityValidationResultService getEntityValidationResultService() { - return defaultApplicationConfiguration.getEntityValidationResultService(); + public IEntityValidationService getEntityValidationService() { + return defaultApplicationConfiguration.getEntityValidationService(); } } diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientOccurenceService.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientOccurenceService.java index 4a59f3d5b..7231136c0 100644 --- a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientOccurenceService.java +++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/view/dataimport/transientServices/TransientOccurenceService.java @@ -922,18 +922,12 @@ public class TransientOccurenceService implements IOccurrenceService { return defaultService.findWithoutFlush(uuid); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listFieldUnitsByAssociatedTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List, java.util.List) - */ @Override public Collection listFieldUnitsByAssociatedTaxon(Taxon associatedTaxon, List orderHints, List propertyPaths) { return defaultService.listFieldUnitsByAssociatedTaxon(associatedTaxon, orderHints, propertyPaths); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#pageFieldUnitsByAssociatedTaxon(java.util.Set, eu.etaxonomy.cdm.model.taxon.Taxon, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List) - */ @Override public Pager pageFieldUnitsByAssociatedTaxon( Set includeRelationships, Taxon associatedTaxon, Integer maxDepth, Integer pageSize, @@ -942,17 +936,11 @@ public class TransientOccurenceService implements IOccurrenceService { } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#assembleDerivateHierarchyDTO(eu.etaxonomy.cdm.model.occurrence.FieldUnit, java.util.UUID) - */ @Override public DerivateHierarchyDTO assembleDerivateHierarchyDTO(FieldUnit fieldUnit, UUID associatedTaxonUuid) { return defaultService.assembleDerivateHierarchyDTO(fieldUnit, associatedTaxonUuid); } - /* (non-Javadoc) - * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getNonCascadedAssociatedElements(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.api.conversation.ConversationHolder) - */ @Override public Collection getNonCascadedAssociatedElements(SpecimenOrObservationBase specimen) { return defaultService.getNonCascadedAssociatedElements(specimen); -- 2.34.1