1 /*******************************************************************************
2  * Copyright (c) 2005, 2015 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.ui.views.markers.internal;
15 
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Map.Entry;
24 import java.util.Set;
25 
26 import org.eclipse.core.resources.IMarker;
27 import org.eclipse.core.runtime.CoreException;
28 import org.eclipse.core.runtime.IConfigurationElement;
29 import org.eclipse.core.runtime.IExtension;
30 import org.eclipse.core.runtime.IExtensionPoint;
31 import org.eclipse.core.runtime.IStatus;
32 import org.eclipse.core.runtime.Platform;
33 import org.eclipse.core.runtime.Status;
34 import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
35 import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
36 import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
37 import org.eclipse.osgi.util.NLS;
38 import org.eclipse.ui.PlatformUI;
39 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
40 import org.eclipse.ui.internal.ide.Policy;
41 import org.eclipse.ui.internal.views.markers.MarkerSupportInternalUtilities;
42 import org.eclipse.ui.views.markers.MarkerField;
43 
44 /**
45  * The ProblemFilterRegistryReader is the registry reader for declarative
46  * problem filters. See the org.eclipse.ui.markerSupport extension point.
47  *
48  * @since 3.2
49  *
50  */
51 public class MarkerSupportRegistry implements IExtensionChangeHandler {
52 
53 	private static final String DESCRIPTION = "onDescription"; //$NON-NLS-1$
54 
55 	/**
56 	 * The enabled attribute.
57 	 */
58 	public static final String ENABLED = "enabled"; //$NON-NLS-1$
59 
60 	private static final Object ERROR = "ERROR";//$NON-NLS-1$
61 
62 	private static final Object INFO = "INFO";//$NON-NLS-1$
63 
64 	private static final Object WARNING = "WARNING";//$NON-NLS-1$
65 
66 	private static final String MARKER_ID = "markerId"; //$NON-NLS-1$
67 
68 	/**
69 	 * Filter enablement : A zero/negative integer implies that the limit is
70 	 * disabled.
71 	 */
72 	public static final String FILTER_LIMIT = "filterLimit"; //$NON-NLS-1$
73 
74 	/**
75 	 * The tag for the marker support extension
76 	 */
77 	public static final String MARKER_SUPPORT = "markerSupport";//$NON-NLS-1$
78 
79 	private static final Object ON_ANY = "ON_ANY"; //$NON-NLS-1$
80 
81 	private static final Object ON_ANY_IN_SAME_CONTAINER = "ON_ANY_IN_SAME_CONTAINER";//$NON-NLS-1$
82 
83 	private static final Object ON_SELECTED_AND_CHILDREN = "ON_SELECTED_AND_CHILDREN";//$NON-NLS-1$
84 
85 	private static final Object ON_SELECTED_ONLY = "ON_SELECTED_ONLY"; //$NON-NLS-1$
86 
87 	private static final Object PROBLEM_FILTER = "problemFilter";//$NON-NLS-1$
88 
89 	private static final String SCOPE = "scope"; //$NON-NLS-1$
90 
91 	private static final String SELECTED_TYPE = "selectedType"; //$NON-NLS-1$
92 
93 	private static final String SEVERITY = "severity";//$NON-NLS-1$
94 
95 	/**
96 	 * The key for marker type references.
97 	 */
98 	public static final String MARKER_TYPE_REFERENCE = "markerTypeReference"; //$NON-NLS-1$
99 
100 	private static final String MARKER_CATEGORY = "markerTypeCategory";//$NON-NLS-1$
101 
102 	/**
103 	 * The markerAttributeMapping element.
104 	 */
105 	public static final String ATTRIBUTE_MAPPING = "markerAttributeMapping"; //$NON-NLS-1$
106 
107 	/**
108 	 * The tag for marker grouping.
109 	 */
110 	public static final String MARKER_GROUPING = "markerGrouping"; //$NON-NLS-1$
111 	/**
112 	 * The value attribute.
113 	 */
114 	public static final String VALUE = "value"; //$NON-NLS-1$
115 
116 	/**
117 	 * The label attribute
118 	 */
119 	public static final String LABEL = "label"; //$NON-NLS-1$
120 
121 	/**
122 	 * The attribute grouping element name.
123 	 */
124 	public static final String MARKER_ATTRIBUTE_GROUPING = "markerAttributeGrouping";//$NON-NLS-1$
125 
126 	/**
127 	 * The constant for grouping entries.
128 	 */
129 	public static final String MARKER_GROUPING_ENTRY = "markerGroupingEntry"; //$NON-NLS-1$
130 
131 	private static final Object SEVERITY_ID = "org.eclipse.ui.ide.severity";//$NON-NLS-1$
132 
133 	/**
134 	 * The tag for content generators.
135 	 */
136 	static final String MARKER_CONTENT_GENERATOR = "markerContentGenerator"; //$NON-NLS-1$
137 
138 	/**
139 	 * The tag for content generator.
140 	 */
141 	private static final String MARKER_CONTENT_GENERATOR_EXTENSION = "markerContentGeneratorExtension"; //$NON-NLS-1$
142 
143 	private static final String MARKER_FIELD = "markerField"; //$NON-NLS-1$
144 
145 	private static final String ATTRIBUTE_CLASS = "class"; //$NON-NLS-1$
146 	/**
147 	 * The bookmarks generator.
148 	 */
149 	public static final String BOOKMARKS_GENERATOR = "org.eclipse.ui.ide.bookmarksGenerator"; //$NON-NLS-1$
150 	/**
151 	 * The tasks generator.
152 	 */
153 	public static final String TASKS_GENERATOR = "org.eclipse.ui.ide.tasksGenerator"; //$NON-NLS-1$
154 
155 	/**
156 	 * The problems generator.
157 	 */
158 	public static final String PROBLEMS_GENERATOR = "org.eclipse.ui.ide.problemsGenerator"; //$NON-NLS-1$
159 
160 
161 	/**
162 	 * The all markers generator.
163 	 */
164 	public static final String ALL_MARKERS_GENERATOR = "org.eclipse.ui.ide.allMarkersGenerator"; //$NON-NLS-1$
165 
166 	/**
167 	 * The id for the new markers view.
168 	 */
169 	public static final String MARKERS_ID = "org.eclipse.ui.ide.MarkersView"; //$NON-NLS-1$;
170 
171 	private static final String ATTRIBUTE_GENERATOR_ID = "generatorId"; //$NON-NLS-1$
172 
173 	private static MarkerSupportRegistry singleton;
174 
175 	/**
176 	 * Get the instance of the registry.
177 	 *
178 	 * @return MarkerSupportRegistry
179 	 */
getInstance()180 	public static synchronized MarkerSupportRegistry getInstance() {
181 		if (singleton == null) {
182 			singleton = new MarkerSupportRegistry();
183 		}
184 		return singleton;
185 	}
186 
187 	private Map<String, ProblemFilter> registeredFilters = new HashMap<>();
188 
189 	private Map<String, MarkerGroup> markerGroups = new HashMap<>();
190 
191 	private Map<String, String> categories = new HashMap<>();
192 
193 	private Map<String, TableComparator> hierarchyOrders = new HashMap<>();
194 
195 	private MarkerType rootType;
196 
197 	private Map<String, ContentGeneratorDescriptor> generators = new HashMap<>();
198 
199 	private Map<String, MarkerField> fields = new HashMap<>();
200 
201 	/**
202 	 * Create a new instance of the receiver and read the registry.
203 	 */
MarkerSupportRegistry()204 	private MarkerSupportRegistry() {
205 		IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker();
206 		IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(IDEWorkbenchPlugin.IDE_WORKBENCH,
207 				MARKER_SUPPORT);
208 		if (point == null) {
209 			return;
210 		}
211 		IExtension[] extensions = point.getExtensions();
212 		// initial population
213 		Map<String, Collection<MarkerGroupingEntry>> groupingEntries = new HashMap<>();
214 		Map<String, Collection<IConfigurationElement>> generatorExtensions = new HashMap<>();
215 		Map<String, MarkerGroupingEntry> entryIDsToEntries = new HashMap<>();
216 		Set<AttributeMarkerGrouping> attributeMappings = new HashSet<>();
217 		for (IExtension extension : extensions) {
218 			processExtension(tracker, extension, groupingEntries,
219 					entryIDsToEntries, attributeMappings, generatorExtensions);
220 		}
221 		postProcessExtensions(groupingEntries, entryIDsToEntries, attributeMappings, generatorExtensions);
222 		tracker.registerHandler(this, ExtensionTracker.createExtensionPointFilter(point));
223 	}
224 
225 	/**
226 	 * Process the extension and register the result with the tracker. Fill the
227 	 * map of groupingEntries and attribueMappings processed for post
228 	 * processing.
229 	 *
230 	 * @param tracker
231 	 * @param extension
232 	 * @param groupIDsToEntries
233 	 *            Mapping of group names to the markerGroupingEntries registered
234 	 *            for them
235 	 * @param entryIDsToEntries
236 	 *            Mapping of entry ids to entries
237 	 * @param attributeMappings
238 	 *            the markerAttributeGroupings found
239 	 * @param generatorExtensions
240 	 *            the markerContentGenerator extensions keyed on group id
241 	 * @see #postProcessExtensions(Map, Map, Collection, Map)
242 	 */
processExtension(IExtensionTracker tracker, IExtension extension, Map<String, Collection<MarkerGroupingEntry>> groupIDsToEntries, Map<String, MarkerGroupingEntry> entryIDsToEntries, Collection<AttributeMarkerGrouping> attributeMappings, Map<String, Collection<IConfigurationElement>> generatorExtensions)243 	private void processExtension(IExtensionTracker tracker, IExtension extension,
244 			Map<String, Collection<MarkerGroupingEntry>> groupIDsToEntries,
245 			Map<String, MarkerGroupingEntry> entryIDsToEntries,
246 			Collection<AttributeMarkerGrouping> attributeMappings,
247 			Map<String, Collection<IConfigurationElement>> generatorExtensions) {
248 		IConfigurationElement[] elements = extension.getConfigurationElements();
249 
250 		for (IConfigurationElement element : elements) {
251 			if (element.getName().equals(PROBLEM_FILTER)) {
252 				ProblemFilter filter = newFilter(element);
253 				registeredFilters.put(filter.getId(), filter);
254 				tracker.registerObject(extension, filter, IExtensionTracker.REF_STRONG);
255 				continue;
256 			}
257 
258 			if (element.getName().equals(MARKER_GROUPING)) {
259 				MarkerGroup group = MarkerGroup.createMarkerGroup(element);
260 				markerGroups.put(group.getId(), group);
261 				tracker.registerObject(extension, group, IExtensionTracker.REF_STRONG);
262 				continue;
263 			}
264 
265 			if (element.getName().equals(MARKER_GROUPING_ENTRY)) {
266 				MarkerGroupingEntry entry = new MarkerGroupingEntry(element);
267 				String groupName = element.getAttribute(MARKER_GROUPING);
268 				Collection<MarkerGroupingEntry> entries = groupIDsToEntries.get(groupName);
269 				if (entries == null) {
270 					entries = new HashSet<>();
271 				}
272 
273 				entries.add(entry);
274 				groupIDsToEntries.put(groupName, entries);
275 				entryIDsToEntries.put(entry.getId(), entry);
276 
277 				tracker.registerObject(extension, entry, IExtensionTracker.REF_STRONG);
278 				continue;
279 			}
280 
281 			if (element.getName().equals(MARKER_ATTRIBUTE_GROUPING)) {
282 				AttributeMarkerGrouping grouping = new AttributeMarkerGrouping(element);
283 				attributeMappings.add(grouping);
284 				tracker.registerObject(extension, grouping, IExtensionTracker.REF_STRONG);
285 				continue;
286 			}
287 
288 			if (element.getName().equals(MARKER_CATEGORY)) {
289 				String[] markerTypes = getMarkerTypes(element);
290 				String categoryName = element.getAttribute(MarkerSupportInternalUtilities.ATTRIBUTE_NAME);
291 				for (String markerType : markerTypes) {
292 					categories.put(markerType, categoryName);
293 				}
294 				tracker.registerObject(extension, categoryName, IExtensionTracker.REF_STRONG);
295 				continue;
296 			}
297 
298 			if (element.getName().equals(MARKER_CONTENT_GENERATOR_EXTENSION)) {
299 				String generatorName = element.getAttribute(ATTRIBUTE_GENERATOR_ID);
300 				Collection<IConfigurationElement> extensionCollection = generatorExtensions.get(generatorName);
301 				if (extensionCollection == null) {
302 					extensionCollection = new ArrayList<>();
303 				}
304 
305 				extensionCollection.add(element);
306 				generatorExtensions.put(generatorName, extensionCollection);
307 				tracker.registerObject(extension, element, IExtensionTracker.REF_STRONG);
308 				continue;
309 			}
310 
311 			if (element.getName().equals(MARKER_CONTENT_GENERATOR)) {
312 				ContentGeneratorDescriptor generatorDesc = new ContentGeneratorDescriptor(element);
313 				generators.put(generatorDesc.getId(), generatorDesc);
314 				tracker.registerObject(extension, generatorDesc, IExtensionTracker.REF_STRONG);
315 				continue;
316 			}
317 
318 			if (element.getName().equals(MARKER_FIELD)) {
319 				processMarkerField(tracker, extension, element);
320 				continue;
321 			}
322 		}
323 	}
324 
325 	/**
326 	 * Create a table of MarkerFields
327 	 *
328 	 * @param tracker
329 	 * @param extension
330 	 * @param element
331 	 */
processMarkerField(IExtensionTracker tracker, IExtension extension, IConfigurationElement element)332 	private void processMarkerField(IExtensionTracker tracker, IExtension extension, IConfigurationElement element) {
333 		MarkerField field = null;
334 		try {
335 			field = (MarkerField) IDEWorkbenchPlugin.createExtension(element, ATTRIBUTE_CLASS);
336 			field.setConfigurationElement(element);
337 		} catch (CoreException e) {
338 			Policy.handle(e);
339 		}
340 
341 		if (field != null) {
342 			fields.put(element.getAttribute(MarkerSupportInternalUtilities.ATTRIBUTE_ID), field);
343 		}
344 		tracker.registerObject(extension, field, IExtensionTracker.REF_STRONG);
345 	}
346 
347 	/**
348 	 * Process the cross references after all of the extensions have been read.
349 	 *
350 	 * @param groupIDsToEntries
351 	 *            Mapping of group names to the markerGroupingEntries registered
352 	 *            for them
353 	 * @param entryIDsToEntries
354 	 *            Mapping of entry names to the mappings for them
355 	 * @param attributeMappings
356 	 *            the markerAttributeGroupings found
357 	 * @param generatorExtensions
358 	 *            map of generator id to generator descriptors
359 	 */
postProcessExtensions(Map<String, Collection<MarkerGroupingEntry>> groupIDsToEntries, Map<String, MarkerGroupingEntry> entryIDsToEntries, Collection<AttributeMarkerGrouping> attributeMappings, Map<String, Collection<IConfigurationElement>> generatorExtensions)360 	private void postProcessExtensions(Map<String, Collection<MarkerGroupingEntry>> groupIDsToEntries,
361 			Map<String, MarkerGroupingEntry> entryIDsToEntries, Collection<AttributeMarkerGrouping> attributeMappings,
362 			Map<String, Collection<IConfigurationElement>> generatorExtensions) {
363 		processGroupingEntries(groupIDsToEntries);
364 		processAttributeMappings(entryIDsToEntries, attributeMappings);
365 		postProcessContentGenerators(generatorExtensions);
366 	}
367 
368 	/**
369 	 * Set up the fields and filters
370 	 *
371 	 * @param generatorExtensions
372 	 *            the extensions to the generators,
373 	 */
postProcessContentGenerators(Map<String, Collection<IConfigurationElement>> generatorExtensions)374 	private void postProcessContentGenerators(Map<String, Collection<IConfigurationElement>> generatorExtensions) {
375 		Iterator<ContentGeneratorDescriptor> generatorIterator = generators.values().iterator();
376 		while (generatorIterator.hasNext()) {
377 			ContentGeneratorDescriptor generatorDesc = generatorIterator.next();
378 			generatorDesc.initializeFromConfigurationElement(this);
379 			Collection<IConfigurationElement> extensions = generatorExtensions.get(generatorDesc.getId());
380 			if (extensions != null) {
381 				generatorDesc.addExtensions(extensions);
382 			}
383 		}
384 
385 	}
386 
387 	/**
388 	 * Process the grouping entries into thier required grouping entries.
389 	 *
390 	 * @param groupingEntries
391 	 */
processGroupingEntries(Map<String, Collection<MarkerGroupingEntry>> groupingEntries)392 	private void processGroupingEntries(Map<String, Collection<MarkerGroupingEntry>> groupingEntries) {
393 		for (Entry<String, Collection<MarkerGroupingEntry>> entry : groupingEntries.entrySet()) {
394 			String nextGroupId = entry.getKey();
395 			MarkerGroup group = markerGroups.get(nextGroupId);
396 			if (group != null) {
397 				for (MarkerGroupingEntry markerGroupingEntry : entry.getValue()) {
398 					markerGroupingEntry.setGroup(group);
399 				}
400 			} else {
401 				for (MarkerGroupingEntry markerGroupingEntry : entry.getValue()) {
402 					IDEWorkbenchPlugin.log(NLS.bind("markerGroupingEntry {0} defines invalid group {1}", //$NON-NLS-1$
403 							new String[] { markerGroupingEntry.getId(), nextGroupId }));
404 				}
405 			}
406 		}
407 	}
408 
409 	/**
410 	 * Process the attribute mappings into thier required grouping entries.
411 	 *
412 	 * @param entryIDsToEntries
413 	 * @param attributeMappings
414 	 */
processAttributeMappings(Map<String, MarkerGroupingEntry> entryIDsToEntries, Collection<AttributeMarkerGrouping> attributeMappings)415 	private void processAttributeMappings(Map<String, MarkerGroupingEntry> entryIDsToEntries,
416 			Collection<AttributeMarkerGrouping> attributeMappings) {
417 		Iterator<AttributeMarkerGrouping> mappingsIterator = attributeMappings.iterator();
418 		while (mappingsIterator.hasNext()) {
419 			AttributeMarkerGrouping attributeGrouping = mappingsIterator.next();
420 			String defaultEntryId = attributeGrouping.getDefaultGroupingEntry();
421 			if (defaultEntryId != null) {
422 				MarkerGroupingEntry entry = entryIDsToEntries.get(defaultEntryId);
423 				if (entry != null) {
424 					entry.setAsDefault(attributeGrouping.getMarkerType());
425 				} else {
426 					IDEWorkbenchPlugin.log(NLS.bind(
427 							"Reference to invalid markerGroupingEntry {0}",//$NON-NLS-1$
428 							defaultEntryId));
429 				}
430 			}
431 			IConfigurationElement[] mappings = attributeGrouping.getElement().getChildren(ATTRIBUTE_MAPPING);
432 
433 			for (IConfigurationElement mapping : mappings) {
434 				String entryId = mapping.getAttribute(MARKER_GROUPING_ENTRY);
435 
436 				MarkerGroupingEntry entry = entryIDsToEntries.get(entryId);
437 				if (entry != null) {
438 					entry.getMarkerGroup().mapAttribute(attributeGrouping, entry, mapping.getAttribute(VALUE));
439 				} else {
440 					IDEWorkbenchPlugin.log(NLS.bind(
441 							"Reference to invaild markerGroupingEntry {0}", //$NON-NLS-1$
442 							defaultEntryId));
443 				}
444 			}
445 		}
446 	}
447 
448 	/**
449 	 * Get the markerTypes defined in element.
450 	 *
451 	 * @param element
452 	 * @return String[]
453 	 */
getMarkerTypes(IConfigurationElement element)454 	private String[] getMarkerTypes(IConfigurationElement element) {
455 		IConfigurationElement[] types = element
456 				.getChildren(MARKER_TYPE_REFERENCE);
457 		String[] ids = new String[types.length];
458 		for (int i = 0; i < ids.length; i++) {
459 			ids[i] = types[i].getAttribute(MarkerSupportInternalUtilities.ATTRIBUTE_ID);
460 		}
461 		return ids;
462 	}
463 
464 	@Override
addExtension(IExtensionTracker tracker, IExtension extension)465 	public void addExtension(IExtensionTracker tracker, IExtension extension) {
466 		Map<String, Collection<MarkerGroupingEntry>> groupIDsToEntries = new HashMap<>();
467 		Map<String, MarkerGroupingEntry> entryIDsToEntries = new HashMap<>();
468 		Map<String, Collection<IConfigurationElement>> generatorExtensions = new HashMap<>();
469 		Set<AttributeMarkerGrouping> attributeMappings = new HashSet<>();
470 		processExtension(tracker, extension, groupIDsToEntries,	entryIDsToEntries, attributeMappings, generatorExtensions);
471 		postProcessExtensions(groupIDsToEntries, entryIDsToEntries,	attributeMappings, generatorExtensions);
472 	}
473 
474 	/**
475 	 * Get the collection of currently registered filters.
476 	 *
477 	 * @return Collection of ProblemFilter
478 	 */
getRegisteredFilters()479 	public Collection<ProblemFilter> getRegisteredFilters() {
480 		Collection<ProblemFilter> filteredFilters = new ArrayList<>();
481 		Iterator<ProblemFilter> registeredIterator = registeredFilters.values().iterator();
482 		while (registeredIterator.hasNext()) {
483 			ProblemFilter next = registeredIterator.next();
484 			if (next.isFilteredOutByActivity()) {
485 				continue;
486 			}
487 			filteredFilters.add(next);
488 		}
489 		return filteredFilters;
490 	}
491 
492 	/**
493 	 * Get the constant for scope from element. Return -1 if there is no value.
494 	 *
495 	 * @param element
496 	 * @return int one of MarkerView#ON_ANY MarkerView#ON_SELECTED_ONLY
497 	 *         MarkerView#ON_SELECTED_AND_CHILDREN
498 	 *         MarkerView#ON_ANY_IN_SAME_CONTAINER
499 	 */
getScopeValue(IConfigurationElement element)500 	private int getScopeValue(IConfigurationElement element) {
501 		String scope = element.getAttribute(SCOPE);
502 		if (scope == null) {
503 			return -1;
504 		}
505 		if (scope.equals(ON_ANY)) {
506 			return MarkerFilter.ON_ANY;
507 		}
508 		if (scope.equals(ON_SELECTED_ONLY)) {
509 			return MarkerFilter.ON_SELECTED_ONLY;
510 		}
511 		if (scope.equals(ON_SELECTED_AND_CHILDREN)) {
512 			return MarkerFilter.ON_SELECTED_AND_CHILDREN;
513 		}
514 		if (scope.equals(ON_ANY_IN_SAME_CONTAINER)) {
515 			return MarkerFilter.ON_ANY_IN_SAME_CONTAINER;
516 		}
517 		return -1;
518 	}
519 
520 	/**
521 	 * Get the constant for scope from element. Return -1 if there is no value.
522 	 *
523 	 * @param element
524 	 * @return int one of MarkerView#ON_ANY MarkerView#ON_SELECTED_ONLY
525 	 *         MarkerView#ON_SELECTED_AND_CHILDREN
526 	 *         MarkerView#ON_ANY_IN_SAME_CONTAINER
527 	 */
getSeverityValue(IConfigurationElement element)528 	private int getSeverityValue(IConfigurationElement element) {
529 		String severity = element.getAttribute(SEVERITY);
530 		if (severity == null) {
531 			return -1;
532 		}
533 		if (severity.equals(INFO)) {
534 			return ProblemFilter.SEVERITY_INFO;
535 		}
536 		if (severity.equals(WARNING)) {
537 			return ProblemFilter.SEVERITY_WARNING;
538 		}
539 		if (severity.equals(ERROR)) {
540 			return ProblemFilter.SEVERITY_ERROR;
541 		}
542 		return -1;
543 	}
544 
545 	/**
546 	 * Read the problem filters in the receiver.
547 	 *
548 	 * @param element
549 	 *            the filter element
550 	 * @return ProblemFilter
551 	 */
newFilter(IConfigurationElement element)552 	private ProblemFilter newFilter(IConfigurationElement element) {
553 		ProblemFilter filter = new ProblemFilter(element.getAttribute(MarkerSupportInternalUtilities.ATTRIBUTE_NAME));
554 
555 		filter.createContributionFrom(element);
556 
557 		String enabledValue = element.getAttribute(ENABLED);
558 		filter.setEnabled(enabledValue == null || Boolean.parseBoolean(enabledValue));
559 
560 		int scopeValue = getScopeValue(element);
561 		if (scopeValue >= 0) {
562 			filter.setOnResource(scopeValue);
563 		}
564 
565 		String description = element.getAttribute(DESCRIPTION);
566 		if (description != null) {
567 			boolean contains = true;
568 			if (description.charAt(0) == '!') {// does not contain flag
569 				description = description.substring(1, description.length());
570 				contains = false;
571 			}
572 			filter.setContains(contains);
573 			filter.setDescription(description);
574 		}
575 
576 		int severityValue = getSeverityValue(element);
577 		if (severityValue > 0) {
578 			filter.setSelectBySeverity(true);
579 			filter.setSeverity(severityValue);
580 		} else {
581 			filter.setSelectBySeverity(false);
582 		}
583 
584 		List<MarkerType> selectedTypes = new ArrayList<>();
585 		for (IConfigurationElement type : element.getChildren(SELECTED_TYPE)) {
586 			String markerId = type.getAttribute(MARKER_ID);
587 			if (markerId != null) {
588 				MarkerType markerType = filter.getMarkerType(markerId);
589 				if (markerType == null) {
590 					IStatus status = new Status(IStatus.WARNING, IDEWorkbenchPlugin.IDE_WORKBENCH, IStatus.WARNING,
591 							NLS.bind(MarkerMessages.ProblemFilterRegistry_nullType,
592 									new Object[] { markerId, filter.getName() }),
593 							null);
594 					IDEWorkbenchPlugin.getDefault().getLog().log(status);
595 				} else {
596 					selectedTypes.add(markerType);
597 				}
598 			}
599 		}
600 
601 		if (selectedTypes.size() > 0) {
602 			// specified
603 			filter.setSelectedTypes(selectedTypes);
604 		}
605 		return filter;
606 	}
607 
608 	@Override
removeExtension(IExtension extension, Object[] objects)609 	public void removeExtension(IExtension extension, Object[] objects) {
610 
611 		for (Object object : objects) {
612 			if (object instanceof ProblemFilter) {
613 				registeredFilters.remove(object);
614 				continue;
615 			}
616 
617 			if (object instanceof MarkerGroup) {
618 				markerGroups.remove(((MarkerGroup) object).getId());
619 				continue;
620 			}
621 
622 			if (object instanceof MarkerGroupingEntry) {
623 				MarkerGroupingEntry entry = (MarkerGroupingEntry) object;
624 				entry.getMarkerGroup().remove(entry);
625 				continue;
626 			}
627 
628 			if (object instanceof AttributeMarkerGrouping) {
629 				AttributeMarkerGrouping entry = (AttributeMarkerGrouping) object;
630 				entry.unmap();
631 				continue;
632 			}
633 
634 			if (object instanceof String) {
635 				removeValues((String) object, categories);
636 				continue;
637 			}
638 
639 			if (object instanceof MarkerField) {
640 				fields.remove(MarkerSupportInternalUtilities.getId((MarkerField) object));
641 				continue;
642 			}
643 
644 			if (object instanceof ContentGeneratorDescriptor) {
645 				generators.remove(((ContentGeneratorDescriptor) object).getId());
646 				continue;
647 			}
648 
649 			if (object instanceof IConfigurationElement) {
650 				IConfigurationElement element = (IConfigurationElement) object;
651 				ContentGeneratorDescriptor generatorDesc = generators.get(element.getAttribute(ATTRIBUTE_GENERATOR_ID));
652 				generatorDesc.removeExtension(element);
653 				continue;
654 			}
655 		}
656 	}
657 
658 	/**
659 	 * Remove the value from all of the collection sets in cache. If the
660 	 * collection is empty remove the key as well.
661 	 *
662 	 * @param value
663 	 * @param cache
664 	 */
removeValues(String value, Map<String, String> cache)665 	private void removeValues(String value, Map<String, String> cache) {
666 		Collection<String> keysToRemove = new ArrayList<>();
667 		for (Entry<String, String> entry : cache.entrySet()) {
668 			if (entry.getValue().equals(value)) {
669 				keysToRemove.add(entry.getKey());
670 			}
671 		}
672 		for (String toRemove : keysToRemove) {
673 			cache.remove(toRemove);
674 		}
675 	}
676 
677 	/**
678 	 * Get the category associated with marker. Return <code>null</code> if
679 	 * there are none.
680 	 *
681 	 * @param marker
682 	 * @return String or <code>null</code>
683 	 */
getCategory(IMarker marker)684 	public String getCategory(IMarker marker) {
685 		try {
686 			return getCategory(marker.getType());
687 		} catch (CoreException e) {
688 			Policy.handle(e);
689 		}
690 		return null;
691 	}
692 
693 	/**
694 	 * Get the category associated with markerType. Return <code>null</code>
695 	 * if there are none.
696 	 *
697 	 * @param markerType
698 	 * @return String or <code>null</code>
699 	 */
getCategory(String markerType)700 	public String getCategory(String markerType) {
701 		return categories.get(markerType);
702 	}
703 
704 	/**
705 	 * Return the TableSorter that corresponds to type.
706 	 *
707 	 * @param type
708 	 * @return TableSorter
709 	 */
getSorterFor(String type)710 	public TableComparator getSorterFor(String type) {
711 		TableComparator sorter = hierarchyOrders.get(type);
712 		if (sorter != null) {
713 			return sorter;
714 		}
715 
716 		sorter = findSorterInChildren(type, getRootType());
717 		if (sorter == null) {
718 			return new TableComparator(new IField[0], new int[0], new int[0]);
719 		}
720 		return sorter;
721 	}
722 
723 	/**
724 	 * Return the list of root marker types.
725 	 *
726 	 * @return List of MarkerType.
727 	 */
getRootType()728 	private MarkerType getRootType() {
729 		if (rootType == null) {
730 			rootType = (MarkerTypesModel.getInstance()).getType(IMarker.PROBLEM);
731 		}
732 		return rootType;
733 	}
734 
735 	/**
736 	 * Find the best match sorter for typeName in the children. If it cannot be
737 	 * found then return <code>null</code>.
738 	 *
739 	 * @param typeName
740 	 * @param type
741 	 * @return TableSorter or <code>null</code>.
742 	 */
findSorterInChildren(String typeName, MarkerType type)743 	private TableComparator findSorterInChildren(String typeName, MarkerType type) {
744 		for (MarkerType markerSubType : type.getAllSubTypes()) {
745 			MarkerType[] subtypes = markerSubType.getAllSubTypes();
746 			for (MarkerType subtype : subtypes) {
747 				TableComparator sorter = findSorterInChildren(typeName, subtype);
748 				if (sorter != null) {
749 					return sorter;
750 				}
751 			}
752 		}
753 		return hierarchyOrders.get(type.getId());
754 	}
755 
756 	/**
757 	 * Return the FieldMarkerGroups in the receiver.
758 	 *
759 	 * @return Collection of {@link MarkerGroup}
760 	 */
getMarkerGroups()761 	public Collection<MarkerGroup> getMarkerGroups() {
762 		return markerGroups.values();
763 	}
764 
765 	/**
766 	 * Return the default groupfield.
767 	 *
768 	 * @return IField
769 	 */
getDefaultGroupField()770 	IField getDefaultGroupField() {
771 		return markerGroups.get(SEVERITY_ID).getField();
772 	}
773 
774 	/**
775 	 * Get the generator descriptor for id
776 	 *
777 	 * @param id
778 	 * @return ContentGeneratorDescriptor or <code>null</code>.
779 	 */
getContentGenDescriptor(String id)780 	public ContentGeneratorDescriptor getContentGenDescriptor (String id) {
781 		if (id != null) {
782 			return generators.get(id);
783 		}
784 		return null;
785 	}
786 
787 	/**
788 	 * Return the default content generator descriptor.
789 	 *
790 	 * @return ContentGeneratorDescriptor
791 	 */
getDefaultContentGenDescriptor()792 	public ContentGeneratorDescriptor getDefaultContentGenDescriptor () {
793 		return generators.get(PROBLEMS_GENERATOR);
794 	}
795 
796 	/**
797 	 * Get the markerGroup associated with categoryName
798 	 *
799 	 * @param categoryName
800 	 * @return FieldMarkerGroup or <code>null</code>
801 	 */
getMarkerGroup(String categoryName)802 	public MarkerGroup getMarkerGroup(String categoryName) {
803 		return markerGroups.get(categoryName);
804 	}
805 
806 	/**
807 	 * Return the field that maps to id.
808 	 *
809 	 * @param id
810 	 * @return {@link MarkerField} or <code>null</code>
811 	 */
getField(String id)812 	public MarkerField getField(String id) {
813 		return fields.get(id);
814 	}
815 
816 }
817