/******************************************************************************* * Copyright (c) 2006-2011, G. Weirich and Elexis * 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: * G. Weirich - initial implementation * *******************************************************************************/ package ch.elexis.core.data.util; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; 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 ch.elexis.core.data.constants.ExtensionPointConstantsData; import ch.elexis.core.jdt.NonNull; import ch.rgw.tools.ExHandler; /** * Vereinfachung der Handhabung von Extensions. Verschidene statische Methoden zum Auflisten von * Extensionpoint.-clients * * 2008: Implementation eines Service-Providers * * @author gerry * */ public class Extensions { /** * EIne Liste von IConfigurationElements (=komplette Definition) liefern, die an einem * bestimmten Extensionpoint hängen * * @param ext * Name des Extensionpoints */ public static List<IConfigurationElement> getExtensions(String ext){ List<IConfigurationElement> ret = new LinkedList<IConfigurationElement>(); IExtensionRegistry exr = Platform.getExtensionRegistry(); IExtensionPoint exp = exr.getExtensionPoint(ext); if (exp != null) { IExtension[] extensions = exp.getExtensions(); for (IExtension ex : extensions) { IConfigurationElement[] elems = ex.getConfigurationElements(); for (IConfigurationElement el : elems) { ret.add(el); } } } return ret; } /** * Eine Liste von bereits initialisierten Klassen liefern, die an einem bestimmten parameter * eines bestimmten Extensionpoints hängen * * @param list * eine Liste, wie von getExtension geliefert * @param points * Name der Klasse * @return eine Liste der konstruierten Klassen * @deprecated Use {@link #getClasses(List<IConfigurationElement>,String,boolean)} instead */ @SuppressWarnings("unchecked") //$NON-NLS-1$ public static List getClasses(List<IConfigurationElement> list, String points){ return getClasses(list, points, true); } /** * Eine Liste von bereits initialisierten Klassen liefern, die an einem bestimmten parameter * eines bestimmten Extensionpoints hängen * * @param list * eine Liste, wie von getExtension geliefert * @param points * Name der Klasse * @param bMandatory * false: do not handle exceptions * @return eine Liste der konstruierten Klassen */ @SuppressWarnings("unchecked") //$NON-NLS-1$ public static List getClasses(List<IConfigurationElement> list, String points, boolean bMandatory){ List ret = new LinkedList(); for (IConfigurationElement el : list) { try { Object o = el.createExecutableExtension(points); if (o != null) { ret.add(o); } } catch (CoreException e) { if (bMandatory) { ExHandler.handle(e); } } } return ret; } /** * Shortcut für getClasses(getExtensions(extension),points); */ public static List getClasses(String extension, String points){ return getClasses(extension, points, null, null); } /** * * @param extension * @param points * @param idParam id parameter on the extension point to filter against * @param idValue key matching idParam * @return instantiated classes of a defined extension point * @since 3.2 */ public static @NonNull List getClasses(String extension, String points, String idParam, String idValue){ List<IConfigurationElement> extensions = getExtensions(extension); if (idParam != null && idValue != null) { List<IConfigurationElement> filteredExtensions = extensions.stream().filter(p -> idValue.equalsIgnoreCase(p.getAttribute(idParam))) .collect(Collectors.toList()); return getClasses(filteredExtensions, points, true); } return getClasses(getExtensions(extension), points, true); } /** * Eine Liste von Werten liefern, die ein bestimmtest Attribut hat * * @param list * @param attr * @return */ public static List<String> getStrings(List<IConfigurationElement> list, String attr){ List<String> ret = new LinkedList<String>(); for (IConfigurationElement el : list) { ret.add(el.getAttribute(attr)); } return ret; } public static List<String> getStrings(String ext, String attr){ return getStrings(getExtensions(ext), attr); } /** * We sort of replicate the OSGi Service Registry, but place it on top of the Extension point * system. * * A Plugin can publish a service by accessing the ExtensionPoint ch.elexis.ServiceRegistry and * defining a service with an arbitrary name. It must offer an Object declared as "actor" that * performs the service. The Methods to use must be documented. (@see executeService) * * A different plugin can implement the same Service "better" by using the same name but * declaring a higher "value" A Client can retrieve and use Services through * isServiceAvailable() and findBestService() * * @param name * name of the service to load * @param variant * the variant wanted. Can be null to indicate don't mind * @return the actor-Object that the "best" Service with this name offers or null if no service * with the given name could be loaded. */ public static Object findBestService(String name, String variant){ int value = Integer.MIN_VALUE; IConfigurationElement best = null; List<IConfigurationElement> services = getExtensions(ExtensionPointConstantsData.SERVICE_REGISTRY); for (IConfigurationElement ic : services) { String nam = ic.getAttribute("name"); if (nam.equalsIgnoreCase(name)) { if (variant != null) { String var = ic.getAttribute("variant"); if (var == null || (!var.equalsIgnoreCase(variant))) { continue; } } String val = ic.getAttribute("value"); if (val != null) { int ival = Integer.parseInt(val); if (ival > value) { value = ival; best = ic; } } } } if (best == null) { return null; } else { try { return best.createExecutableExtension("actor"); } catch (CoreException e) { ExHandler.handle(e); return null; } } } public static List<Object> getServices(String name, String variant){ List<IConfigurationElement> services = getExtensions(ExtensionPointConstantsData.SERVICE_REGISTRY); List<Object> ret = new ArrayList<Object>(); for (IConfigurationElement ic : services) { String nam = ic.getAttribute("name"); if (nam.equalsIgnoreCase(name)) { if (variant != null) { String var = ic.getAttribute("variant"); if (var == null || (!var.equalsIgnoreCase(variant))) { continue; } } try { ret.add(ic.createExecutableExtension("actor")); } catch (CoreException e) { ExHandler.handle(e); } } } return ret; } /** * Shortcut for findBestService(name,null) */ public static Object findBestService(String name){ return findBestService(name, null); } /** * Execute a method of the service actor, that is known by name and signature * * @param service * The service actor as returned by findBestService() * @param method * the name of the method to be called * @param types * the parameter types * @param params * the parameters * @return an Object that ist implementation dependent or null if the method call failed. It is * recommended that an actor returns a ch.elexis.Result to allow error handling. */ public static Object executeService(Object service, String method, Class[] types, Object[] params){ try { Method m = service.getClass().getMethod(method, types); return m.invoke(service, params); } catch (Exception ex) { ExHandler.handle(ex); return null; } } /** * Ask whether a service is available. The call is cheap because no Object will be * instantaniated. Note: If this call returns true, a call to findBestService() might still * return null, because a Service might have gone unavailable in the meantime. * * @param name * the name of the service to find. * @return true if at least one implementation of a service with the given name is registered */ public static boolean isServiceAvailable(String name){ List<IConfigurationElement> services = getExtensions(ExtensionPointConstantsData.SERVICE_REGISTRY); for (IConfigurationElement ic : services) { String nam = ic.getAttribute("name"); if (nam.equalsIgnoreCase(name)) { return true; } } return false; } }