/* * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * bstefanescu */ package org.nuxeo.ecm.core.event.script; import java.io.File; import java.io.IOException; import java.io.Reader; import java.net.URI; import java.net.URISyntaxException; 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 IOException { if (location.indexOf(':') > -1) { return newScript(new URL(location)); } else { return new FileScript(location); } } public static Script newScript(URL location) throws IOException { 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:")) { URI uri; try { uri = new URI(path); } catch (URISyntaxException e) { throw new IOException(e); } return new JARFileScript(new File(uri), location); } else { // TODO import query string too? return new JARUrlScript(new URL(path), location); } } else if (proto.equals("file")) { URI uri; try { uri = location.toURI(); } catch (URISyntaxException e) { throw new IOException(e); } return new FileScript(new File(uri)); } 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 ScriptException { 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); } } }