All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scijava.plugin.PluginInfo Maven / Gradle / Ivy

Go to download

SciJava Common is a shared library for SciJava software. It provides a plugin framework, with an extensible mechanism for service discovery, backed by its own annotation processor, so that plugins can be loaded dynamically. It is used by downstream projects in the SciJava ecosystem, such as ImageJ and SCIFIO.

There is a newer version: 2.99.0
Show newest version
/*
 * #%L
 * SciJava Common shared library for SciJava software.
 * %%
 * Copyright (C) 2009 - 2017 Board of Regents of the University of
 * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck
 * Institute of Molecular Cell Biology and Genetics, University of
 * Konstanz, and KNIME GmbH.
 * %%
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * #L%
 */

package org.scijava.plugin;

import java.net.URL;

import org.scijava.AbstractUIDetails;
import org.scijava.Identifiable;
import org.scijava.Instantiable;
import org.scijava.InstantiableException;
import org.scijava.Locatable;
import org.scijava.MenuEntry;
import org.scijava.MenuPath;
import org.scijava.Priority;
import org.scijava.UIDetails;
import org.scijava.Versioned;
import org.scijava.input.Accelerator;
import org.scijava.util.ClassUtils;
import org.scijava.util.StringMaker;
import org.scijava.util.Types;
import org.scijava.util.VersionUtils;

