package org.erlide.util.services; import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.CoreException; 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.Platform; import org.eclipse.core.runtime.RegistryFactory; import org.erlide.util.ErlLogger; import com.google.common.collect.Lists; public final class ExtensionUtils { /** * Get an executable extension that has only one implementor. We do no hard * checks, but take the first one. */ public static <T> T getSingletonExtension(final String id, final Class<? extends T> clazz) { final IExtensionRegistry reg = RegistryFactory.getRegistry(); final IConfigurationElement[] elements = reg.getConfigurationElementsFor(id); if (elements.length > 1) { ErlLogger.warn("There are multiple implementors of extension %s! " + "Picking one of them...", id); } for (final IConfigurationElement element : elements) { try { final Object object = element.createExecutableExtension("class"); if (clazz.isInstance(object)) { return clazz.cast(object); } } catch (final CoreException e) { e.printStackTrace(); // for some reason, ErlLogger only is printed if the above is // here... ErlLogger.error(e); } } return null; } public static <T> Provider<? extends T> getSingletonProviderExtension(final String id, final Class<? extends Provider<? extends T>> clazz) { final IExtensionRegistry reg = RegistryFactory.getRegistry(); final IConfigurationElement[] elements = reg.getConfigurationElementsFor(id); for (final IConfigurationElement element : elements) { try { final Object object = element.createExecutableExtension("provider"); if (clazz.isInstance(object)) { return clazz.cast(object); } } catch (final CoreException e) { ErlLogger.error(e); } } return null; } /** * Get the underlying class for a type, or null if the type is a variable * type. * * @param type * the type * @return the underlying class */ @SuppressWarnings("rawtypes") public static Class<?> getClass(final Type type) { if (type instanceof Class) { return (Class) type; } else if (type instanceof ParameterizedType) { return getClass(((ParameterizedType) type).getRawType()); } else if (type instanceof GenericArrayType) { final Type componentType = ((GenericArrayType) type) .getGenericComponentType(); final Class<?> componentClass = getClass(componentType); if (componentClass != null) { return Array.newInstance(componentClass, 0).getClass(); } return null; } else { return null; } } public static <T> List<T> getExtensions(final String id, final Class<T> clazz) { final List<T> result = Lists.newArrayList(); final IExtensionRegistry reg = RegistryFactory.getRegistry(); final IConfigurationElement[] elements = reg.getConfigurationElementsFor(id); for (final IConfigurationElement element : elements) { try { final Object object = element.createExecutableExtension("class"); if (clazz.isInstance(object)) { result.add(clazz.cast(object)); } } catch (final CoreException e) { ErlLogger.error(e); } } return result; } /** * This should be used to add participants at test-time. It should be the * name of the extension point to a list (which will be returned) */ public static Map<String, List<Object>> testingParticipants; public static IExtension[] getExtensions(final String type) { IExtension[] extensions; final IExtensionRegistry registry = Platform.getExtensionRegistry(); // we may not be in eclipse env when testing if (registry != null) { try { final IExtensionPoint extensionPoint = registry.getExtensionPoint(type); extensions = extensionPoint.getExtensions(); } catch (final Exception e) { ErlLogger.error( "Error getting extension for:" + type + " -- " + e.getMessage()); throw new RuntimeException(e); } } else { extensions = new IExtension[0]; } return extensions; } @SuppressWarnings("unchecked") public static Object getParticipant(final String type) { // only one participant may be used for this final List<Object> participants = (List<Object>) getParticipants(type); if (participants.size() == 1) { return participants.get(0); } if (participants.isEmpty()) { return null; } if (participants.size() > 1) { throw new RuntimeException( "More than one participant is registered for type:" + type); } throw new RuntimeException("Should never get here!"); } /** * @param type * the extension we want to get * @return a list of classes created from those extensions */ public static List<?> getParticipants(final String type) { if (testingParticipants != null) { return testingParticipants.get(type); } final List<Object> list = Lists.newArrayList(); final IExtension[] extensions = getExtensions(type); // For each extension ... for (int i = 0; i < extensions.length; i++) { final IExtension extension = extensions[i]; final IConfigurationElement[] elements = extension.getConfigurationElements(); // For each member of the extension ... for (int j = 0; j < elements.length; j++) { final IConfigurationElement element = elements[j]; try { list.add(element.createExecutableExtension("class")); } catch (final Exception e) { ErlLogger.warn(e); } } } return list; } private ExtensionUtils() { } }