Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/classes/apple/applescript/AppleScriptEngine.java
38829 views
/*1* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package apple.applescript;2627import java.io.*;28import java.nio.file.Files;29import java.util.*;30import java.util.Map.Entry;3132import javax.script.*;3334/**35* AppleScriptEngine implements JSR 223 for AppleScript on Mac OS X36*/37public class AppleScriptEngine implements ScriptEngine {38private static native void initNative();3940private static native long createContextFrom(final Object object);41private static native Object createObjectFrom(final long context);42private static native void disposeContext(final long context);4344private static native long evalScript(final String script, long contextptr);45private static native long evalScriptFromURL(final String filename, long contextptr);4647static {48System.loadLibrary("AppleScriptEngine");49initNative();50TRACE("<static-init>");51}5253static void checkSecurity() {54final SecurityManager securityManager = System.getSecurityManager();55if (securityManager != null) securityManager.checkExec("/usr/bin/osascript");56}5758static void TRACE(final String str) {59// System.out.println(AppleScriptEngine.class.getName() + "." + str);60}6162/**63* Accessor for the ScriptEngine's long name variable64* @return the long name of the ScriptEngine65*/66protected static String getEngine() {67TRACE("getEngine()");68return AppleScriptEngineFactory.ENGINE_NAME;69}7071/**72* Accessor for the ScriptEngine's version73* @return the version of the ScriptEngine74*/75protected static String getEngineVersion() {76TRACE("getEngineVersion()");77return AppleScriptEngineFactory.ENGINE_VERSION;78}7980/**81* Accessor for the ScriptEngine's short name82* @return the short name of the ScriptEngine83*/84protected static String getName() {85TRACE("getName()");86return AppleScriptEngineFactory.ENGINE_SHORT_NAME;87}8889/**90* Accessor for the ScriptEngine's supported language name91* @return the language the ScriptEngine supports92*/93protected static String getLanguage() {94TRACE("getLanguage()");95return AppleScriptEngineFactory.LANGUAGE;96}9798/**99* The no argument constructor sets up the object with default members,100* a factory for the engine and a fresh context.101* @see com.apple.applescript.AppleScriptEngine#init()102*/103public AppleScriptEngine() {104TRACE("<ctor>()");105// set our parent factory to be a new factory106factory = AppleScriptEngineFactory.getFactory();107108// set up our noarg bindings109setContext(new SimpleScriptContext());110put(ARGV, "");111112init();113}114115/**116* All AppleScriptEngines share the same ScriptEngineFactory117*/118private final ScriptEngineFactory factory;119120/**121* The local context for the AppleScriptEngine122*/123private ScriptContext context;124125/**126* The constructor taking a factory as an argument sets the parent factory for127* this engine to be the passed factory, and sets up the engine with a fresh context128* @param factory129* @see com.apple.applescript.AppleScriptEngine#init()130*/131public AppleScriptEngine(final ScriptEngineFactory factory) {132// inherit the factory passed to us133this.factory = factory;134135// set up our noarg bindings136setContext(new SimpleScriptContext());137put(ARGV, "");138139init();140}141142/**143* The initializer populates the local context with some useful predefined variables:144* <ul><li><code>javax_script_language_version</code> - the version of AppleScript that the AppleScriptEngine supports.</li>145* <li><code>javax_script_language</code> - "AppleScript" -- the language supported by the AppleScriptEngine.</li>146* <li><code>javax_script_engine</code> - "AppleScriptEngine" -- the name of the ScriptEngine.</li>147* <li><code>javax_script_engine_version</code> - the version of the AppleScriptEngine</li>148* <li><code>javax_script_argv</code> - "" -- AppleScript does not take arguments from the command line</li>149* <li><code>javax_script_filename</code> - "" -- the currently executing filename</li>150* <li><code>javax_script_name</code> - "AppleScriptEngine" -- the short name of the AppleScriptEngine</li>151* <li><code>THREADING</code> - null -- the AppleScriptEngine does not support concurrency, you will have to implement thread-safeness yourself.</li></ul>152*/153private void init() {154TRACE("init()");155// set up our context156/* TODO -- name of current executable? bad java documentation at:157* https://docs.oracle.com/javase/6/docs/api/javax/script/ScriptEngine.html#FILENAME */158put(ScriptEngine.FILENAME, "");159put(ScriptEngine.ENGINE, getEngine());160put(ScriptEngine.ENGINE_VERSION, getEngineVersion());161put(ScriptEngine.NAME, getName());162put(ScriptEngine.LANGUAGE, getLanguage());163put(ScriptEngine.LANGUAGE_VERSION, getLanguageVersion());164165// TODO -- for now, err on the side of caution and say that we are NOT thread-safe166put("THREADING", null);167}168169/**170* Uses the AppleScriptEngine to get the local AppleScript version171* @return the version of AppleScript running on the system172*/173protected String getLanguageVersion() {174TRACE("AppleScriptEngine.getLanguageVersion()");175try {176final Object result = eval("get the version of AppleScript");177if (result instanceof String) return (String)result;178} catch (final ScriptException e) { e.printStackTrace(); }179return "unknown";180}181182/**183* Implementation required by ScriptEngine parent<br />184* Returns the factory parent of this AppleScriptEngine185*/186public ScriptEngineFactory getFactory() {187return factory;188}189190/**191* Implementation required by ScriptEngine parent<br />192* Return the engine's context193* @return this ScriptEngine's context194*/195public ScriptContext getContext() {196return context;197}198199/**200* Implementation required by ScriptEngine parent<br />201* Set a new context for the engine202* @param context the new context to install in the engine203*/204public void setContext(final ScriptContext context) {205this.context = context;206}207208/**209* Implementation required by ScriptEngine parent<br />210* Create and return a new set of simple bindings.211* @return a new and empty set of bindings212*/213public Bindings createBindings() {214return new SimpleBindings();215}216217/**218* Implementation required by ScriptEngine parent<br />219* Return the engines bindings for the context indicated by the argument.220* @param scope contextual scope to return.221* @return the bindings in the engine for the scope indicated by the parameter222*/223public Bindings getBindings(final int scope) {224return context.getBindings(scope);225}226227/**228* Implementation required by ScriptEngine parent<br />229* Sets the bindings for the indicated scope230* @param bindings a set of bindings to assign to the engine231* @param scope the scope that the passed bindings should be assigned to232*/233public void setBindings(final Bindings bindings, final int scope) {234context.setBindings(bindings, scope);235}236237/**238* Implementation required by ScriptEngine parent<br />239* Insert a key and value into the engine's bindings (scope: engine)240* @param key the key of the pair241* @param value the value of the pair242*/243public void put(final String key, final Object value) {244getBindings(ScriptContext.ENGINE_SCOPE).put(key, value);245}246247/**248* Implementation required by ScriptEngine parent<br />249* Get a value from the engine's bindings using a key (scope: engine)250* @param key the key of the pair251* @return the value of the pair252*/253public Object get(final String key) {254return getBindings(ScriptContext.ENGINE_SCOPE).get(key);255}256257/**258* Implementation required by ScriptEngine parent<br />259* Passes the Reader argument, as well as the engine's context to a lower evaluation function.<br />260* Prefers FileReader or BufferedReader wrapping FileReader as argument.261* @param reader a Reader to AppleScript source or compiled AppleScript262* @return an Object corresponding to the return value of the script263* @see com.apple.applescript.AppleScriptEngine#eval(Reader, ScriptContext)264*/265public Object eval(final Reader reader) throws ScriptException {266return eval(reader, getContext());267}268269/**270* Implementation required by ScriptEngine parent<br />271* Uses the passed bindings as the context for executing the passed script.272* @param reader a stream to AppleScript source or compiled AppleScript273* @param bindings a Bindings object representing the contexts to execute inside274* @return the return value of the script275* @see com.apple.applescript.AppleScriptEngine#eval(Reader, ScriptContext)276*/277public Object eval(final Reader reader, final Bindings bindings) throws ScriptException {278final Bindings tmp = getContext().getBindings(ScriptContext.ENGINE_SCOPE);279getContext().setBindings(bindings, ScriptContext.ENGINE_SCOPE);280final Object retval = eval(reader);281getContext().setBindings(tmp, ScriptContext.ENGINE_SCOPE);282return retval;283}284285/**286* Implementation required by ScriptEngine parent<br />287* This function can execute either AppleScript source or compiled AppleScript and functions by writing the288* contents of the Reader to a temporary file and then executing it with the engine's context.289* @param reader290* @param scriptContext291* @return an Object corresponding to the return value of the script292*/293public Object eval(final Reader reader, final ScriptContext context) throws ScriptException {294checkSecurity();295296// write our passed reader to a temporary file297File tmpfile;298FileWriter tmpwrite;299try {300tmpfile = Files.createTempFile("AppleScriptEngine.", ".scpt").toFile();301tmpwrite = new FileWriter(tmpfile);302303// read in our input and write directly to tmpfile304/* TODO -- this may or may not be avoidable for certain Readers,305* if a filename can be grabbed, it would be faster to get that and306* use the underlying file than writing a temp file.307*/308int data;309while ((data = reader.read()) != -1) {310tmpwrite.write(data);311}312tmpwrite.close();313314// set up our context business315final long contextptr = scriptContextToNSDictionary(context);316try {317final long retCtx = evalScriptFromURL("file://" + tmpfile.getCanonicalPath(), contextptr);318Object retVal = (retCtx == 0) ? null : createObjectFrom(retCtx);319disposeContext(retCtx);320return retVal;321} finally {322disposeContext(contextptr);323tmpfile.delete();324}325} catch (final IOException e) {326throw new ScriptException(e);327}328}329330/**331* Implementation required by ScriptEngine parent<br />332* Evaluate an AppleScript script passed as a source string. Using the engine's built in context.333* @param script the string to execute.334* @return an Object representing the return value of the script335* @see com.apple.applescript.AppleScriptEngine#eval(String, ScriptContext)336*/337public Object eval(final String script) throws ScriptException {338return eval(script, getContext());339}340341/**342* Implementation required by ScriptEngine parent<br />343* Evaluate an AppleScript script passed as a source string with a custom ScriptContext.344* @param script the AppleScript source to compile and execute.345* @param scriptContext the context to execute the script under346* @see com.apple.applescript.AppleScriptEngine#eval(String, ScriptContext)347*/348public Object eval(final String script, final Bindings bindings) throws ScriptException {349final Bindings tmp = getContext().getBindings(ScriptContext.ENGINE_SCOPE);350getContext().setBindings(bindings, ScriptContext.ENGINE_SCOPE);351352final Object retval = eval(script);353getContext().setBindings(tmp, ScriptContext.ENGINE_SCOPE);354355return retval;356}357358/**359* Implementation required by ScriptEngine parent360* @param script361* @param scriptContext362*/363public Object eval(final String script, final ScriptContext context) throws ScriptException {364checkSecurity();365final long ctxPtr = scriptContextToNSDictionary(context);366try {367final long retCtx = evalScript(script, ctxPtr);368Object retVal = (retCtx == 0) ? null : createObjectFrom(retCtx);369disposeContext(retCtx);370return retVal;371} finally {372disposeContext(ctxPtr);373}374}375376/**377* Converts a ScriptContext into an NSDictionary378* @param context ScriptContext for the engine379* @return a pointer to an NSDictionary380*/381private long scriptContextToNSDictionary(final ScriptContext context) throws ScriptException {382final Map<String, Object> contextAsMap = new HashMap<String, Object>();383for (final Entry<String, Object> e : context.getBindings(ScriptContext.ENGINE_SCOPE).entrySet()) {384contextAsMap.put(e.getKey().replaceAll("\\.", "_"), e.getValue());385}386return createContextFrom(contextAsMap);387}388}389390391