Merge branch 'release/4.6.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.editor / src / main / java / eu / etaxonomy / taxeditor / editor / validation / MarkerManager.java
1 package eu.etaxonomy.taxeditor.editor.validation;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Set;
6
7 import javax.xml.validation.Validator;
8
9 import org.eclipse.core.resources.IMarker;
10 import org.eclipse.core.resources.IResource;
11 import org.eclipse.core.resources.IWorkspaceRoot;
12 import org.eclipse.core.resources.ResourcesPlugin;
13 import org.eclipse.core.runtime.CoreException;
14
15 import eu.etaxonomy.cdm.model.validation.EntityConstraintViolation;
16 import eu.etaxonomy.cdm.model.validation.EntityValidation;
17 import eu.etaxonomy.cdm.model.validation.Severity;
18
19 /**
20 * A class responsible for refreshing problem markers coming from the CVI
21 * (Cdmlib Validation Infrastructure).
22 *
23 * @author ayco_holleman
24 *
25 */
26
27 /*
28 * See following for problems with icons in Problems view
29 * http://stackoverflow.com
30 * /questions/13497258/markers-view-shows-my-marker-with-
31 * a-red-square-insted-of-error-warning-icon
32 * http://stackoverflow.com/questions/2888207
33 * /eclipse-plugin-custom-icon-for-a-marker
34 * http://www.eclipse.org/articles/Article-Mark%20My%20Words/mark-my-words.html
35 * http
36 * ://cubussapiens.hu/2010/11/markers-and-annotations-in-eclipse-for-error-feedback
37 * /
38 *
39 * See here for difficulty of attaching markers to non-resources (files,
40 * folders):
41 * http://stackoverflow.com/questions/12493179/eclipse-virtual-resources
42 */
43 public class MarkerManager {
44
45 public static final String MARKER_TYPE_ID = "eu.etaxonomy.taxeditor.markers.validationerror"; //$NON-NLS-1$
46
47 /**
48 * The primary key (id) of the EntityConstraintViolation record
49 */
50 public static final String ATTRIB_DATABASE_ID = "databaseId"; //$NON-NLS-1$
51
52 // The values of the following constants must correspond to the attributes
53 // defined for the org.eclipse.core.resources.markers extension point in
54 // plugin.xml
55
56 /**
57 * A user-friendly description of the type of the entity
58 */
59 public static final String ATTRIB_USER_FRIENDLY_TYPE_NAME = "userFriendlyTypeName"; //$NON-NLS-1$
60 /**
61 * A user-friendly description of the entity
62 */
63 public static final String ATTRIB_USER_FRIENDLY_DESCRIPTION = "userFriendlyDescription"; //$NON-NLS-1$
64 /**
65 * The field whose value violated a constraint
66 */
67 public static final String ATTRIB_USER_FRIENDLY_FIELD_NAME = "userFriendlyFieldName"; //$NON-NLS-1$
68 /**
69 * The value violating a constraint
70 */
71 public static final String ATTRIB_INVALID_VALUE = "invalidValue"; //$NON-NLS-1$
72 /**
73 * The message from the {@link Validator} about what was wrong.
74 */
75 public static final String ATTRIB_VALIDATOR_MESSAGE = "validatorMessage"; //$NON-NLS-1$
76 /**
77 * The class of the {@link Validator} coding for the constraint
78 */
79 public static final String ATTRIB_VALIDATOR_CLASS = "validatorClass"; //$NON-NLS-1$
80 /**
81 * The class of the validated entity
82 */
83 public static final String ATTRIB_ENTITY_CLASS = "entityClass"; //$NON-NLS-1$
84 /**
85 * The id of the validated entity
86 */
87 public static final String ATTRIB_ENTITY_ID = "entityId"; //$NON-NLS-1$
88
89 private final List<EntityConstraintViolation> problems;
90
91 MarkerManager(List<EntityValidation> results) {
92 this.problems = new ArrayList<EntityConstraintViolation>();
93 for (EntityValidation result : results) {
94 Set<EntityConstraintViolation> problemsPerEntity = result.getEntityConstraintViolations();
95 for (EntityConstraintViolation problem : problemsPerEntity) {
96 problem.setEntityValidation(result);
97 problems.add(problem);
98 }
99 }
100 //MessagingUtils.info("Number of validation errors: " + problems.size());
101 }
102
103 /**
104 * Delete all markers that refer to errors that do not exist any longer
105 * (i.e. the corresponding database record has been deleted).
106 *
107 * @return The number of deleted markers
108 *
109 * @throws CoreException
110 */
111 int deleteObsoleteMarkers() throws CoreException {
112 int i = 0;
113 IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
114 IMarker[] markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE);
115 for (IMarker marker : markers) {
116 if (isObsoleteMarker(marker)) {
117 ++i;
118 marker.delete();
119 }
120 }
121 //MessagingUtils.info("Obsolete markers: " + i);
122 return i;
123 }
124
125 /**
126 * Create markers for new errors (i.e. no marker has been created for them
127 * yet).
128 *
129 * @return The number of new markers
130 *
131 * @throws CoreException
132 */
133 int createMarkers() throws CoreException {
134 int i = 0;
135 IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
136 IMarker[] markers = root.findMarkers(MARKER_TYPE_ID, true, IResource.DEPTH_INFINITE);
137 for (EntityConstraintViolation problem : problems) {
138 if (isNewProblem(problem, markers)) {
139 ++i;
140 IMarker marker = root.createMarker(MARKER_TYPE_ID);
141 if (problem.getSeverity() == Severity.ERROR) {
142 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
143 } else if (problem.getSeverity() == Severity.WARNING) {
144 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
145 } else {
146 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
147 }
148 EntityValidation result = problem.getEntityValidation();
149 marker.setAttribute(IMarker.MESSAGE, problem.getMessage());
150 marker.setAttribute(ATTRIB_DATABASE_ID, new Integer(problem.getId()));
151 marker.setAttribute(ATTRIB_USER_FRIENDLY_TYPE_NAME, result.getUserFriendlyTypeName());
152 marker.setAttribute(ATTRIB_USER_FRIENDLY_DESCRIPTION, result.getUserFriendlyDescription());
153 marker.setAttribute(ATTRIB_USER_FRIENDLY_FIELD_NAME, problem.getUserFriendlyFieldName());
154 marker.setAttribute(ATTRIB_VALIDATOR_MESSAGE, problem.getMessage());
155 marker.setAttribute(ATTRIB_INVALID_VALUE, problem.getInvalidValue());
156 marker.setAttribute(ATTRIB_VALIDATOR_CLASS, problem.getValidator());
157 marker.setAttribute(ATTRIB_ENTITY_CLASS, result.getValidatedEntityClass());
158 marker.setAttribute(ATTRIB_ENTITY_ID, result.getValidatedEntityId());
159 }
160 }
161 //MessagingUtils.info("New problems: " + i);
162 return i;
163 }
164
165 private boolean isObsoleteMarker(IMarker marker) throws CoreException {
166 for (EntityConstraintViolation problem : problems) {
167 if (isMarkerForProblem(marker, problem)) {
168 return false;
169 }
170 }
171 return true;
172 }
173
174 private static boolean isNewProblem(EntityConstraintViolation problem, IMarker[] markers) throws CoreException {
175 for (IMarker marker : markers) {
176 if (isMarkerForProblem(marker, problem)) {
177 return false;
178 }
179 }
180 return true;
181 }
182
183 private static boolean isMarkerForProblem(IMarker marker, EntityConstraintViolation problem) throws CoreException {
184 if (isEqual(marker, ATTRIB_DATABASE_ID, new Integer(problem.getId()))) {
185 return true;
186 }
187 EntityValidation result = problem.getEntityValidation();
188 if (!isEqual(marker, ATTRIB_ENTITY_ID, result.getValidatedEntityId())) {
189 return false;
190 }
191 if (!isEqual(marker, ATTRIB_INVALID_VALUE, problem.getInvalidValue())) {
192 return false;
193 }
194 if (!isEqual(marker, ATTRIB_ENTITY_CLASS, result.getValidatedEntityClass())) {
195 return false;
196 }
197 if (!isEqual(marker, ATTRIB_USER_FRIENDLY_FIELD_NAME, problem.getUserFriendlyFieldName())) {
198 return false;
199 }
200 if (!isEqual(marker, ATTRIB_VALIDATOR_CLASS, problem.getValidator())) {
201 return false;
202 }
203 return true;
204 }
205
206 private static boolean isEqual(IMarker marker, String attribute, Object value) throws CoreException {
207 Object val = marker.getAttribute(attribute);
208 boolean equal;
209 if (val == null) {
210 equal = value == null;
211 } else {
212 equal = value != null && val.equals(value);
213 }
214 return equal;
215 }
216
217 }