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 038/** 039 * @author <a href="mailto:[email protected]">Bogdan Stefanescu</a> 040 */ 041public abstract class Script { 042 043 protected static volatile ScriptEngineManager scripting; 044 045 protected CompiledScript script; 046 047 public volatile long lastModified = -1; 048 049 public static ScriptEngineManager getScripting() { 050 if (scripting == null) { 051 synchronized (Script.class) { 052 if (scripting == null) { 053 scripting = new ScriptEngineManager(); 054 } 055 } 056 } 057 return scripting; 058 } 059 060 public static Script newScript(String location) throws IOException { 061 if (location.indexOf(':') > -1) { 062 return newScript(new URL(location)); 063 } else { 064 return new FileScript(location); 065 } 066 } 067 068 public static Script newScript(URL location) throws IOException { 069 String proto = location.getProtocol(); 070 if (proto.equals("jar")) { 071 String path = location.getPath(); 072 int p = path.indexOf('!'); 073 if (p == -1) { // invalid jar URL .. returns a generic URL script 074 return new URLScript(location); 075 } 076 path = path.substring(0, p); 077 if (path.startsWith("file:")) { 078 URI uri; 079 try { 080 uri = new URI(path); 081 } catch (URISyntaxException e) { 082 throw new IOException(e); 083 } 084 return new JARFileScript(new File(uri), location); 085 } else { // TODO import query string too? 086 return new JARUrlScript(new URL(path), location); 087 } 088 } else if (proto.equals("file")) { 089 URI uri; 090 try { 091 uri = location.toURI(); 092 } catch (URISyntaxException e) { 093 throw new IOException(e); 094 } 095 return new FileScript(new File(uri)); 096 } else { 097 return new URLScript(location); 098 } 099 } 100 101 public static Script newScript(File location) { 102 return new FileScript(location); 103 } 104 105 public abstract Reader getReader() throws IOException; 106 107 public abstract Reader getReaderIfModified() throws IOException; 108 109 public abstract String getExtension(); 110 111 public abstract String getLocation(); 112 113 protected String getExtension(String location) { 114 int p = location.lastIndexOf('.'); 115 if (p > -1) { 116 return location.substring(p + 1); 117 } 118 return null; 119 } 120 121 public Object run(Bindings args) throws ScriptException { 122 if (args == null) { 123 args = new SimpleBindings(); 124 } 125 ScriptContext ctx = new SimpleScriptContext(); 126 ctx.setBindings(args, ScriptContext.ENGINE_SCOPE); 127 return getCompiledScript().eval(ctx); 128 } 129 130 public CompiledScript getCompiledScript() throws ScriptException { 131 try { 132 try (Reader reader = script == null ? getReader() : getReaderIfModified()) { 133 if (reader != null) { 134 script = compile(reader); 135 } 136 return script; 137 } 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}