net.imagej.patcher
Class LegacyEnvironment

java.lang.Object
  extended by net.imagej.patcher.LegacyEnvironment

public class LegacyEnvironment
extends Object

Encapsulates an ImageJ 1.x "instance".

This class is a partner to the LegacyClassLoader, intended to make sure that the ImageJ 1.x contained in a given class loader is patched and can be accessed conveniently.

Author:
"Johannes Schindelin"

Constructor Summary
LegacyEnvironment(ClassLoader loader, boolean headless)
          Constructs a new legacy environment.
 
Method Summary
 void addPluginClasspath(ClassLoader fromClassLoader)
          Adds the class path of a given ClassLoader to the plugin class loader.
 void addPluginClasspath(File... classpathEntries)
          Adds extra elements to the class path of ImageJ 1.x' plugin class loader.
 void applyPatches()
          Applies the configuration patches.
 void disableIJ1PluginDirs()
          Disallows the encapsulated ImageJ 1.x from parsing the directories listed in ij1.plugin.dirs.
 void disableInitializer()
          Disables the execution of the ij1.patcher.initializer.
 ClassLoader getClassLoader()
          Gets the class loader containing the ImageJ 1.x classes used in this legacy environment.
 Map<String,String> getMenuStructure()
          Gets the ImageJ 1.x menu structure as a map
static LegacyEnvironment getPatchedImageJ1()
          Launches a fully-patched, self-contained ImageJ 1.x.
static boolean isImageJ1Initialized(ClassLoader loader)
          Determines whether there is already an ImageJ 1.x instance.
 void main(String... args)
          Runs ImageJ.main(args) in the legacy environment.
 Object newImageJ1(boolean hidden)
          Initializes a new ImageJ 1.x instance.
 void noPluginClassLoader()
          Forces ImageJ 1.x to use the same ClassLoader for plugins as for ImageJ 1.x itself.
 void run(String command, String options)
          Runs IJ.run(command, options) in the legacy environment.
 void runMacro(String macro, String arg)
          Runs IJ.runMacro(macro, arg) in the legacy environment.
 Object runPlugIn(String className, String arg)
          Runs IJ.runPlugIn(className, arg) in the legacy environment.
 void setMacroOptions(String options)
          Sets the macro options.
 void suppressIJ1ScriptDiscovery()
          Disallows ImageJ 1.x from discovering macros and scripts to put into the menu structure.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

LegacyEnvironment

public LegacyEnvironment(ClassLoader loader,
                         boolean headless)
                  throws ClassNotFoundException
Constructs a new legacy environment.

Parameters:
loader - the ClassLoader to use for loading the (patched) ImageJ 1.x classes; if null, a LegacyClassLoader is constructed.
headless - whether to patch in support for headless operation (compatible only with "well-behaved" plugins, i.e. plugins that do not use graphical components directly)
Throws:
ClassNotFoundException
Method Detail

disableIJ1PluginDirs

public void disableIJ1PluginDirs()
Disallows the encapsulated ImageJ 1.x from parsing the directories listed in ij1.plugin.dirs.

The patched ImageJ 1.x has a feature where it interprets the value of the ij1.plugin.dirs system property as a list of directories in which to discover plugins in addition to <imagej.dir>/plugins. In the case that the ij1.plugin.dirs property is not set, the directory $HOME/.plugins/ -- if it exists -- is inspected instead.

This is a convenient behavior when the user starts up ImageJ 1.x as an application, but it is less than desirable when running in a cluster or from unit tests. For such use cases, this method needs to be called in order to disable additional plugin directories.


disableInitializer

public void disableInitializer()
Disables the execution of the ij1.patcher.initializer.

A fully patched ImageJ 1.x will allow an initializer class implementing the Runnable interface (and discovered via ImageJ 1.x' own PluginClassLoader) to run just after ImageJ 1.x was initialized. If the system property ij1.patcher.initializer is unset, it defaults to ImageJ2's LegacyInitializer class.

Users of the LegacyEnvironment class can call this method to disable that behavior.


noPluginClassLoader

public void noPluginClassLoader()
Forces ImageJ 1.x to use the same ClassLoader for plugins as for ImageJ 1.x itself.

ImageJ 1.x has a command Help>Refresh Menus that allows users to ask ImageJ 1.x to parse the plugins/ directory for new, or modified, plugins, and to remove menu labels corresponding to plugins whose files were deleted while ImageJ 1.x is running. The intended use case is to support developing ImageJ 1.x plugins without having to restart ImageJ 1.x all the time, just to test new iterations of the same plugin.

To support this, a PluginClassLoader that loads the plugin classes is instantiated at initialization, and whenever the user calls Refresh Menus, essentially releasing the old ClassLoader. This is a fragile solution, as no measures are taken to ensure that the classes loaded by the previous PluginClassLoader are no longer used, but it works most of the time.

With ImageJ2 being developed in a modular manner, it is no longer easy to have one class loader containing only the ImageJ classes and another class loader containing all the plugins. Therefore, this method is required to be able to force ImageJ 1.x to reuse the same class loader for plugins as for ImageJ classes, implying that the Refresh Menus command needs to be disabled.

Since the advent of powerful Integrated Development Environments such as Netbeans and Eclipse, it is preferable to develop even ImageJ 1.x plugins in such environments instead of using a text editor to edit the .java source, then running javac from the command-line, calling Refresh Menus and finally repeating the manual test procedure, anyway.


suppressIJ1ScriptDiscovery

public void suppressIJ1ScriptDiscovery()
Disallows ImageJ 1.x from discovering macros and scripts to put into the menu structure.

Some callers -- most notably ImageJ2 and Fiji -- want to improve on the scripting support, which unfortunately implies overriding the non-extensible script and macro handling of ImageJ 1.x.


addPluginClasspath

public void addPluginClasspath(ClassLoader fromClassLoader)
Adds the class path of a given ClassLoader to the plugin class loader.

This method is intended to be used in unit tests as well as interactive debugging from inside an Integrated Development Environment where the plugin's classes are not available inside a .jar file.

At the moment, the only supported parameters are URLClassLoaders.

Parameters:
fromClassLoader - the class path donor

addPluginClasspath

public void addPluginClasspath(File... classpathEntries)
Adds extra elements to the class path of ImageJ 1.x' plugin class loader.

The typical use case for a LegacyEnvironment is to run specific plugins in an encapsulated environment. However, in the case of multiple one wants to use multiple legacy environments with separate sets of plugins enabled, it becomes impractical to pass the location of the plugins' .jar files via the plugins.dir system property (because of threading issues).

In other cases, the plugins' .jar files are not located in a single directory, or worse: they might be contained in a directory among .jar files one might not want to add to the plugin class loader's class path.

This method addresses that need by allowing to add individual .jar files to the class path of the plugin class loader and ensuring that their plugins.config files are parsed.

Parameters:
classpathEntries - the class path entries containing ImageJ 1.x plugins

setMacroOptions

public void setMacroOptions(String options)
Sets the macro options.

Both run(String, String) and runMacro(String, String) take an argument that is typically recorded by the macro recorder. For runPlugIn(String, String), however, only the arg parameter that is to be passed to the plugins run() or setup() method can be specified. For those use cases where one wants to call a plugin class directly, but still provide macro options, this method is the solution.

Parameters:
options - the macro options to use for the next call to runPlugIn(String, String)

run

public void run(String command,
                String options)
Runs IJ.run(command, options) in the legacy environment.

Parameters:
command - the command to run
options - the options to pass to the command

runMacro

public void runMacro(String macro,
                     String arg)
Runs IJ.runMacro(macro, arg) in the legacy environment.

Parameters:
macro - the macro code to run
arg - an optional argument (which can be retrieved in the macro code via getArgument())

runPlugIn

public Object runPlugIn(String className,
                        String arg)
Runs IJ.runPlugIn(className, arg) in the legacy environment.

Parameters:
className - the plugin class to run
arg - an optional argument (which get passed to the run() or setup() method of the plugin)

main

public void main(String... args)
Runs ImageJ.main(args) in the legacy environment.

Parameters:
args - the arguments to pass to the main() method

newImageJ1

public Object newImageJ1(boolean hidden)
Initializes a new ImageJ 1.x instance.

This method starts up a fully-patched ImageJ 1.x, optionally hidden (in headless mode, it must be hidden).

Parameters:
hidden - whether to hide the ImageJ 1.x main window upon startup
Returns:
the instance of the ImageJ class, or null in headless mode

applyPatches

public void applyPatches()
Applies the configuration patches.

After calling methods to configure the current LegacyEnvironment (e.g. disableIJ1PluginDirs()), the final step before using the encapsulated ImageJ 1.x is to apply the configuring patches to the EssentialLegacyHooks class. This method needs to be called if the configuration has to be finalized, but ImageJ 1.x is not run right away, e.g. to prepare for third-party libraries using ImageJ 1.x classes directly.


getClassLoader

public ClassLoader getClassLoader()
Gets the class loader containing the ImageJ 1.x classes used in this legacy environment.

Returns:
the class loader

getMenuStructure

public Map<String,String> getMenuStructure()
Gets the ImageJ 1.x menu structure as a map


getPatchedImageJ1

public static LegacyEnvironment getPatchedImageJ1()
                                           throws ClassNotFoundException
Launches a fully-patched, self-contained ImageJ 1.x.

Throws:
ClassNotFoundException

isImageJ1Initialized

public static boolean isImageJ1Initialized(ClassLoader loader)
Determines whether there is already an ImageJ 1.x instance.

In contrast to IJ.getInstance(), this method avoids loading any ImageJ 1.x class, and is therefore suitable for testing whether a LegacyEnvironment needs to be created when the caller wants the classes to be patched in its own ClassLoader.

Parameters:
loader - the class loader in which to look for the ImageJ 1.x instance
Returns:
true if there is an initialized instance


Copyright © 2009–2014 ImageJ. All rights reserved.