/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * bstefanescu */ package org.eclipse.ecr.core.event.script; import java.io.File; import java.io.IOException; import java.io.Reader; import java.net.URI; import java.net.URL; import javax.script.Bindings; import javax.script.Compilable; import javax.script.CompiledScript; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import javax.script.SimpleBindings; import javax.script.SimpleScriptContext; import org.nuxeo.common.utils.FileUtils; /** * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> */ public abstract class Script { public static boolean trackChanges = true; public static ScriptEngineManager scripting; public CompiledScript script; public long lastModified = -1; public static ScriptEngineManager getScripting() { if (scripting == null) { synchronized (Script.class) { scripting = new ScriptEngineManager(); } } return scripting; } public static Script newScript(String location) throws Exception { if (location.indexOf(':') > -1) { return newScript(new URL(location)); } else { return new FileScript(location); } } public static Script newScript(URL location) throws Exception { String proto = location.getProtocol(); if (proto.equals("jar")) { String path = location.getPath(); int p = path.indexOf('!'); if (p == -1) { // invalid jar URL .. returns a generic URL script return new URLScript(location); } path = path.substring(0, p); if (path.startsWith("file:")) { return new JARFileScript(new File(new URI(path)), location); } else { // TODO import query string too? return new JARUrlScript(new URL(path), location); } } else if (proto.equals("file")) { return new FileScript(new File(location.toURI())); } else { return new URLScript(location); } } public static Script newScript(File location) { return new FileScript(location); } public abstract Reader getReader() throws IOException; public abstract Reader getReaderIfModified() throws IOException; public abstract String getExtension(); public abstract String getLocation(); protected String getExtension(String location) { int p = location.lastIndexOf('.'); if (p > -1) { return location.substring(p + 1); } return null; } public Object run(Bindings args) throws Exception { if (args == null) { args = new SimpleBindings(); } ScriptContext ctx = new SimpleScriptContext(); ctx.setBindings(args, ScriptContext.ENGINE_SCOPE); Object result = null; if (!trackChanges && script != null) { result = script.eval(ctx); } else { result = getCompiledScript().eval(ctx); } return result; } public CompiledScript getCompiledScript() throws ScriptException { try { Reader reader = script == null ? getReader() : getReaderIfModified(); if (reader != null) { script = compile(reader); } return script; } catch (IOException e) { throw new ScriptException(e); } } public CompiledScript compile(Reader reader) throws ScriptException { ScriptEngine engine = getScripting().getEngineByExtension(getExtension()); if (engine == null) { throw new ScriptException("Unknown script type: " + getExtension()); } if (engine instanceof Compilable) { Compilable comp = (Compilable) engine; try { try { return comp.compile(reader); } finally { reader.close(); } } catch (IOException e) { throw new ScriptException(e); } } else {// TODO this will read sources twice the fist time - pass // reader? return new FakeCompiledScript(engine, this); } } // FIXME: make a proper test and remove. public static void main(String[] args) throws Exception { URL url = new URL( "jar:file:///Users/bstefanescu/work/kits/freemarker-2.3.15/lib/freemarker.jar!/freemarker/version.properties"); System.out.println(">>" + url.getProtocol()); System.out.println(">>" + url.getPath()); System.out.println(">>" + FileUtils.read(url.openStream())); } }