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

org.scijava.script.ScriptInfo Maven / Gradle / Ivy

Go to download

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 downstream projects in the SciJava ecosystem, such as ImageJ and SCIFIO.

There is a newer version: 2.99.0
Show newest version
/*
 * #%L
 * SciJava Common shared library for SciJava software.
 * %%
 * Copyright (C) 2009 - 2017 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.script;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.scijava.Context;
import org.scijava.Contextual;
import org.scijava.NullContextException;
import org.scijava.log.LogService;
import org.scijava.module.AbstractModuleInfo;
import org.scijava.module.ModuleException;
import org.scijava.module.ModuleItem;
import org.scijava.plugin.Parameter;
import org.scijava.script.process.ParameterScriptProcessor;
import org.scijava.script.process.ScriptCallback;
import org.scijava.script.process.ScriptProcessorService;
import org.scijava.util.DigestUtils;
import org.scijava.util.FileUtils;

/**
 * Metadata about a script.
 * 
 * @author Curtis Rueden
 * @author Johannes Schindelin
 */
public class ScriptInfo extends AbstractModuleInfo implements Contextual {

	private static final int PARAM_CHAR_MAX = 640 * 1024; // should be enough ;-)

	private final URL url;
	private final String path;
	private final String script;

	@Parameter
	private Context context;

	@Parameter
	private LogService log;

	@Parameter
	private ScriptService scriptService;

	@Parameter
	private ScriptProcessorService scriptProcessorService;

	/** Final version of the script, after script processing. */
	private String processedScript;

	/** True iff the return value should be appended as an output. */
	private boolean appendReturnValue;

	/** Script language in which the script should be executed. */
	private ScriptLanguage scriptLanguage;

	/** Routines to be invoked prior to script execution. */
	private ArrayList callbacks;

	/**
	 * Creates a script metadata object which describes the given script file.
	 * 
	 * @param context The SciJava application context to use when populating
	 *          service inputs.
	 * @param file The script file.
	 */
	public ScriptInfo(final Context context, final File file) {
		this(context, null, file.getPath(), null);
	}

	/**
	 * Creates a script metadata object which describes the given script file.
	 * 
	 * @param context The SciJava application context to use when populating
	 *          service inputs.
	 * @param path Path to the script file.
	 */
	public ScriptInfo(final Context context, final String path) {
		this(context, null, path, null);
	}

	/**
	 * Creates a script metadata object which describes a script at the given URL.
	 * 
	 * @param context The SciJava application context to use when populating
	 *          service inputs.
	 * @param url URL which references the script.
	 * @param path Pseudo-path to the script file. This file does not actually
	 *          need to exist, but rather provides a name for the script with file
	 *          extension.
	 */
	public ScriptInfo(final Context context, final URL url, final String path)
		throws IOException
	{
		this(context, url, path, new InputStreamReader(url.openStream()));
	}

	/**
	 * Creates a script metadata object which describes a script provided by the
	 * given {@link Reader}.
	 * 
	 * @param context The SciJava application context to use when populating
	 *          service inputs.
	 * @param path Pseudo-path to the script file. This file does not actually
	 *          need to exist, but rather provides a name for the script with file
	 *          extension.
	 * @param reader Reader which provides the script itself (i.e., its contents).
	 */
	public ScriptInfo(final Context context, final String path,
		final Reader reader)
	{
		this(context, null, path, reader);
	}

	private ScriptInfo(final Context context, final URL url, final String path,
		final Reader reader)
	{
		setContext(context);
		this.url = url(url, path);
		this.path = path(url, path);

		String contents = null;
		if (reader != null) {
			try {
				contents = getReaderContentsAsString(reader);
			}
			catch (final IOException exc) {
				log.error("Error reading script: " + path, exc);
			}
		}
		script = contents;
	}

	// -- ScriptInfo methods --

