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