Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
<parent>
<groupId>org.scijava</groupId>
<artifactId>pom-scijava</artifactId>
<version>5.1</version>
<version>5.3.3</version>
<relativePath />
</parent>

<artifactId>scijava-common</artifactId>
<version>2.35.2-SNAPSHOT</version>
<version>2.36.1-SNAPSHOT</version>

<name>SciJava Common</name>
<description>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.</description>
Expand Down
22 changes: 12 additions & 10 deletions src/main/java/org/scijava/AbstractBasicDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ public String toString() {

// -- BasicDetails methods --

@Override
public String getName() {
return name;
}

@Override
public String getLabel() {
return label;
Expand All @@ -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;
Expand All @@ -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;
}

}
8 changes: 1 addition & 7 deletions src/main/java/org/scijava/BasicDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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);

Expand Down
140 changes: 103 additions & 37 deletions src/main/java/org/scijava/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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";

Expand All @@ -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.
* <ul>
* <li>If the flag is 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.</li>
* <li>If this flag is false, then a call to {@link Context#inject(Object)}
* will attempt to catch any errors that occur during context injection
* (notably: {@link NoClassDefFoundError} when scanning for event handler
* methods), logging them as errors.</li>
* </ul>
*/
private boolean strict;

/**
* Creates a new SciJava application context with all available services.
*
Expand Down Expand Up @@ -239,6 +258,8 @@ public Context(final Collection<Class<? extends Service>> serviceClasses,
this.pluginIndex = pluginIndex == null ? new PluginIndex() : pluginIndex;
this.pluginIndex.discover();

setStrict(strict);

final ServiceHelper serviceHelper =
new ServiceHelper(this, serviceClasses, strict);
serviceHelper.loadServices();
Expand All @@ -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.
*
Expand Down Expand Up @@ -329,46 +358,14 @@ public Service getService(final String className) {
*/
public void inject(final Object o) {
// iterate over all @Parameter annotated fields
final List<Field> fields =
ClassUtils.getAnnotatedFields(o.getClass(), Parameter.class);
final List<Field> 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<? extends Service> serviceType =
(Class<? extends Service>) 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 --
Expand Down Expand Up @@ -403,6 +400,75 @@ public static List<Class<? extends Service>> serviceClassList(

// -- Helper methods --

private List<Field> 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<? extends Service> serviceType =
(Class<? extends Service>) 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<? extends Service> serviceType)
{
Expand Down
24 changes: 15 additions & 9 deletions src/main/java/org/scijava/MenuEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/org/scijava/Named.java
Original file line number Diff line number Diff line change
@@ -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);

}
12 changes: 7 additions & 5 deletions src/main/java/org/scijava/command/CommandModuleItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,6 @@ public List<T> getChoices() {

// -- BasicDetails methods --

@Override
public String getName() {
return field.getName();
}

@Override
public String getLabel() {
return getParameter().label();
Expand All @@ -198,4 +193,11 @@ public String get(final String key) {
return null;
}

// -- Named methods --

@Override
public String getName() {
return field.getName();
}

}
Loading