	/**
	 * Gets the URL of the script.
	 * 

* If the actual source of the script is a URL (provided via * {@link #ScriptInfo(Context, URL, String)}), then this will return it. *

*

* Alternately, if the path (from {@link #getPath()}) is a real file on disk * (provided via {@link #ScriptInfo(Context, File)} or * {@link #ScriptInfo(Context, String)}), then the URL returned here will be a * {@code file://} one reference to it. *

*

* Otherwise, this method will return null. *

*/ public URL getURL() { return url; } /** * Gets the path to the script on disk. *

* If the path doesn't actually exist on disk, then this is a pseudo-path * merely for the purpose of naming the script with a file extension, and the * actual script content is delivered by the {@link BufferedReader} given by * {@link #getReader()}. *

*/ public String getPath() { return path; } /** * Gets a reader which delivers the script's content. *

* This might be null, in which case the content is stored in a file on disk * given by {@link #getPath()}. *

*/ public BufferedReader getReader() { if (script == null) { return null; } return new BufferedReader(new StringReader(script), PARAM_CHAR_MAX); } /** * Gets the script contents after script processing. * * @return The processed script. * @see ScriptProcessorService#process */ public String getProcessedScript() { return processedScript; } /** Gets the scripting language of the script. */ public ScriptLanguage getLanguage() { if (scriptLanguage == null) { // infer the language from the script path's extension final String scriptPath = getPath(); if (scriptPath != null) { // use language associated with the script path extension final String extension = FileUtils.getExtension(scriptPath); scriptLanguage = scriptService.getLanguageByExtension(extension); } else { // use the highest priority language final List langs = scriptService.getLanguages(); if (langs != null && !langs.isEmpty()) scriptLanguage = langs.get(0); } } return scriptLanguage; } /** Overrides the script language to use when executing the script. */ public void setLanguage(final ScriptLanguage scriptLanguage) { this.scriptLanguage = scriptLanguage; } /** Gets whether the return value is appended as an additional output. */ public boolean isReturnValueAppended() { return appendReturnValue; } /** Gets whether the return value is appended as an additional output. */ public void setReturnValueAppended(final boolean appendReturnValue) { this.appendReturnValue = appendReturnValue; } /** * Gets the list of routines which should be invoked each time the script is * about to execute. * * @return Reference to the mutable list of {@link Runnable} objects which the * {@link ScriptModule} will run prior to executing the script itself. */ public List callbacks() { if (callbacks == null) callbacks = new ArrayList<>(); return callbacks; } // -- AbstractModuleInfo methods -- /** * Performs script processing. In particular, parses the script parameters. * * @see ParameterScriptProcessor * @see ScriptProcessorService#process */ // NB: Widened visibility from AbstractModuleInfo. @Override public void parseParameters() { clearParameters(); try { processedScript = scriptProcessorService.process(this); } catch (final IOException exc) { // TODO: Consider a better error handling approach. throw new RuntimeException(exc); } } // NB: Widened visibility from AbstractModuleInfo. @Override public void clearParameters() { super.clearParameters(); } // NB: Widened visibility from AbstractModuleInfo. @Override public void registerInput(final ModuleItem input) { super.registerInput(input); } // NB: Widened visibility from AbstractModuleInfo. @Override public void registerOutput(final ModuleItem output) { super.registerOutput(output); } // -- ModuleInfo methods -- @Override public String getDelegateClassName() { return ScriptModule.class.getName(); } @Override public Class loadDelegateClass() { return ScriptModule.class; } @Override public ScriptModule createModule() throws ModuleException { return new ScriptModule(this); } // -- Contextual methods -- @Override public Context context() { if (context == null) throw new NullContextException(); return context; } @Override public Context getContext() { return context; } @Override public void setContext(final Context context) { context.inject(this); } // -- Identifiable methods -- @Override public String getIdentifier() { return "script:" + (path == null ? "" : path); } // -- Locatable methods -- @Override public String getLocation() { return new File(path).toURI().normalize().toString(); } // -- Versioned methods -- @Override public String getVersion() { final File file = new File(path); if (!file.exists()) return null; // no version for non-existent script try { return DigestUtils.bestHex(FileUtils.readFile(file)); } catch (final IOException exc) { log.error(exc); } final Date lastModified = FileUtils.getModifiedTime(file); final String datestamp = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss").format(lastModified); return datestamp; } // -- Helper methods -- private URL url(final URL u, final String p) { if (u != null) return u; if (p == null) return null; try { return new File(p).toURI().toURL(); } catch (final MalformedURLException exc) { log.debug("Cannot glean URL from path: " + p, exc); return null; } } private String path(final URL u, final String p) { if (p != null) return p; return u == null ? null : u.getPath(); } /** * Read entire contents of a Reader and return as String. * * @param reader {@link Reader} whose contents should be returned as String. * Expected to never be null. * @return contents of reader as String. * @throws IOException If an I/O error occurs * @throws NullPointerException If reader is null */ private static String getReaderContentsAsString(final Reader reader) throws IOException, NullPointerException { final char[] buffer = new char[8192]; final StringBuilder builder = new StringBuilder(); int read; while ((read = reader.read(buffer)) != -1) { builder.append(buffer, 0, read); } return builder.toString(); } // -- Deprecated methods -- /** @deprecated Use {@link #isReturnValueAppended()} instead. */ @Deprecated public boolean isReturnValueDeclared() { return !isReturnValueAppended(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy