blob: 825e71e332b7d42b411cb131049d740b57a4a13f [file] [log] [blame]
/*******************************************************************************
* 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);
}
}