/**
 * A collection of metadata about a particular plugin.
 * 

* For performance reasons, the metadata is populated without actually loading * the plugin class, by reading from an efficient binary cache (see * {@link org.scijava.plugin.DefaultPluginService} for details). As such, we can * very quickly build a complex structure containing all available plugins * without waiting for the Java class loader. *

* * @param The type of plugin described by this metadata. See * {@link SciJavaPlugin} for a list of common plugin types. * @author Curtis Rueden * @see Plugin * @see PluginService */ public class PluginInfo extends AbstractUIDetails implements Instantiable, Identifiable, Locatable, Versioned { /** Fully qualified class name of this plugin. */ private String className; /** Class object for this plugin. Lazily loaded. */ private Class pluginClass; /** Type of this entry's plugin; e.g., {@link org.scijava.service.Service}. */ private Class pluginType; /** Annotation describing the plugin. */ private Plugin annotation; /** Class loader to use when loading the class with {@link #loadClass()}. */ private ClassLoader classLoader; /** * Creates a new plugin metadata object. * * @param className The name of the class, which must implement * {@link SciJavaPlugin}. * @param pluginType The type of plugin described by this metadata. * See {@link SciJavaPlugin} for a list of common plugin types. */ public PluginInfo(final String className, final Class pluginType) { this(className, null, pluginType, null, null); } /** * Creates a new plugin metadata object. * * @param className The name of the class, which must implement * {@link SciJavaPlugin}. * @param pluginType The type of plugin described by this metadata. * See {@link SciJavaPlugin} for a list of common plugin types. * @param annotation The @{@link Plugin} annotation to associate with this * metadata object. */ public PluginInfo(final String className, final Class pluginType, final Plugin annotation) { this(className, null, pluginType, annotation, null); } /** * Creates a new plugin metadata object. * * @param className The name of the class, which must implement * {@link SciJavaPlugin}. * @param pluginType The type of plugin described by this metadata. * See {@link SciJavaPlugin} for a list of common plugin types. * @param annotation The @{@link Plugin} annotation to associate with this * metadata object. * @param classLoader The {@link ClassLoader} to use when loading the class * via {@link #loadClass()}, or null to use the current thread's * context class loader by default. */ public PluginInfo(final String className, final Class pluginType, final Plugin annotation, final ClassLoader classLoader) { this(className, null, pluginType, annotation, classLoader); } /** * Creates a new plugin metadata object. * * @param pluginClass The plugin class, which must implement * {@link SciJavaPlugin}. * @param pluginType The type of plugin described by this metadata. * See {@link SciJavaPlugin} for a list of common plugin types. */ public PluginInfo(final Class pluginClass, final Class pluginType) { this(null, pluginClass, pluginType, null, null); } /** * Creates a new plugin metadata object. * * @param pluginClass The plugin class, which must implement * {@link SciJavaPlugin}. * @param pluginType The type of plugin described by this metadata. * See {@link SciJavaPlugin} for a list of common plugin types. * @param annotation The @{@link Plugin} annotation to associate with this * metadata object. */ public PluginInfo(final Class pluginClass, final Class pluginType, final Plugin annotation) { this(null, pluginClass, pluginType, annotation, null); } protected PluginInfo(final String className, final Class pluginClass, final Class pluginType, final Plugin annotation, final ClassLoader classLoader) { if (pluginClass != null) { if (className != null) { throw new IllegalArgumentException( "className and pluginClass are mutually exclusive"); } setPluginClass(pluginClass); } else { this.className = className; } setPluginType(pluginType); setMenuPath(null); setMenuRoot(UIDetails.APPLICATION_MENU_ROOT); if (annotation == null) { // attempt to obtain the annotation from the plugin class, if available if (pluginClass != null) { this.annotation = pluginClass.getAnnotation(Plugin.class); } } else this.annotation = annotation; populateValues(); this.classLoader = classLoader; } // -- PluginInfo methods -- /** * Explicitly sets the {@link Class} of the item objects. *

* This is useful if your class is produced by something other than the system * classloader. *

*/ public void setPluginClass(final Class pluginClass) { this.pluginClass = pluginClass; } /** * Obtains the {@link Class} of the item objects, if that class has already * been loaded. * * @return The {@link Class}, or null if it has not yet been loaded by * {@link #loadClass}. */ public Class getPluginClass() { return pluginClass; } /** * Sets the type of plugin described by the metadata. * @see SciJavaPlugin for a list of common plugin types. */ public void setPluginType(final Class pluginType) { this.pluginType = pluginType; } /** * Gets the type of plugin described by the metadata. * @see SciJavaPlugin for a list of common plugin types. */ public Class getPluginType() { return pluginType; } /** Gets the associated @{@link Plugin} annotation. */ public Plugin getAnnotation() { return annotation; } /** * Gets the URL corresponding to the icon resource path. * * @see #getIconPath() */ public URL getIconURL() throws InstantiableException { final String iconPath = getIconPath(); if (iconPath == null || iconPath.isEmpty()) return null; return loadClass().getResource(iconPath); } /** * Injects the metadata into the given object. Note that this is only possible * if the given object implements the {@link HasPluginInfo} interface. * * @param o The object to which the metadata should be assigned. * @return true If the metadata was successfully injected. */ public boolean inject(final Object o) { if (!(o instanceof HasPluginInfo)) return false; final HasPluginInfo hi = (HasPluginInfo) o; hi.setInfo(this); return true; } // -- Object methods -- @Override public String toString() { final StringMaker sm = new StringMaker(); sm.append("class", className); sm.append(super.toString()); sm.append("pluginType", pluginType); return sm.toString(); } // -- Instantiable methods -- @Override public String getClassName() { if (pluginClass != null) return pluginClass.getName(); return className; } @Override public Class loadClass() throws InstantiableException { if (pluginClass == null) { try { final Class c = Types.load(className, classLoader, false); @SuppressWarnings("unchecked") final Class typedClass = (Class) c; pluginClass = typedClass; } catch (final IllegalArgumentException exc) { throw new InstantiableException("Class not found: " + className, exc); } } return pluginClass; } @Override public PT createInstance() throws InstantiableException { final Class c = loadClass(); // instantiate plugin final PT instance; try { instance = c.newInstance(); inject(instance); Priority.inject(instance, getPriority()); } catch (final InstantiationException e) { throw new InstantiableException(e); } catch (final IllegalAccessException e) { throw new InstantiableException(e); } return instance; } // -- Identifiable methods -- @Override public String getIdentifier() { try { return "plugin:" + loadClass(); } catch (final InstantiableException exc) { return null; } } // -- Locatable methods -- @Override public String getLocation() { try { return Types.location(loadClass()).toExternalForm(); } catch (InstantiableException exc) { return null; } } // -- Versioned methods -- @Override public String getVersion() { try { return VersionUtils.getVersion(loadClass()); } catch (InstantiableException exc) { return null; } } // -- Helper methods -- /** Populates the entry to match the associated @{@link Plugin} annotation. */ private void populateValues() { final Plugin ann = getAnnotation(); if (ann == null) return; setName(ann.name()); setLabel(ann.label()); setDescription(ann.description()); final MenuPath menuPath; final Menu[] menu = ann.menu(); if (menu.length > 0) { menuPath = parseMenuPath(menu); } else { // parse menuPath attribute menuPath = new MenuPath(ann.menuPath()); } setMenuPath(menuPath); setMenuRoot(ann.menuRoot()); final String iconPath = ann.iconPath(); setIconPath(iconPath); setPriority(ann.priority()); setEnabled(ann.enabled()); setVisible(ann.visible()); setSelectable(ann.selectable()); setSelectionGroup(ann.selectionGroup()); // add default icon if none attached to leaf final MenuEntry menuLeaf = menuPath.getLeaf(); if (menuLeaf != null && !iconPath.isEmpty()) { final String menuIconPath = menuLeaf.getIconPath(); if (menuIconPath == null || menuIconPath.isEmpty()) { menuLeaf.setIconPath(iconPath); } } // populate extra attributes for (final Attr attr : ann.attrs()) { final String name = attr.name(); final String value = attr.value(); set(name, value); } } private MenuPath parseMenuPath(final Menu[] menu) { final MenuPath menuPath = new MenuPath(); for (int i = 0; i < menu.length; i++) { final String name = menu[i].label(); final double weight = menu[i].weight(); final char mnemonic = menu[i].mnemonic(); final Accelerator acc = Accelerator.create(menu[i].accelerator()); final String iconPath = menu[i].iconPath(); menuPath.add(new MenuEntry(name, weight, mnemonic, acc, iconPath)); } return menuPath; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy