001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * bstefanescu 011 */ 012package org.nuxeo.ecm.core.event.script; 013 014import java.io.File; 015import java.io.IOException; 016import java.io.Reader; 017import java.net.URI; 018import java.net.URISyntaxException; 019import java.net.URL; 020 021import javax.script.Bindings; 022import javax.script.Compilable; 023import javax.script.CompiledScript; 024import javax.script.ScriptContext; 025import javax.script.ScriptEngine; 026import javax.script.ScriptEngineManager; 027import javax.script.ScriptException; 028import javax.script.SimpleBindings; 029import javax.script.SimpleScriptContext; 030 031import org.nuxeo.common.utils.FileUtils; 032 033/** 034 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 035 */ 036public abstract class Script { 037 038 public static boolean trackChanges = true; 039 040 public static ScriptEngineManager scripting; 041 042 public CompiledScript script; 043 044 public long lastModified = -1; 045 046 public static ScriptEngineManager getScripting() { 047 if (scripting == null) { 048 synchronized (Script.class) { 049 scripting = new ScriptEngineManager(); 050 } 051 } 052 return scripting; 053 } 054 055 public static Script newScript(String location) throws IOException { 056 if (location.indexOf(':') > -1) { 057 return newScript(new URL(location)); 058 } else { 059 return new FileScript(location); 060 } 061 } 062 063 public static Script newScript(URL location) throws IOException { 064 String proto = location.getProtocol(); 065 if (proto.equals("jar")) { 066 String path = location.getPath(); 067 int p = path.indexOf('!'); 068 if (p == -1) { // invalid jar URL .. returns a generic URL script 069 return new URLScript(location); 070 } 071 path = path.substring(0, p); 072 if (path.startsWith("file:")) { 073 URI uri; 074 try { 075 uri = new URI(path); 076 } catch (URISyntaxException e) { 077 throw new IOException(e); 078 } 079 return new JARFileScript(new File(uri), location); 080 } else { // TODO import query string too? 081 return new JARUrlScript(new URL(path), location); 082 } 083 } else if (proto.equals("file")) { 084 URI uri; 085 try { 086 uri = location.toURI(); 087 } catch (URISyntaxException e) { 088 throw new IOException(e); 089 } 090 return new FileScript(new File(uri)); 091 } else { 092 return new URLScript(location); 093 } 094 } 095 096 public static Script newScript(File location) { 097 return new FileScript(location); 098 } 099 100 public abstract Reader getReader() throws IOException; 101 102 public abstract Reader getReaderIfModified() throws IOException; 103 104 public abstract String getExtension(); 105 106 public abstract String getLocation(); 107 108 protected String getExtension(String location) { 109 int p = location.lastIndexOf('.'); 110 if (p > -1) { 111 return location.substring(p + 1); 112 } 113 return null; 114 } 115 116 public Object run(Bindings args) throws ScriptException { 117 if (args == null) { 118 args = new SimpleBindings(); 119 } 120 ScriptContext ctx = new SimpleScriptContext(); 121 ctx.setBindings(args, ScriptContext.ENGINE_SCOPE); 122 Object result = null; 123 if (!trackChanges && script != null) { 124 result = script.eval(ctx); 125 } else { 126 result = getCompiledScript().eval(ctx); 127 } 128 return result; 129 } 130 131 public CompiledScript getCompiledScript() throws ScriptException { 132 try { 133 Reader reader = script == null ? getReader() : getReaderIfModified(); 134 if (reader != null) { 135 script = compile(reader); 136 } 137 return script; 138 } catch (IOException e) { 139 throw new ScriptException(e); 140 } 141 } 142 143 public CompiledScript compile(Reader reader) throws ScriptException { 144 ScriptEngine engine = getScripting().getEngineByExtension(getExtension()); 145 if (engine == null) { 146 throw new ScriptException("Unknown script type: " + getExtension()); 147 } 148 if (engine instanceof Compilable) { 149 Compilable comp = (Compilable) engine; 150 try { 151 try { 152 return comp.compile(reader); 153 } finally { 154 reader.close(); 155 } 156 } catch (IOException e) { 157 throw new ScriptException(e); 158 } 159 } else {// TODO this will read sources twice the fist time - pass 160 // reader? 161 return new FakeCompiledScript(engine, this); 162 } 163 } 164 165}