diff --git a/pom.xml b/pom.xml index cde8d72fd..5c0396dbc 100644 --- a/pom.xml +++ b/pom.xml @@ -5,12 +5,12 @@ org.scijava pom-scijava - 5.1 + 5.3.3 scijava-common - 2.35.2-SNAPSHOT + 2.36.1-SNAPSHOT SciJava Common 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 both ImageJ and SCIFIO. diff --git a/src/main/java/org/scijava/AbstractBasicDetails.java b/src/main/java/org/scijava/AbstractBasicDetails.java index 64e354950..05e303be7 100644 --- a/src/main/java/org/scijava/AbstractBasicDetails.java +++ b/src/main/java/org/scijava/AbstractBasicDetails.java @@ -71,11 +71,6 @@ public String toString() { // -- BasicDetails methods -- - @Override - public String getName() { - return name; - } - @Override public String getLabel() { return label; @@ -96,11 +91,6 @@ public String get(final String key) { return values.get(key); } - @Override - public void setName(final String name) { - this.name = name; - } - @Override public void setLabel(final String label) { this.label = label; @@ -116,4 +106,16 @@ public void set(String key, String value) { values.put(key, value); } + // -- Named methods -- + + @Override + public String getName() { + return name; + } + + @Override + public void setName(final String name) { + this.name = name; + } + } diff --git a/src/main/java/org/scijava/BasicDetails.java b/src/main/java/org/scijava/BasicDetails.java index 6c8cb39cc..06c295c51 100644 --- a/src/main/java/org/scijava/BasicDetails.java +++ b/src/main/java/org/scijava/BasicDetails.java @@ -37,10 +37,7 @@ * * @author Curtis Rueden */ -public interface BasicDetails { - - /** Gets the unique name of the object. */ - String getName(); +public interface BasicDetails extends Named { /** Gets the name to appear in a UI, if applicable. */ String getLabel(); @@ -54,9 +51,6 @@ public interface BasicDetails { /** Gets the value of the given key, or null if undefined. */ public String get(String key); - /** Sets the unique name of the object. */ - void setName(String name); - /** Sets the name to appear in a UI, if applicable. */ void setLabel(String label); diff --git a/src/main/java/org/scijava/Context.java b/src/main/java/org/scijava/Context.java index edf0303df..c2c9fb0f6 100644 --- a/src/main/java/org/scijava/Context.java +++ b/src/main/java/org/scijava/Context.java @@ -42,6 +42,7 @@ import org.scijava.event.ContextDisposingEvent; import org.scijava.event.EventHandler; import org.scijava.event.EventService; +import org.scijava.log.LogService; import org.scijava.plugin.Parameter; import org.scijava.plugin.PluginIndex; import org.scijava.service.Service; @@ -62,10 +63,11 @@ public class Context implements Disposable { /** * System property indicating whether the context should fail fast when - * is attempts to instantiate a required service which is invalid or missing. + * attempting to instantiate a required service which is invalid or missing. * If this property is set to "false" then the context creation will attempt * to continue even when a required service cannot be instantiated. Otherwise, - * the constructor will throw an {@link IllegalArgumentException} in that situation. + * the constructor will throw an {@link IllegalArgumentException} in that + * situation. */ public static final String STRICT_PROPERTY = "scijava.context.strict"; @@ -77,6 +79,23 @@ public class Context implements Disposable { /** Master index of all plugins known to the application context. */ private final PluginIndex pluginIndex; + /** + * Whether context creation and injection should behave strictly, failing fast + * when attempting to instantiate a required service which is invalid or + * missing. + * + */ + private boolean strict; + /** * Creates a new SciJava application context with all available services. * @@ -239,6 +258,8 @@ public Context(final Collection> serviceClasses, this.pluginIndex = pluginIndex == null ? new PluginIndex() : pluginIndex; this.pluginIndex.discover(); + setStrict(strict); + final ServiceHelper serviceHelper = new ServiceHelper(this, serviceClasses, strict); serviceHelper.loadServices(); @@ -254,6 +275,14 @@ public PluginIndex getPluginIndex() { return pluginIndex; } + public boolean isStrict() { + return strict; + } + + public void setStrict(final boolean strict) { + this.strict = strict; + } + /** * Gets the service of the given class. * @@ -329,46 +358,14 @@ public Service getService(final String className) { */ public void inject(final Object o) { // iterate over all @Parameter annotated fields - final List fields = - ClassUtils.getAnnotatedFields(o.getClass(), Parameter.class); + final List fields = getParameterFields(o); for (final Field f : fields) { - f.setAccessible(true); // expose private fields - - final Class type = f.getType(); - if (Service.class.isAssignableFrom(type)) { - final Service existingService = (Service) ClassUtils.getValue(f, o); - if (existingService != null) { - throw new IllegalStateException("Context already injected: " + - f.getDeclaringClass().getName() + "#" + f.getName()); - } - - // populate Service parameter - @SuppressWarnings("unchecked") - final Class serviceType = - (Class) type; - final Service service = getService(serviceType); - if (service == null && f.getAnnotation(Parameter.class).required()) { - throw new IllegalArgumentException( - createMissingServiceMessage(serviceType)); - } - ClassUtils.setValue(f, o, service); - } - else if (Context.class.isAssignableFrom(type) && type.isInstance(this)) { - final Context existingContext = (Context) ClassUtils.getValue(f, o); - if (existingContext != null) { - throw new IllegalStateException("Context already injected: " + - f.getDeclaringClass().getName() + "#" + f.getName()); - } - - // populate Context parameter - ClassUtils.setValue(f, o, this); - } + inject(f, o); } // NB: Subscribe to all events handled by this object. // This greatly simplifies event handling. - final EventService eventService = getService(EventService.class); - if (eventService != null) eventService.subscribe(o); + subscribeToEvents(o); } // -- Disposable methods -- @@ -403,6 +400,75 @@ public static List> serviceClassList( // -- Helper methods -- + private List getParameterFields(Object o) { + try { + return ClassUtils.getAnnotatedFields(o.getClass(), Parameter.class); + } + catch (final Throwable t) { + handleSafely(t); + } + return Collections.emptyList(); + } + + private void inject(final Field f, final Object o) { + try { + f.setAccessible(true); // expose private fields + + final Class type = f.getType(); + if (Service.class.isAssignableFrom(type)) { + final Service existingService = (Service) ClassUtils.getValue(f, o); + if (existingService != null) { + throw new IllegalStateException("Context already injected: " + + f.getDeclaringClass().getName() + "#" + f.getName()); + } + + // populate Service parameter + @SuppressWarnings("unchecked") + final Class serviceType = + (Class) type; + final Service service = getService(serviceType); + if (service == null && f.getAnnotation(Parameter.class).required()) { + throw new IllegalArgumentException( + createMissingServiceMessage(serviceType)); + } + ClassUtils.setValue(f, o, service); + } + else if (Context.class.isAssignableFrom(type) && type.isInstance(this)) { + final Context existingContext = (Context) ClassUtils.getValue(f, o); + if (existingContext != null) { + throw new IllegalStateException("Context already injected: " + + f.getDeclaringClass().getName() + "#" + f.getName()); + } + + // populate Context parameter + ClassUtils.setValue(f, o, this); + } + } + catch (final Throwable t) { + handleSafely(t); + } + } + + private void subscribeToEvents(final Object o) { + try { + final EventService eventService = getService(EventService.class); + if (eventService != null) eventService.subscribe(o); + } + catch (final Throwable t) { + handleSafely(t); + } + } + + private void handleSafely(final Throwable t) { + if (isStrict()) { + // NB: Only rethrow unchecked exceptions. + if (t instanceof RuntimeException) throw (RuntimeException) t; + if (t instanceof Error) throw (Error) t; + } + final LogService log = getService(LogService.class); + if (log != null) log.error(t); + } + private String createMissingServiceMessage( final Class serviceType) { diff --git a/src/main/java/org/scijava/MenuEntry.java b/src/main/java/org/scijava/MenuEntry.java index 1fd70ab36..cc31b20fe 100644 --- a/src/main/java/org/scijava/MenuEntry.java +++ b/src/main/java/org/scijava/MenuEntry.java @@ -39,7 +39,7 @@ * @author Curtis Rueden * @author Johannes Schindelin */ -public class MenuEntry { +public class MenuEntry implements Named { public static final double DEFAULT_WEIGHT = Double.POSITIVE_INFINITY; @@ -68,14 +68,6 @@ public MenuEntry(final String name, final double weight, setIconPath(iconPath); } - public void setName(final String name) { - this.name = name; - } - - public String getName() { - return name; - } - public void setWeight(final double weight) { this.weight = weight; } @@ -120,6 +112,20 @@ public void assignProperties(final MenuEntry entry) { if (iconPath == null) iconPath = entry.getIconPath(); } + // -- Named methods -- + + @Override + public String getName() { + return name; + } + + @Override + public void setName(final String name) { + this.name = name; + } + + // -- Object methods -- + @Override public String toString() { return name; diff --git a/src/main/java/org/scijava/Named.java b/src/main/java/org/scijava/Named.java new file mode 100644 index 000000000..5e715ce9a --- /dev/null +++ b/src/main/java/org/scijava/Named.java @@ -0,0 +1,47 @@ +/* + * #%L + * SciJava Common shared library for SciJava software. + * %% + * Copyright (C) 2009 - 2014 Board of Regents of the University of + * Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck + * Institute of Molecular Cell Biology and Genetics. + * %% + * 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; + +/** + * Interface for things that have names. + * + * @author Lee Kamentsky + */ +public interface Named { + + /** Gets the name of the object. */ + String getName(); + + /** Sets the name of the object. */ + void setName(String name); + +} diff --git a/src/main/java/org/scijava/command/CommandModuleItem.java b/src/main/java/org/scijava/command/CommandModuleItem.java index e325ef468..5f6524095 100644 --- a/src/main/java/org/scijava/command/CommandModuleItem.java +++ b/src/main/java/org/scijava/command/CommandModuleItem.java @@ -167,11 +167,6 @@ public List getChoices() { // -- BasicDetails methods -- - @Override - public String getName() { - return field.getName(); - } - @Override public String getLabel() { return getParameter().label(); @@ -198,4 +193,11 @@ public String get(final String key) { return null; } + // -- Named methods -- + + @Override + public String getName() { + return field.getName(); + } + } diff --git a/src/main/java/org/scijava/command/DynamicCommandInfo.java b/src/main/java/org/scijava/command/DynamicCommandInfo.java index 178bc9d97..4227b1cd8 100644 --- a/src/main/java/org/scijava/command/DynamicCommandInfo.java +++ b/src/main/java/org/scijava/command/DynamicCommandInfo.java @@ -248,11 +248,6 @@ public void setSelected(final boolean selected) { // -- BasicDetails methods -- - @Override - public String getName() { - return info.getName(); - } - @Override public String getLabel() { return info.getLabel(); @@ -263,11 +258,6 @@ public String getDescription() { return info.getDescription(); } - @Override - public void setName(final String name) { - info.setName(name); - } - @Override public void setLabel(final String label) { info.setLabel(label); @@ -278,6 +268,18 @@ public void setDescription(final String description) { info.setDescription(description); } + // -- Named methods -- + + @Override + public String getName() { + return info.getName(); + } + + @Override + public void setName(final String name) { + info.setName(name); + } + // -- Validated methods -- @Override diff --git a/src/main/java/org/scijava/display/AbstractDisplay.java b/src/main/java/org/scijava/display/AbstractDisplay.java index 7ed70aa4a..22796e346 100644 --- a/src/main/java/org/scijava/display/AbstractDisplay.java +++ b/src/main/java/org/scijava/display/AbstractDisplay.java @@ -150,6 +150,8 @@ public void close() { isClosed = true; } + // -- Named methods -- + @Override public String getName() { return name; diff --git a/src/main/java/org/scijava/display/Display.java b/src/main/java/org/scijava/display/Display.java index 8a82d5a42..4461c200a 100644 --- a/src/main/java/org/scijava/display/Display.java +++ b/src/main/java/org/scijava/display/Display.java @@ -33,6 +33,7 @@ import java.util.List; +import org.scijava.Named; import org.scijava.plugin.Plugin; import org.scijava.plugin.RichPlugin; @@ -52,7 +53,7 @@ * @see Plugin * @see DisplayService */ -public interface Display extends List, RichPlugin { +public interface Display extends List, RichPlugin, Named { /** * Tests whether the display is capable of visualizing objects of the given @@ -99,10 +100,4 @@ public interface Display extends List, RichPlugin { /** Closes the display and disposes its resources. */ void close(); - /** Gets the name of the display. */ - String getName(); - - /** Sets the name of the display. */ - void setName(String name); - } diff --git a/src/main/java/org/scijava/log/AbstractLogService.java b/src/main/java/org/scijava/log/AbstractLogService.java index fefc5a5d0..53062fdc8 100644 --- a/src/main/java/org/scijava/log/AbstractLogService.java +++ b/src/main/java/org/scijava/log/AbstractLogService.java @@ -44,7 +44,7 @@ */ public abstract class AbstractLogService extends AbstractService implements LogService { - private int currentLevel = System.getenv("DEBUG") == null ? WARN : DEBUG; + private int currentLevel = System.getenv("DEBUG") == null ? INFO : DEBUG; private Map classAndPackageLevels = new HashMap(); @@ -77,7 +77,7 @@ public AbstractLogService() { if (getLevel() == 0) { // use the default, which is WARN unless the DEBUG env. variable is set - setLevel(System.getenv("DEBUG") == null ? WARN : DEBUG); + setLevel(System.getenv("DEBUG") == null ? INFO : DEBUG); } // populate custom class- and package-specific log level properties diff --git a/src/main/java/org/scijava/menu/ShadowMenu.java b/src/main/java/org/scijava/menu/ShadowMenu.java index b117f1e0c..8efb7bf8f 100644 --- a/src/main/java/org/scijava/menu/ShadowMenu.java +++ b/src/main/java/org/scijava/menu/ShadowMenu.java @@ -45,6 +45,7 @@ import org.scijava.Context; import org.scijava.MenuEntry; import org.scijava.MenuPath; +import org.scijava.Named; import org.scijava.event.EventService; import org.scijava.log.LogService; import org.scijava.menu.event.MenusAddedEvent; @@ -79,7 +80,7 @@ * @see MenuEntry */ public class ShadowMenu extends AbstractContextual implements - Comparable, Collection, Runnable + Comparable, Collection, Runnable, Named { /** Icon to use for leaf entries by default, if no icon is specified. */ @@ -177,11 +178,6 @@ public int getMenuDepth() { return menuDepth; } - /** Gets the name of the menu. */ - public String getName() { - return menuEntry == null ? null : menuEntry.getName(); - } - /** Gets this node's parent, or null if it is a root node. */ public ShadowMenu getParent() { return parent; @@ -279,6 +275,19 @@ public boolean updateAll(final Collection c) { return true; } + // -- Named methods -- + + @Override + public String getName() { + return menuEntry == null ? null : menuEntry.getName(); + } + + @Override + public void setName(final String name) { + if (menuEntry == null) return; + menuEntry.setName(name); + } + // -- Object methods -- @Override diff --git a/src/main/java/org/scijava/module/DefaultMutableModuleItem.java b/src/main/java/org/scijava/module/DefaultMutableModuleItem.java index 50c085ac5..372809564 100644 --- a/src/main/java/org/scijava/module/DefaultMutableModuleItem.java +++ b/src/main/java/org/scijava/module/DefaultMutableModuleItem.java @@ -296,11 +296,6 @@ public List getChoices() { // -- BasicDetails methods -- - @Override - public String getName() { - return name; - } - @Override public String getLabel() { return label; @@ -311,11 +306,6 @@ public String getDescription() { return description; } - @Override - public void setName(final String name) { - this.name = name; - } - @Override public void setLabel(final String label) { this.label = label; @@ -326,4 +316,16 @@ public void setDescription(final String description) { this.description = description; } + // -- Named methods -- + + @Override + public String getName() { + return name; + } + + @Override + public void setName(final String name) { + this.name = name; + } + } diff --git a/src/main/java/org/scijava/platform/DefaultPlatformService.java b/src/main/java/org/scijava/platform/DefaultPlatformService.java index 446c4c9a9..9eae1470b 100644 --- a/src/main/java/org/scijava/platform/DefaultPlatformService.java +++ b/src/main/java/org/scijava/platform/DefaultPlatformService.java @@ -164,7 +164,7 @@ public void initialize() { log.debug("Configuring platform: " + platform.getClass().getName()); platform.configure(this); } - if (platforms.size() == 0) log.info("No platforms to configure."); + if (platforms.size() == 0) log.debug("No platforms to configure."); } // -- Disposable methods -- diff --git a/src/main/java/org/scijava/plugin/AbstractSingletonService.java b/src/main/java/org/scijava/plugin/AbstractSingletonService.java index 3d5b013c4..d965238a8 100644 --- a/src/main/java/org/scijava/plugin/AbstractSingletonService.java +++ b/src/main/java/org/scijava/plugin/AbstractSingletonService.java @@ -125,7 +125,7 @@ private synchronized void initInstances() { map.put(ptClass, plugin); } - log.info("Found " + list.size() + " " + getPluginType().getSimpleName() + + log.debug("Found " + list.size() + " " + getPluginType().getSimpleName() + " plugins."); instanceMap = map; diff --git a/src/main/java/org/scijava/plugin/AbstractWrapperService.java b/src/main/java/org/scijava/plugin/AbstractWrapperService.java index 89a4756bc..964916608 100644 --- a/src/main/java/org/scijava/plugin/AbstractWrapperService.java +++ b/src/main/java/org/scijava/plugin/AbstractWrapperService.java @@ -64,7 +64,7 @@ public PT create(final D data) { @Override public void initialize() { if (log != null) { - log.info("Found " + getPlugins().size() + " " + + log.debug("Found " + getPlugins().size() + " " + getPluginType().getSimpleName() + " plugins."); } } diff --git a/src/main/java/org/scijava/plugin/DefaultPluginService.java b/src/main/java/org/scijava/plugin/DefaultPluginService.java index db1048a86..74e26aa25 100644 --- a/src/main/java/org/scijava/plugin/DefaultPluginService.java +++ b/src/main/java/org/scijava/plugin/DefaultPluginService.java @@ -249,7 +249,7 @@ public List createInstances( public void initialize() { pluginIndex = context().getPluginIndex(); - log.info("Found " + pluginIndex.size() + " plugins."); + log.debug("Found " + pluginIndex.size() + " plugins."); if (log.isDebug()) { for (final PluginInfo info : pluginIndex) { log.debug("- " + info); diff --git a/src/main/java/org/scijava/script/ScriptFinder.java b/src/main/java/org/scijava/script/ScriptFinder.java index 528b6b4d4..43715545d 100644 --- a/src/main/java/org/scijava/script/ScriptFinder.java +++ b/src/main/java/org/scijava/script/ScriptFinder.java @@ -84,7 +84,7 @@ public void findScripts(final List scripts) { final HashSet scriptFiles = new HashSet(); for (final File directory : directories) { if (!directory.exists()) { - log.warn("Ignoring non-existent scripts directory: " + + log.debug("Ignoring non-existent scripts directory: " + directory.getAbsolutePath()); continue; } @@ -94,7 +94,7 @@ public void findScripts(final List scripts) { discoverScripts(scripts, scriptFiles, directory, menuPath); } - log.info("Found " + scriptCount + " scripts"); + log.debug("Found " + scriptCount + " scripts"); } // -- Helper methods -- diff --git a/src/main/java/org/scijava/ui/DefaultUIService.java b/src/main/java/org/scijava/ui/DefaultUIService.java index d66eeed95..ac576b86f 100644 --- a/src/main/java/org/scijava/ui/DefaultUIService.java +++ b/src/main/java/org/scijava/ui/DefaultUIService.java @@ -176,7 +176,7 @@ public void showUI(final String name) { @Override public void showUI(final UserInterface ui) { - log.info("Launching user interface: " + ui.getClass().getName()); + log.debug("Launching user interface: " + ui.getClass().getName()); ui.show(); // NB: Also show all the current displays. for (final Display display : displayService.getDisplays()) { @@ -499,7 +499,7 @@ private synchronized void discoverUIs() { // instantiate user interface final UserInterface ui = pluginService.createInstance(info); if (ui == null) continue; - log.info("Discovered user interface: " + ui.getClass().getName()); + log.debug("Discovered user interface: " + ui.getClass().getName()); addUserInterface(info.getName(), ui); }