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

net.imagej.patcher.EssentialLegacyHooks Maven / Gradle / Ivy

Go to download

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

There is a newer version: 1.2.7
Show newest version
/*
 * #%L
 * ImageJ software for multidimensional image processing and analysis.
 * %%
 * Copyright (C) 2009 - 2016 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 net.imagej.patcher;

import ij.IJ;

import java.io.File;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * The base {@link LegacyHooks} to be used in the patched ImageJ 1.x.
 * 

* This is the minimal implementation of {@link LegacyHooks} and will be * installed by default after patching in the extension points into ImageJ 1.x. * On its own, it does not allow to override the extension points (such as the * editor) with different implementations; one needs to install different hooks * using the * {@link net.imagej.patcher.LegacyInjector#installHooks(ClassLoader, LegacyHooks)} * method. *

*

* This class is also the perfect base class for all implementations of the * {@link LegacyHooks} interface, e.g. to offer "real" extension mechanisms such * as the SciJava-common plugin framework. *

* * @author Johannes Schindelin */ public class EssentialLegacyHooks extends LegacyHooks { @Override public void error(Throwable t) { IJ.handleException(t); } @Override public void initialized() { runInitializer(); } private void runInitializer() { final String property = System.getProperty("ij1.patcher.initializer"); try { final ClassLoader loader = IJ.getClassLoader(); Thread.currentThread().setContextClassLoader(loader); Class runClass; if (property != null) { runClass = loader.loadClass(property); } else { try { runClass = loader.loadClass("net.imagej.legacy.plugin.LegacyInitializer"); } catch (ClassNotFoundException e) { runClass = loader.loadClass("imagej.legacy.plugin.LegacyInitializer"); } } final Runnable run = (Runnable)runClass.newInstance(); run.run(); } catch (ClassNotFoundException e) { // ignore } catch (Throwable t) { t.printStackTrace(); } } /** * Intended for sole use with patches in {@link ij.IJ}. DO NOT USE. */ public static ClassLoader missingSubdirs(final ClassLoader loader, final boolean addPluginsDir) { if (loader == null || !(loader instanceof URLClassLoader)) return null; final URLClassLoader classLoader = (URLClassLoader) loader; final Set directories = new LinkedHashSet<>(); for (final URL url : classLoader.getURLs()) { if (!"file".equals(url.getProtocol())) continue; final File dir = new File(url.getPath()); if (!dir.isDirectory() || isBuildDirectory(dir)) continue; directories.add(dir); } final Set missing = new LinkedHashSet<>(); if (addPluginsDir) { String pluginsDir = IJ.getDirectory("plugins"); if (pluginsDir == null) { pluginsDir = System.getProperty("plugins.dir"); } if (pluginsDir != null) { final File plugins = new File(pluginsDir); if (!directories.contains(plugins)) { directories.add(plugins); missing.add(plugins); } } } try { for (final File dir : directories) { missingSubdirectories(dir, directories, missing); } if (missing.isEmpty()) return null; final URL[] urls = new URL[missing.size()]; int i = 0; for (final File dir : missing) { urls[i++] = dir.toURI().toURL(); } return new URLClassLoader(urls, loader); } catch (Exception e) { e.printStackTrace(); return null; } } /** * Tests whether the given directory is a build directory in a development * environment. E.g., with Maven, class files typically reside in * subdirectories of a directory called {@code target}. */ private static boolean isBuildDirectory(final File dir) { final String[] buildDirs = {"target", "build", "bin"}; return Arrays.asList(buildDirs).contains(dir.getParentFile().getName()); } private static boolean missingSubdirectories(final File dir, final Set already, final Set missing) { boolean containsClassFiles = false; for (final File sub : dir.listFiles()) { if (sub.isDirectory()) { if (already.contains(sub) || missing.contains(sub)) continue; if (missingSubdirectories(sub, already, missing)) try { containsClassFiles = true; missing.add(sub); } catch (Exception e) { if (e instanceof RuntimeException) throw (RuntimeException) e; throw new RuntimeException(e); } } else if (sub.getName().endsWith(".class")) { containsClassFiles = true; } } return containsClassFiles; } /** * Intercepts LegacyInitializer's Context creation. *

* One of the most critical code paths in Fiji * is how its runtime patches get installed. It calls the * {@link LegacyEnvironment}, of course, but the idea is for said environment * to install the essential {@link LegacyHooks} which then give ImageJ's * {@code LegacyService} a chance to spin up all of the legacy patches, * including Fiji's (which are add-ons on top of {@code imagej-legacy}). *

*

* If this critical code path fails, Fiji fails to start up properly. Ideally, * this should never happen, but this is not an ideal world: corrupt * {@code .jar} files and version skews caused by forgotten updates, * locally-modified files or simply by forward-incompatible downstream updates * can break any number of things in that path. So let's bend over another * inch (the existence of the {@code ij1-patcher} speaks volumes about our * learned ability to do so) and try extra hard to keep things working even * under very unfavorable circumstances. *

* * @param className the class name * @param arg the argument passed to the {@code runPlugIn} method * @return the object to return, or null to let ImageJ 1.x handle the call */ @Override public Object interceptRunPlugIn(final String className, final String arg) { if ("org.scijava.Context".equals(className)) { try { final Class contextClass = IJ.getClassLoader().loadClass(className); try { return contextClass.newInstance(); } catch (Throwable t) { // "Something" failed... Darn. t.printStackTrace(); // Try again, with the bare minimum of services: LegacyService and friends Class legacyServiceClass; try { // NB: Old concrete LegacyService class, which no longer exists. legacyServiceClass = IJ.getClassLoader().loadClass( "net.imagej.legacy.DefaultLegacyService"); } catch (Throwable t2) { try { // NB: Current concrete LegacyService class. legacyServiceClass = IJ.getClassLoader().loadClass( "net.imagej.legacy.LegacyService"); } catch (Throwable t3) { // NB: _Really_ old concrete LegacyService class, long gone. legacyServiceClass = IJ.getClassLoader().loadClass( "imagej.legacy.DefaultLegacyService"); } } Constructor ctor = contextClass.getConstructor((Class) Class[].class); return ctor.newInstance((Object) new Class[] { legacyServiceClass }); } } catch (Throwable t) { t.printStackTrace(); System.err.println("Giving up to create a SciJava Context!"); } } return null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy