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

imagej.patcher.LegacyEnvironment Maven / Gradle / Ivy

Go to download

A runtime patcher to introduce extension points into ImageJ 1.x. This project offers extension points for use with ImageJ2 and it also offers (limited) support for headless operations.

The newest version!
/*
 * #%L
 * ImageJ2 software for multidimensional image processing and analysis.
 * %%
 * Copyright (C) 2009 - 2024 ImageJ2 developers.
 * %%
 * 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 imagej.patcher;

import imagej.patcher.LegacyInjector.Callback;

import java.awt.GraphicsEnvironment;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;
import java.util.jar.Attributes.Name;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

/**
 * @deprecated Use {@link net.imagej.patcher.LegacyEnvironment} instead.
 */
@Deprecated
public class LegacyEnvironment {

	final private boolean headless;
	final private LegacyInjector injector;
	private Throwable initializationStackTrace;
	private ClassLoader loader;
	private Method setOptions, run, runMacro, runPlugIn, main;
	private Field _hooks;

	public LegacyEnvironment(final ClassLoader loader, final boolean headless)
		throws ClassNotFoundException
	{
		this(loader, headless, new LegacyInjector());
	}

	LegacyEnvironment(final ClassLoader loader, final boolean headless,
		final LegacyInjector injector) throws ClassNotFoundException
	{
		this.headless = headless;
		this.loader = loader;
		this.injector = injector;
	}

	private boolean isInitialized() {
		return _hooks != null;
	}

	private synchronized void initialize() {
		if (isInitialized()) return;
		initializationStackTrace = new Throwable("Initialized here:");
		if (loader != null) {
			injector.injectHooks(loader, headless);
		}
		try {
			this.loader =
				loader != null ? loader : new LegacyClassLoader(headless, injector);
			final Class ij = this.loader.loadClass("ij.IJ");
			final Class imagej = this.loader.loadClass("ij.ImageJ");
			final Class macro = this.loader.loadClass("ij.Macro");
			_hooks = ij.getField("_hooks");
			setOptions = macro.getMethod("setOptions", String.class);
			run = ij.getMethod("run", String.class, String.class);
			runMacro = ij.getMethod("runMacro", String.class, String.class);
			runPlugIn = ij.getMethod("runPlugIn", String.class, String.class);
			main = imagej.getMethod("main", String[].class);
		}
		catch (final Exception e) {
			throw new RuntimeException("Found incompatible ij.IJ class", e);
		}
		// TODO: if we want to allow calling IJ#run(ImagePlus, String, String), we
		// will need a data translator
	}

	private void ensureUninitialized() {
		if (isInitialized()) {
			final StringWriter string = new StringWriter();
			final PrintWriter writer = new PrintWriter(string);
			initializationStackTrace.printStackTrace(writer);
			writer.close();
			throw new RuntimeException(
				"LegacyEnvironment was already initialized:\n\n" +
					string.toString().replaceAll("(?m)^", "\t"));
		}
	}

	public void disableIJ1PluginDirs() {
		ensureUninitialized();
		injector.after.add(new Callback() {
			@Override
			public void call(final CodeHacker hacker) {
				hacker.insertAtBottomOfMethod(EssentialLegacyHooks.class.getName(),
					"public ()",
					"enableIJ1PluginDirs(false);");
			}
		});
	}

	public void addPluginClasspath(final ClassLoader fromClassLoader) {
		if (fromClassLoader == null) return;
		ensureUninitialized();
		for (ClassLoader loader = fromClassLoader; loader != null; loader =
			loader.getParent())
		{
			if (loader == this.loader) {
				break;
			}
			if (this.loader != null && loader == this.loader.getParent()) {
				break;
			}
			if (this.loader == null &&
				loader == getClass().getClassLoader().getParent())
			{
				break;
			}
			if (!(loader instanceof URLClassLoader)) {
				if (loader != fromClassLoader) continue;
				throw new IllegalArgumentException(
					"Cannot add class path from ClassLoader of type " +
						fromClassLoader.getClass().getName());
			}

			for (final URL url : ((URLClassLoader) loader).getURLs()) {
				if (!"file".equals(url.getProtocol())) {
					throw new RuntimeException("Not a file URL! " + url);
				}
				addPluginClasspath(new File(url.getPath()));
				final String path = url.getPath();
				if (path.matches(".*/target/surefire/surefirebooter[0-9]*\\.jar")) try {
					final JarFile jar = new JarFile(path);
					final Manifest manifest = jar.getManifest();
					if (manifest != null) {
						final String classPath =
							manifest.getMainAttributes().getValue(Name.CLASS_PATH);
						if (classPath != null) {
							for (final String element : classPath.split(" +"))
								try {
									final URL url2 = new URL(element);
									if (!"file".equals(url2.getProtocol())) continue;
									addPluginClasspath(new File(url2.getPath()));
								}
								catch (final MalformedURLException e) {
									e.printStackTrace();
								}
						}
					}
				}
				catch (final IOException e) {
					System.err
						.println("Warning: could not add plugin class path due to ");
					e.printStackTrace();
				}

			}
		}
	}

	public void addPluginClasspath(final File... classpathEntries) {
		if (classpathEntries.length == 0) return;
		ensureUninitialized();

		final StringBuilder builder = new StringBuilder();
		for (final File file : classpathEntries) {
			final String quoted = file.getPath().replaceAll("[\\\"\\\\]", "\\\\$0").replaceAll("\n", "\\n");
			builder.append("addPluginClasspath(new java.io.File(\"").append(quoted).append("\"));");
		}

		injector.after.add(new Callback() {
			@Override
			public void call(final CodeHacker hacker) {
				hacker.insertAtBottomOfMethod(EssentialLegacyHooks.class.getName(),
					"public ()",
					builder.toString());
			}
		});
	}

	public void setMacroOptions(final String options) {
		initialize();
		try {
			setOptions.invoke(null, options);
		}
		catch (final Exception e) {
			throw new RuntimeException(e);
		}
	}

	public void run(final String command, final String options) {
		initialize();
		final Thread thread = Thread.currentThread();
		final ClassLoader savedLoader = thread.getContextClassLoader();
		thread.setContextClassLoader(loader);
		try {
			run.invoke(null, command, options);
		}
		catch (final Exception e) {
			throw new RuntimeException(e);
		}
		finally {
			thread.setContextClassLoader(savedLoader);
		}
	}

	public void runMacro(final String macro, final String arg) {
		initialize();
		final Thread thread = Thread.currentThread();
		final String savedName = thread.getName();
		thread.setName("Run$_" + savedName);
		final ClassLoader savedLoader = thread.getContextClassLoader();
		thread.setContextClassLoader(loader);
		try {
			runMacro.invoke(null, macro, arg);
		}
		catch (final Exception e) {
			throw new RuntimeException(e);
		}
		finally {
			thread.setName(savedName);
			thread.setContextClassLoader(savedLoader);
		}
	}

	public Object runPlugIn(final String className, final String arg) {
		initialize();
		final Thread thread = Thread.currentThread();
		final String savedName = thread.getName();
		thread.setName("Run$_" + savedName);
		final ClassLoader savedLoader = thread.getContextClassLoader();
		thread.setContextClassLoader(loader);
		try {
			return runPlugIn.invoke(null, className, arg);
		}
		catch (final Exception e) {
			throw new RuntimeException(e);
		}
		finally {
			thread.setName(savedName);
			thread.setContextClassLoader(savedLoader);
		}
	}

	public void main(final String... args) {
		initialize();
		Thread.currentThread().setContextClassLoader(loader);
		try {
			main.invoke(null, (Object) args);
		}
		catch (final Exception e) {
			throw new RuntimeException(e);
		}
	}

	public ClassLoader getClassLoader() {
		initialize();
		return loader;
	}

	public Map getMenuStructure() {
		initialize();
		try {
			final LegacyHooks hooks = (LegacyHooks) _hooks.get(null);
			return hooks.getMenuStructure();
		}
		catch (final RuntimeException e) {
			throw e;
		}
		catch (final Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static LegacyEnvironment getPatchedImageJ1()
		throws ClassNotFoundException
	{
		final boolean headless = GraphicsEnvironment.isHeadless();
		return new LegacyEnvironment(new LegacyClassLoader(headless), headless);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy