/******************************************************************************* * Copyright (c) 2011, 2012 Tasktop Technologies. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Tasktop Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.commons.core; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.osgi.util.NLS; /** * @author Steffen Pingel * @author Sam Davis * @since 3.7 */ public class ExtensionPointReader<T> { private final class PriorityComparator implements Comparator<IConfigurationElement> { public int compare(IConfigurationElement arg0, IConfigurationElement arg1) { double p0 = 0; double p1 = 0; try { String priorityAttribute = arg0.getAttribute(getPriorityAttributeId()); if (priorityAttribute != null) { p0 = Double.parseDouble(priorityAttribute); } } catch (NumberFormatException e) { } try { String priorityAttribute = arg1.getAttribute(getPriorityAttributeId()); if (priorityAttribute != null) { p1 = Double.parseDouble(priorityAttribute); } } catch (NumberFormatException e) { } if (p1 > p0) { return 1; } else if (p1 < p0) { return -1; } return 0; } } private static final String DEFAULT_ATTRIBUTE_ID_CLASS = "class"; //$NON-NLS-1$ private static final String DEFAULT_ATTRIBUTE_ID_PRIORITY = "priority"; //$NON-NLS-1$ private final PriorityComparator priorityComparator = new PriorityComparator(); private String classAttributeId; private final Class<T> clazz; private final String elementId; private final String extensionId; private String filterAttributeId; private String filterAttributeValue; private final List<T> items; private final String pluginId; private String priorityAttributeId; public ExtensionPointReader(String pluginId, String extensionId, String elementId, Class<T> clazz) { this(pluginId, extensionId, elementId, clazz, null, null); } public ExtensionPointReader(String pluginId, String extensionId, String elementId, Class<T> clazz, String filterAttributeId, String filterAttributeValue) { Assert.isNotNull(pluginId); Assert.isNotNull(extensionId); Assert.isNotNull(elementId); Assert.isNotNull(clazz); this.pluginId = pluginId; this.extensionId = extensionId; this.elementId = elementId; this.clazz = clazz; this.filterAttributeId = filterAttributeId; this.filterAttributeValue = filterAttributeValue; this.classAttributeId = DEFAULT_ATTRIBUTE_ID_CLASS; this.priorityAttributeId = DEFAULT_ATTRIBUTE_ID_PRIORITY; this.items = new ArrayList<T>(); } public final String getClassAttributeId() { return classAttributeId; } public final String getElementId() { return elementId; } public T getItem() { return (items.isEmpty()) ? null : items.get(0); } public List<T> getItems() { return new ArrayList<T>(items); } public final String getPluginId() { return pluginId; } public String getPriorityAttributeId() { return priorityAttributeId; } public IStatus read() { items.clear(); IExtensionRegistry registry = Platform.getExtensionRegistry(); if (registry == null) { return Status.CANCEL_STATUS; } MultiStatus result = new MultiStatus(pluginId, 0, NLS.bind( "Extensions for {0}/{1} failed to load", pluginId, elementId), null); //$NON-NLS-1$ IExtensionPoint extensionPoint = registry.getExtensionPoint(pluginId + "." + extensionId); //$NON-NLS-1$ if (extensionPoint != null) { IExtension[] extensions = extensionPoint.getExtensions(); for (IExtension extension : extensions) { IConfigurationElement[] elements = extension.getConfigurationElements(); Arrays.sort(elements, priorityComparator); for (IConfigurationElement element : elements) { if (element.getName().equals(elementId) && shouldRead(element)) { T item = readElement(element, result); if (item != null) { items.add(item); } } } } } handleResult(result); return result; } public final void setClassAttributeId(String classAttributeId) { this.classAttributeId = classAttributeId; } public void setFilterAttributeId(String filterAttributeId) { this.filterAttributeId = filterAttributeId; } public void setFilterAttributeValue(String filterAttributeValue) { this.filterAttributeValue = filterAttributeValue; } public void setPriorityAttributeId(String priorityAttributeId) { this.priorityAttributeId = priorityAttributeId; } protected void handleResult(IStatus result) { if (!result.isOK()) { StatusHandler.log(result); } } protected T readElement(IConfigurationElement element, MultiStatus result) { try { Object object = element.createExecutableExtension(getClassAttributeId()); if (clazz.isInstance(object)) { return clazz.cast(object); } else { result.add(new Status(IStatus.ERROR, pluginId, NLS.bind( "Class ''{0}'' does not extend expected class for extension contributed by {1}", //$NON-NLS-1$ object.getClass().getCanonicalName(), getPluginId()))); } } catch (Throwable e) { result.add(new Status(IStatus.ERROR, pluginId, NLS.bind( "Failed to load for extension contributed by {0}", getPluginId()), e)); //$NON-NLS-1$ } return null; } /** * Determines whether the element should be instantiated by this ExtensionPointReader. This implementation checks * whether the element defines an attribute with id and value matching filterAttributeId and filterAttributeValue. * If filterAttributeValue is the empty string, an element is also considered to match if it does not define the * attribute. * <p> * Subclasses may override. */ protected boolean shouldRead(IConfigurationElement element) { return filterAttributeId == null || filterAttributeValue == null || filterAttributeValue.equals(element.getAttribute(filterAttributeId)) || (filterAttributeValue.length() == 0 && element.getAttribute(filterAttributeId) == null); } }