changeset 4693:04e69e47d7e3

Contributing the AppleScript javax.script engine <http://java.net/jira/browse/MACOSX_PORT-336>
author swingler@apple.com
date Tue, 30 Aug 2011 11:13:12 -0700
parents 89cfcf516724
children 05637166157b
files make/Makefile make/apple/Makefile make/apple/applescript/Makefile src/macosx/classes/apple/applescript/AppleScriptEngine.java src/macosx/classes/apple/applescript/AppleScriptEngineFactory.java src/macosx/native/apple/applescript/AS_NS_ConversionUtils.h src/macosx/native/apple/applescript/AS_NS_ConversionUtils.m src/macosx/native/apple/applescript/AppleScriptEngine.m src/macosx/native/apple/applescript/AppleScriptExecutionContext.h src/macosx/native/apple/applescript/AppleScriptExecutionContext.m src/macosx/native/apple/applescript/NS_Java_ConversionUtils.h src/macosx/native/apple/applescript/NS_Java_ConversionUtils.m
diffstat 12 files changed, 2135 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/make/Makefile	Mon Aug 29 21:28:34 2011 -0700
+++ b/make/Makefile	Tue Aug 30 11:13:12 2011 -0700
@@ -232,7 +232,7 @@
 
 all build:: sanity-all post-sanity-all
 
-SUBDIRS       = tools java javax sun com
+SUBDIRS       = tools java javax sun apple com
 SUBDIRS_tools = launchers
 SUBDIRS_misc  = org sunw jpda mkdemo mksample
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/apple/Makefile	Tue Aug 30 11:13:12 2011 -0700
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+#
+# Makefile for building com/apple
+#
+
+BUILDDIR = ..
+PRODUCT = sun
+include $(BUILDDIR)/common/Defs.gmk
+
+SUBDIRS = applescript
+
+include $(BUILDDIR)/common/Subdirs.gmk
+
+all build clean clobber::
+	$(SUBDIRS-loop)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/apple/applescript/Makefile	Tue Aug 30 11:13:12 2011 -0700
@@ -0,0 +1,71 @@
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+BUILDDIR = ../..
+PACKAGE = apple.applescript
+LIBRARY = AppleScriptEngine
+PRODUCT = sun
+include $(BUILDDIR)/common/Defs.gmk
+
+
+#
+# Files
+#
+AUTO_FILES_JAVA_DIRS = apple/applescript
+
+FILES_objc = \
+        $(TARGDIR)AppleScriptEngine.m \
+        $(TARGDIR)AppleScriptExecutionContext.m \
+        $(TARGDIR)AS_NS_ConversionUtils.m \
+        $(TARGDIR)NS_Java_ConversionUtils.m
+
+
+FILES_export = \
+	apple/applescript/AppleScriptEngine.java \
+	apple/applescript/AppleScriptEngineFactory.java
+
+#
+# Rules
+#
+include $(BUILDDIR)/common/Mapfile-vers.gmk
+include $(BUILDDIR)/common/Library.gmk
+
+
+#
+# Extra rules
+#
+
+#
+# Add to ambient vpath to get files in a subdirectory
+#
+vpath %.m   $(call NativeSrcDirList,,native/apple/applescript)
+
+CPPFLAGS += \
+	-I$(TEMPDIR)/../../sun.awt/awt/CClassHeaders
+
+OTHER_LDLIBS = \
+    -framework Cocoa \
+    -framework Carbon \
+    -framework JavaNativeFoundation
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/apple/applescript/AppleScriptEngine.java	Tue Aug 30 11:13:12 2011 -0700
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package apple.applescript;
+
+import java.io.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import javax.script.*;
+
+/**
+ * AppleScriptEngine implements JSR 223 for AppleScript on Mac OS X
+ */
+public class AppleScriptEngine implements ScriptEngine {
+    private static native void initNative();
+    
+    private static native long createContextFrom(final Object object);
+    private static native Object createObjectFrom(final long context);
+    private static native void disposeContext(final long context);
+    
+    private static native long evalScript(final String script, long contextptr);
+    private static native long evalScriptFromURL(final String filename, long contextptr);
+    
+    static {
+        System.loadLibrary("AppleScriptEngine");
+        initNative();
+        TRACE("<static-init>");
+    }
+    
+    static void checkSecurity() {
+        final SecurityManager securityManager = System.getSecurityManager();
+        if (securityManager != null) securityManager.checkExec("/usr/bin/osascript");
+    }
+    
+    static void TRACE(final String str) {
+//        System.out.println(AppleScriptEngine.class.getName() + "." + str);
+    }
+    
+    /**
+     * Accessor for the ScriptEngine's long name variable
+     * @return the long name of the ScriptEngine
+     */
+    protected static String getEngine() {
+        TRACE("getEngine()");
+        return AppleScriptEngineFactory.ENGINE_NAME;
+    }
+
+    /**
+     * Accessor for the ScriptEngine's version
+     * @return the version of the ScriptEngine
+     */
+    protected static String getEngineVersion() {
+        TRACE("getEngineVersion()");
+        return AppleScriptEngineFactory.ENGINE_VERSION;
+    }
+
+    /**
+     * Accessor for the ScriptEngine's short name
+     * @return the short name of the ScriptEngine
+     */
+    protected static String getName() {
+        TRACE("getName()");
+        return AppleScriptEngineFactory.ENGINE_SHORT_NAME;
+    }
+
+    /**
+     * Accessor for the ScriptEngine's supported language name
+     * @return the language the ScriptEngine supports
+     */
+    protected static String getLanguage() {
+        TRACE("getLanguage()");
+        return AppleScriptEngineFactory.LANGUAGE;
+    }
+
+    /**
+     * The no argument constructor sets up the object with default members, 
+     * a factory for the engine and a fresh context.
+     * @see com.apple.applescript.AppleScriptEngine#init()
+     */
+    public AppleScriptEngine() {
+        TRACE("<ctor>()");
+        // set our parent factory to be a new factory
+        factory = AppleScriptEngineFactory.getFactory();
+
+        // set up our noarg bindings
+        setContext(new SimpleScriptContext());
+        put(ARGV, "");
+
+        init();
+    }
+    
+    /**
+     * All AppleScriptEngines share the same ScriptEngineFactory
+     */
+    private final ScriptEngineFactory factory;
+
+    /**
+     * The local context for the AppleScriptEngine
+     */
+    private ScriptContext context;
+
+    /**
+     * The constructor taking a factory as an argument sets the parent factory for 
+     * this engine to be the passed factory, and sets up the engine with a fresh context
+     * @param factory
+     * @see com.apple.applescript.AppleScriptEngine#init()
+     */
+    public AppleScriptEngine(final ScriptEngineFactory factory) {
+        // inherit the factory passed to us
+        this.factory = factory;
+
+        // set up our noarg bindings
+        setContext(new SimpleScriptContext());
+        put(ARGV, "");
+
+        init();
+    }
+
+    /**
+     * The initializer populates the local context with some useful predefined variables:
+     * <ul><li><code>javax_script_language_version</code> - the version of AppleScript that the AppleScriptEngine supports.</li>
+     * <li><code>javax_script_language</code> - "AppleScript" -- the language supported by the AppleScriptEngine.</li>
+     * <li><code>javax_script_engine</code> - "AppleScriptEngine" -- the name of the ScriptEngine.</li>
+     * <li><code>javax_script_engine_version</code> - the version of the AppleScriptEngine</li>
+     * <li><code>javax_script_argv</code> - "" -- AppleScript does not take arguments from the command line</li>
+     * <li><code>javax_script_filename</code> - "" -- the currently executing filename</li>
+     * <li><code>javax_script_name</code> - "AppleScriptEngine" -- the short name of the AppleScriptEngine</li>
+     * <li><code>THREADING</code> - null -- the AppleScriptEngine does not support concurrency, you will have to implement thread-safeness yourself.</li></ul>
+     */
+    private void init() {
+        TRACE("init()");
+        // set up our context
+/* TODO -- name of current executable?  bad java documentation at:
+ * http://java.sun.com/javase/6/docs/api/javax/script/ScriptEngine.html#FILENAME */
+        put(ScriptEngine.FILENAME, "");
+        put(ScriptEngine.ENGINE, getEngine());
+        put(ScriptEngine.ENGINE_VERSION, getEngineVersion());
+        put(ScriptEngine.NAME, getName());
+        put(ScriptEngine.LANGUAGE, getLanguage());
+        put(ScriptEngine.LANGUAGE_VERSION, getLanguageVersion());
+
+        // TODO -- for now, err on the side of caution and say that we are NOT thread-safe
+        put("THREADING", null);
+    }
+    
+    /**
+     * Uses the AppleScriptEngine to get the local AppleScript version
+     * @return the version of AppleScript running on the system
+     */
+    protected String getLanguageVersion() {
+        TRACE("AppleScriptEngine.getLanguageVersion()");
+        try {
+            final Object result = eval("get the version of AppleScript");
+            if (result instanceof String) return (String)result;
+        } catch (final ScriptException e) { e.printStackTrace(); }
+        return "unknown";
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Returns the factory parent of this AppleScriptEngine
+     */
+    public ScriptEngineFactory getFactory() {
+        return factory;
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Return the engine's context
+     * @return this ScriptEngine's context
+     */
+    public ScriptContext getContext() {
+        return context;
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Set a new context for the engine
+     * @param context the new context to install in the engine
+     */
+    public void setContext(final ScriptContext context) {
+        this.context = context;
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Create and return a new set of simple bindings.
+     * @return a new and empty set of bindings
+     */
+    public Bindings createBindings() {
+        return new SimpleBindings();
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Return the engines bindings for the context indicated by the argument.
+     * @param scope contextual scope to return.
+     * @return the bindings in the engine for the scope indicated by the parameter
+     */
+    public Bindings getBindings(final int scope) {
+        return context.getBindings(scope);
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Sets the bindings for the indicated scope
+     * @param bindings a set of bindings to assign to the engine
+     * @param scope the scope that the passed bindings should be assigned to
+     */
+    public void setBindings(final Bindings bindings, final int scope) {
+        context.setBindings(bindings, scope);
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Insert a key and value into the engine's bindings (scope: engine)
+     * @param key the key of the pair
+     * @param value the value of the pair
+     */
+    public void put(final String key, final Object value) {
+        getBindings(ScriptContext.ENGINE_SCOPE).put(key, value);
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Get a value from the engine's bindings using a key (scope: engine)
+     * @param key the key of the pair
+     * @return the value of the pair
+     */
+    public Object get(final String key) {
+        return getBindings(ScriptContext.ENGINE_SCOPE).get(key);
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Passes the Reader argument, as well as the engine's context to a lower evaluation function.<br />
+     * Prefers FileReader or BufferedReader wrapping FileReader as argument.
+     * @param reader a Reader to AppleScript source or compiled AppleScript
+     * @return an Object corresponding to the return value of the script
+     * @see com.apple.applescript.AppleScriptEngine#eval(Reader, ScriptContext) 
+     */
+    public Object eval(final Reader reader) throws ScriptException {
+        return eval(reader, getContext());
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Uses the passed bindings as the context for executing the passed script.
+     * @param reader a stream to AppleScript source or compiled AppleScript
+     * @param bindings a Bindings object representing the contexts to execute inside
+     * @return the return value of the script
+     * @see com.apple.applescript.AppleScriptEngine#eval(Reader, ScriptContext)
+     */
+    public Object eval(final Reader reader, final Bindings bindings) throws ScriptException {
+        final Bindings tmp = getContext().getBindings(ScriptContext.ENGINE_SCOPE);
+        getContext().setBindings(bindings, ScriptContext.ENGINE_SCOPE);
+        final Object retval = eval(reader);
+        getContext().setBindings(tmp, ScriptContext.ENGINE_SCOPE);
+        return retval;
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * This function can execute either AppleScript source or compiled AppleScript and functions by writing the 
+     * contents of the Reader to a temporary file and then executing it with the engine's context.
+     * @param reader
+     * @param scriptContext
+     * @return an Object corresponding to the return value of the script
+     */
+    public Object eval(final Reader reader, final ScriptContext context) throws ScriptException {
+        checkSecurity();
+        
+        // write our passed reader to a temporary file
+        File tmpfile;
+        FileWriter tmpwrite;
+        try {
+            tmpfile = File.createTempFile("AppleScriptEngine.", ".scpt");
+            tmpwrite = new FileWriter(tmpfile);
+
+            // read in our input and write directly to tmpfile
+            /* TODO -- this may or may not be avoidable for certain Readers, 
+             * if a filename can be grabbed, it would be faster to get that and 
+             * use the underlying file than writing a temp file. 
+             */
+            int data;
+            while ((data = reader.read()) != -1) {
+                tmpwrite.write(data);
+            }
+            tmpwrite.close();
+            
+            // set up our context business
+            final long contextptr = scriptContextToNSDictionary(context);
+            try {
+                final long retCtx = evalScriptFromURL("file://" + tmpfile.getCanonicalPath(), contextptr);
+                Object retVal = (retCtx == 0) ? null : createObjectFrom(retCtx);
+                disposeContext(retCtx);
+                return retVal;
+            } finally {
+                disposeContext(contextptr);
+                tmpfile.delete();
+            }
+        } catch (final IOException e) {
+            throw new ScriptException(e);
+        }
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Evaluate an AppleScript script passed as a source string. Using the engine's built in context.
+     * @param script the string to execute.
+     * @return an Object representing the return value of the script
+     * @see com.apple.applescript.AppleScriptEngine#eval(String, ScriptContext)
+     */
+    public Object eval(final String script) throws ScriptException {
+        return eval(script, getContext());
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent<br />
+     * Evaluate an AppleScript script passed as a source string with a custom ScriptContext.
+     * @param script the AppleScript source to compile and execute.
+     * @param scriptContext the context to execute the script under
+     * @see com.apple.applescript.AppleScriptEngine#eval(String, ScriptContext)
+     */
+    public Object eval(final String script, final Bindings bindings) throws ScriptException {
+        final Bindings tmp = getContext().getBindings(ScriptContext.ENGINE_SCOPE);
+        getContext().setBindings(bindings, ScriptContext.ENGINE_SCOPE);
+        
+        final Object retval = eval(script);
+        getContext().setBindings(tmp, ScriptContext.ENGINE_SCOPE);
+        
+        return retval;
+    }
+
+    /**
+     * Implementation required by ScriptEngine parent
+     * @param script
+     * @param scriptContext
+     */
+    public Object eval(final String script, final ScriptContext context) throws ScriptException {
+        checkSecurity();
+        final long ctxPtr = scriptContextToNSDictionary(context);
+        try {
+            final long retCtx = evalScript(script, ctxPtr);
+            Object retVal = (retCtx == 0) ? null : createObjectFrom(retCtx);
+            disposeContext(retCtx);
+            return retVal;
+        } finally {
+            disposeContext(ctxPtr);
+        }
+    }
+
+    /**
+     * Converts a ScriptContext into an NSDictionary
+     * @param context ScriptContext for the engine
+     * @return a pointer to an NSDictionary
+     */
+    private long scriptContextToNSDictionary(final ScriptContext context) throws ScriptException {
+        final Map<String, Object> contextAsMap = new HashMap<String, Object>();
+        for (final Entry<String, Object> e : context.getBindings(ScriptContext.ENGINE_SCOPE).entrySet()) {
+            contextAsMap.put(e.getKey().replaceAll("\\.", "_"), e.getValue());
+        }
+        return createContextFrom(contextAsMap);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/apple/applescript/AppleScriptEngineFactory.java	Tue Aug 30 11:13:12 2011 -0700
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package apple.applescript;
+
+import java.security.*;
+import java.util.*;
+import javax.script.*;
+
+public class AppleScriptEngineFactory implements ScriptEngineFactory {
+    private static native void initNative();
+    
+    static {
+        java.awt.Toolkit.getDefaultToolkit();
+        System.loadLibrary("AppleScriptEngine");
+        initNative();
+        TRACE("<static-init>");
+    }
+    
+    static void TRACE(final String str) {
+//        System.out.println(AppleScriptEngineFactory.class.getName() + "." + str);
+    }
+    
+    /**
+     * The name of this ScriptEngine
+     */
+    static final String ENGINE_NAME = "AppleScriptEngine";
+
+    /**
+     * The version of this ScriptEngine
+     */
+    static final String ENGINE_VERSION = "1.1";
+
+    /**
+     * The name of this ScriptEngine (yes, again)
+     */
+    static final String ENGINE_SHORT_NAME = ENGINE_NAME;
+
+    /**
+     * The name of the language supported by this ScriptEngine 
+     */
+    static final String LANGUAGE = "AppleScript";
+    
+    static ScriptEngineFactory getFactory() {
+        TRACE("getFactory()");
+        return new AppleScriptEngineFactory();
+    }
+
+    /**
+     * Initialize a new AppleScriptEngineFactory, replete with a member AppleScriptEngine
+     */
+    public AppleScriptEngineFactory() { 
+        TRACE("<ctor>()");
+    }
+
+    /**
+     * Returns the full name of the ScriptEngine.
+     * 
+     * @return full name of the ScriptEngine
+     */
+    public String getEngineName() {
+        TRACE("getEngineName()");
+        return ENGINE_NAME;
+    }
+
+    /**
+     * Returns the version of the ScriptEngine.
+     * 
+     * @return version of the ScriptEngine
+     */
+    public String getEngineVersion() {
+        TRACE("getEngineVersion()");
+        return ENGINE_VERSION;
+    }
+    
+    /**
+     * Returns the name of the scripting language supported by this ScriptEngine.
+     * 
+     * @return name of the language supported by the ScriptEngine(Factory)
+     */
+    public String getLanguageName() {
+        TRACE("getLanguageName()");
+        return LANGUAGE;
+    }
+    
+    /**
+     * Returns the version of the scripting language supported by this ScriptEngine(Factory).
+     * 
+     * @return language version supported by the ScriptEngine(Factory)
+     */
+    public String getLanguageVersion() {
+        TRACE("getLanguageVersion()");
+        return AccessController.doPrivileged(new PrivilegedAction<String>() {
+            public String run() {
+                final AppleScriptEngine engine = new AppleScriptEngine(AppleScriptEngineFactory.this);
+                return engine.getLanguageVersion();
+            }
+        });
+    }
+    
+    /**
+     * Returns an immutable list of filename extensions, which generally identify 
+     * scripts written in the language supported by this ScriptEngine.
+     * 
+     * @return ArrayList of file extensions AppleScript associates with
+     */
+    public List<String> getExtensions() {
+        TRACE("getExtensions()");
+        return Arrays.asList("scpt", "applescript", "app");
+    }
+
+    /**
+     * Returns an immutable list of mimetypes, associated with scripts 
+     * that can be executed by the engine.
+     * 
+     * @return ArrayList of mimetypes that AppleScript associates with
+     */
+    public List<String> getMimeTypes() {
+        TRACE("getMimeTypes()");
+        return Arrays.asList("application/x-applescript", "text/plain", "text/applescript");
+    }
+
+    /**
+     * Returns an immutable list of short names for the ScriptEngine, 
+     * which may be used to identify the ScriptEngine by the ScriptEngineManager.
+     * 
+     * @return
+     */
+    public List<String> getNames() {
+        TRACE("getNames()");
+        return Arrays.asList("AppleScriptEngine", "AppleScript", "OSA");
+    }
+
+    /**
+     * Returns a String which can be used to invoke a method of a Java 
+     * object using the syntax of the supported scripting language.
+     * 
+     * @param obj
+     *            unused -- AppleScript does not support objects
+     * @param m
+     *            function name
+     * @param args
+     *            arguments to the function
+     * @return the AppleScript string calling the method
+     */
+    public String getMethodCallSyntax(final String obj, final String fname, final String ... args) {
+//        StringBuilder builder = new StringBuilder();
+//        builder.append("my " + fname + "(");
+//        // TODO -- do
+//        builder.append(")\n");
+//        return builder.toString();
+        
+        return null;
+    }
+
+    /**
+     * Returns a String that can be used as a statement to display the specified String using the syntax of the supported scripting language.
+     * 
+     * @param toDisplay
+     * @return
+     */
+    public String getOutputStatement(final String toDisplay) {
+        // TODO -- this might even be good enough? XD
+        return getMethodCallSyntax(null, "print", toDisplay);
+    }
+
+    /**
+     * Returns the value of an attribute whose meaning may be implementation-specific.
+     * 
+     * @param key
+     *            the key to look up
+     * @return the static preseeded value for the key in the ScriptEngine, if it exists, otherwise <code>null</code>
+     */
+    public Object getParameter(final String key) {
+        final AppleScriptEngine engine = new AppleScriptEngine(this);
+        if (!engine.getBindings(ScriptContext.ENGINE_SCOPE).containsKey(key)) return null;
+        return engine.getBindings(ScriptContext.ENGINE_SCOPE).get(key);
+    }
+
+    /**
+     * Returns A valid scripting language executable program with given statements.
+     * 
+     * @param statements
+     * @return
+     */
+    public String getProgram(final String ... statements) {
+        final StringBuilder program = new StringBuilder();
+        for (final String statement : statements) {
+            program.append(statement + "\n");
+        }
+        return program.toString();
+    }
+
+    /**
+     * Returns an instance of the ScriptEngine associated with this ScriptEngineFactory.
+     * 
+     * @return new AppleScriptEngine with this factory as it's parent
+     */
+    public ScriptEngine getScriptEngine() {
+        AppleScriptEngine.checkSecurity();
+        return new AppleScriptEngine(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/apple/applescript/AS_NS_ConversionUtils.h	Tue Aug 30 11:13:12 2011 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import <Foundation/Foundation.h>
+
+
+// A 'collection' (responds to -objectEnumerator) is translated to an AS list.
+// For any other object obj, this returns [[obj description] aeDescriptorValue], mainly
+// intended for debugging purposes.
+@interface NSObject (JavaAppleScriptEngineAdditions)
+- (NSAppleEventDescriptor *) aeDescriptorValue;
+@end
+
+@interface NSAppleEventDescriptor (JavaAppleScriptEngineAdditions)
+- (id) objCObjectValue;
+@end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/apple/applescript/AS_NS_ConversionUtils.m	Tue Aug 30 11:13:12 2011 -0700
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//
+//    Most of this is adapted from Ken Ferry's KFAppleScript Additions, contributed with permission
+//    http://homepage.mac.com/kenferry/software.html
+//
+
+#import "AS_NS_ConversionUtils.h"
+
+#import <Cocoa/Cocoa.h>
+#import <Carbon/Carbon.h>
+
+
+@interface NSAppleEventDescriptor (JavaAppleScriptEngineAdditionsPrivate)
+
+// just returns self.  This means that you can pass custom descriptors
+// to -[NSAppleScript executeHandler:error:withParameters:].  
+- (NSAppleEventDescriptor *)aeDescriptorValue;
+
+// working with primitive descriptor types
++ (id)descriptorWithInt16:(SInt16)val;
+- (SInt16)int16Value;
++ (id)descriptorWithUnsignedInt32:(UInt32)val;
+- (UInt32)unsignedInt32Value;
++ (id)descriptorWithFloat32:(Float32)val;
+- (Float32)float32Value;
++ (id)descriptorWithFloat64:(Float64)val;
+- (Float64)float64Value;
++ (id)descriptorWithLongDateTime:(LongDateTime)val;
+- (LongDateTime)longDateTimeValue;
+
+
+// These are the methods for converting AS objects to objective-C objects.  
+// -[NSAppleEventDescriptor objCObjectValue] is the general method for converting
+// AS objects to ObjC objects, and is called by -[NSAppleScript executeHandler:error:withParameters:].
+// It does no work itself.  It finds a handler based on the type of the descriptor and lets that
+// handler object do the work.  If there is no handler type registered for a the type of a descriptor, 
+// the raw descriptor is returned.
+//
+// You can designate a handlers for descriptor types with 
+// +[NSAppleEventDescriptor registerConversionHandler:selector:forDescriptorTypes:].  Please note
+// that this method does _not_ retain the handler object (for now anyway).  The selector should
+// take a single argument, a descriptor to translate, and should return an object.  An example such 
+// selector is @selector(dictionaryWithAEDesc:), for which the handler object would be [NSDictionary class].
+// 
+// A number of handlers are designated by default.  The methods and objects can be easily inferred (or check 
+// the implementation), but the automatically handled types are
+//    typeUnicodeText,
+//    typeText,
+//    typeUTF8Text, 
+//    typeCString,
+//    typeChar,
+//    typeBoolean,
+//    typeTrue,
+//    typeFalse,
+//    typeSInt16, 
+//    typeSInt32,
+//    typeUInt32,
+//    typeSInt64,
+//    typeIEEE32BitFloatingPoint,
+//    typeIEEE64BitFloatingPoint,
+//    type128BitFloatingPoint,
+//    typeAEList,
+//    typeAERecord,
+//    typeLongDateTime,
+//    typeNull.
++ (void)registerConversionHandler:(id)anObject selector:(SEL)aSelector forDescriptorTypes:(DescType)firstType, ...;
++ (void) jaseSetUpHandlerDict;
+@end
+
+// wrap the NSAppleEventDescriptor string methods
+@interface NSString (JavaAppleScriptEngineAdditions)
+- (NSAppleEventDescriptor *)aeDescriptorValue;
++ (NSString *)stringWithAEDesc:(NSAppleEventDescriptor *)desc;
+@end
+
+// wrap the NSAppleEventDescriptor longDateTime methods
+@interface NSDate (JavaAppleScriptEngineAdditions)
+- (NSAppleEventDescriptor *)aeDescriptorValue;
++ (NSDate *)dateWithAEDesc:(NSAppleEventDescriptor *)desc;
+@end
+
+// these are fairly complicated methods, due to having to try to match up the various
+// AS number types (see NSAppleEventDescriptor for the primitive number methods) 
+// with NSNumber variants.  For complete behavior it's best to look at the implementation.
+// Some notes:
+//    NSNumbers created with numberWithBool should be correctly translated to AS booleans and vice versa.
+//    NSNumbers created with large integer types may have to be translated to AS doubles,
+//      so be careful if checking equality (you may have to check equality within epsilon).
+//    Since NSNumbers can't remember if they were created with an unsigned value, 
+//      [[NSNumber numberWithUnsignedChar:255] aeDescriptorValue] is going to get you an AS integer
+//      with value -1.  If you really need a descriptor with an unsigned value, you'll need to do it
+//      manually using the primitive methods on NSAppleEventDescriptor.  The resulting descriptor
+//      can still be passed to AS with -[NSAppleScript executeHandler:error:withParameters:].
+@interface NSNumber (JavaAppleScriptEngineAdditions)
+- (NSAppleEventDescriptor *)aeDescriptorValue;
++ (id)numberWithAEDesc:(NSAppleEventDescriptor *)desc;
+@end
+
+// Here we're following the behavior described in the CocoaScripting release note.
+//
+// NSPoint -> list of two numbers: {x, y}
+// NSRange -> list of two numbers: {begin offset, end offset}
+// NSRect  -> list of four numbers: {left, bottom, right, top}
+// NSSize  -> list of two numbers: {width, height}
+@interface NSValue (JavaAppleScriptEngineAdditions)
+- (NSAppleEventDescriptor *)aeDescriptorValue;
+@end
+
+// No need for ObjC -> AS conversion here, we fall through to NSObject as a collection.
+// For AS -> ObjC conversion, we build an array using the primitive list methods on
+// NSAppleEventDescriptor.
+@interface NSArray (JavaAppleScriptEngineAdditions)
++ (NSArray *)arrayWithAEDesc:(NSAppleEventDescriptor *)desc;
+@end
+
+
+// Please see the CocoaScripting release note for behavior.  It's kind of complicated.
+// 
+// methods wrap the primitive record methods on NSAppleEventDescriptor.  
+@interface NSDictionary (JavaAppleScriptEngineAdditions)
+- (NSAppleEventDescriptor *)aeDescriptorValue;
++ (NSDictionary *)dictionaryWithAEDesc:(NSAppleEventDescriptor *)desc;
+@end
+
+// be aware that a null descriptor does not correspond to the 'null' keyword in 
+// AppleScript - it's more like nothing at all.  For example, the return
+// from an empty handler.
+@interface NSNull (JavaAppleScriptEngineAdditions)
+- (NSAppleEventDescriptor *)aeDescriptorValue;
++ (NSNull *)nullWithAEDesc:(NSAppleEventDescriptor *)desc;
+@end
+
+
+@interface NSNumber (JavaAppleScriptEngineAdditionsPrivate)
++ (id) jaseNumberWithSignedIntP:(void *)int_p byteCount:(int)bytes;
++ (id) jaseNumberWithUnsignedIntP:(void *)int_p byteCount:(int)bytes;
++ (id) jaseNumberWithFloatP:(void *)float_p byteCount:(int)bytes;
+@end
+
+
+@implementation NSObject (JavaAppleScriptEngineAdditions)
+
+- (NSAppleEventDescriptor *)aeDescriptorValue {
+    // collections go to lists
+    if (![self respondsToSelector:@selector(objectEnumerator)]) {
+        // encode the description as a fallback - this is pretty useless, only helpful for debugging
+        return [[self description] aeDescriptorValue];
+    }
+    
+    NSAppleEventDescriptor *resultDesc = [NSAppleEventDescriptor listDescriptor];
+    NSEnumerator *objectEnumerator = [(id)self objectEnumerator];
+    
+    unsigned int i = 1; // apple event descriptors are 1-indexed
+    id currentObject;
+    while((currentObject = [objectEnumerator nextObject]) != nil) {
+        [resultDesc insertDescriptor:[currentObject aeDescriptorValue] atIndex:i++];
+    }
+    
+    return resultDesc;
+}
+
+@end
+
+
+@implementation NSArray (JavaAppleScriptEngineAdditions)
+
+// don't need to override aeDescriptorValue, the NSObject will treat the array as a collection
++ (NSArray *)arrayWithAEDesc:(NSAppleEventDescriptor *)desc {
+    NSAppleEventDescriptor *listDesc = [desc coerceToDescriptorType:typeAEList];
+    NSMutableArray *resultArray = [NSMutableArray array];
+    
+    // apple event descriptors are 1-indexed
+    unsigned int listCount = [listDesc numberOfItems];
+    unsigned int i;
+    for (i = 1; i <= listCount; i++) {
+        [resultArray addObject:[[listDesc descriptorAtIndex:i] objCObjectValue]];
+    }
+    
+    return resultArray;
+}
+
+@end
+
+
+@implementation NSDictionary (JavaAppleScriptEngineAdditions)
+
+- (NSAppleEventDescriptor *)aeDescriptorValue {
+    NSAppleEventDescriptor *resultDesc = [NSAppleEventDescriptor recordDescriptor];
+    NSMutableArray *userFields = [NSMutableArray array];
+    NSArray *keys = [self allKeys];
+    
+    unsigned int keyCount = [keys count];
+    unsigned int i;
+    for (i = 0; i < keyCount; i++) {
+        id key = [keys objectAtIndex:i];
+        
+        if ([key isKindOfClass:[NSNumber class]]) {
+            [resultDesc setDescriptor:[[self objectForKey:key] aeDescriptorValue] forKeyword:[(NSNumber *)key intValue]];
+        } else if ([key isKindOfClass:[NSString class]]) {
+            [userFields addObject:key];
+            [userFields addObject:[self objectForKey:key]];
+        }
+    }
+    
+    if ([userFields count] > 0) {
+        [resultDesc setDescriptor:[userFields aeDescriptorValue] forKeyword:keyASUserRecordFields];
+    }
+    
+    return resultDesc;
+}
+
++ (NSDictionary *)dictionaryWithAEDesc:(NSAppleEventDescriptor *)desc {
+    NSAppleEventDescriptor *recDescriptor = [desc coerceToDescriptorType:typeAERecord];
+    NSMutableDictionary *resultDict = [NSMutableDictionary dictionary];
+    
+    // NSAppleEventDescriptor uses 1 indexing
+    unsigned int recordCount = [recDescriptor numberOfItems];
+    unsigned int recordIndex;
+    for (recordIndex = 1; recordIndex <= recordCount; recordIndex++) {
+        AEKeyword keyword = [recDescriptor keywordForDescriptorAtIndex:recordIndex];
+        
+        if(keyword == keyASUserRecordFields) {
+            NSAppleEventDescriptor *listDescriptor = [recDescriptor descriptorAtIndex:recordIndex];
+            
+            // NSAppleEventDescriptor uses 1 indexing
+            unsigned int listCount = [listDescriptor numberOfItems];
+            unsigned int listIndex;
+            for (listIndex = 1; listIndex <= listCount; listIndex += 2) {
+                id keyObj = [[listDescriptor descriptorAtIndex:listIndex] objCObjectValue];
+                id valObj = [[listDescriptor descriptorAtIndex:listIndex+1] objCObjectValue];
+                
+                [resultDict setObject:valObj forKey:keyObj];
+            }
+        } else {
+            id keyObj = [NSNumber numberWithInt:keyword];
+            id valObj = [[recDescriptor descriptorAtIndex:recordIndex] objCObjectValue];
+            
+            [resultDict setObject:valObj forKey:keyObj];
+        }
+    }
+    
+    return resultDict;
+}
+
+@end
+
+
+@implementation NSString (JavaAppleScriptEngineAdditions)
+
+- (NSAppleEventDescriptor *)aeDescriptorValue {
+    return [NSAppleEventDescriptor descriptorWithString:self];
+}
+
++ (NSString *)stringWithAEDesc:(NSAppleEventDescriptor *)desc {
+    return [desc stringValue];
+}
+
++ (NSString *)versionWithAEDesc:(NSAppleEventDescriptor *)desc {
+    const AEDesc *aeDesc = [desc aeDesc];
+    VersRec v;
+    AEGetDescData(aeDesc, &v, sizeof(v));
+    return [[[NSString alloc] initWithBytes:&v.shortVersion[1] length:StrLength(v.shortVersion) encoding:NSUTF8StringEncoding] autorelease];
+}
+
+@end
+
+
+@implementation NSNull (JavaAppleScriptEngineAdditions)
+
+- (NSAppleEventDescriptor *)aeDescriptorValue {
+    return [NSAppleEventDescriptor nullDescriptor];
+}
+
++ (NSNull *)nullWithAEDesc:(NSAppleEventDescriptor *)desc {
+    return [NSNull null];
+}
+
+@end
+
+
+@implementation NSDate (JavaAppleScriptEngineAdditions)
+
+- (NSAppleEventDescriptor *)aeDescriptorValue {
+    LongDateTime ldt;
+    UCConvertCFAbsoluteTimeToLongDateTime(CFDateGetAbsoluteTime((CFDateRef)self), &ldt);
+    return [NSAppleEventDescriptor descriptorWithLongDateTime:ldt];
+}
+
++ (NSDate *)dateWithAEDesc:(NSAppleEventDescriptor *)desc {
+    CFAbsoluteTime absTime;
+    UCConvertLongDateTimeToCFAbsoluteTime([desc longDateTimeValue], &absTime);
+    NSDate *resultDate = (NSDate *)CFDateCreate(NULL, absTime);
+    return [resultDate autorelease];
+}
+
+@end
+
+
+
+static inline int areEqualEncodings(const char *enc1, const char *enc2) {
+    return (strcmp(enc1, enc2) == 0);
+}
+
+@implementation NSNumber (JavaAppleScriptEngineAdditions)
+
+-(id)jaseDescriptorValueWithFloatP:(void *)float_p byteCount:(int)bytes {
+    float floatVal;
+    if (bytes < sizeof(Float32)) {
+        floatVal = [self floatValue];
+        float_p = &floatVal;
+        bytes = sizeof(floatVal);
+    }
+    
+    double doubleVal;
+    if (bytes > sizeof(Float64)) {
+        doubleVal = [self doubleValue];
+        float_p = &doubleVal;
+        bytes = sizeof(doubleVal);
+    }
+    
+    if (bytes == sizeof(Float32)) {
+        return [NSAppleEventDescriptor descriptorWithFloat32:*(Float32 *)float_p];
+    }
+    
+    if (bytes == sizeof(Float64)) {
+        return [NSAppleEventDescriptor descriptorWithFloat64:*(Float64 *)float_p];
+    }
+    
+    [NSException raise:NSInvalidArgumentException
+                format:@"Cannot create an NSAppleEventDescriptor for float with %d bytes of data.",  bytes];
+    
+    return nil;
+}
+
+-(id)jaseDescriptorValueWithSignedIntP:(void *)int_p byteCount:(int)bytes {
+    int intVal;
+    
+    if (bytes < sizeof(SInt16)) {
+        intVal = [self intValue];
+        int_p = &intVal;
+        bytes = sizeof(intVal);
+    }
+    
+    if (bytes == sizeof(SInt16)) {
+        return [NSAppleEventDescriptor descriptorWithInt16:*(SInt16 *)int_p];
+    }
+    
+    if (bytes == sizeof(SInt32)) {
+        return [NSAppleEventDescriptor descriptorWithInt32:*(SInt32 *)int_p];
+    }
+    
+    double val = [self doubleValue];
+    return [self jaseDescriptorValueWithFloatP:&val byteCount:sizeof(val)];
+}
+
+-(id)jaseDescriptorValueWithUnsignedIntP:(void *)int_p byteCount:(int)bytes {
+    unsigned int uIntVal;
+    
+    if (bytes < sizeof(UInt32)) {
+        uIntVal = [self unsignedIntValue];
+        int_p = &uIntVal;
+        bytes = sizeof(uIntVal);
+    }
+    
+    if (bytes == sizeof(UInt32)) {
+        return [NSAppleEventDescriptor descriptorWithUnsignedInt32:*(UInt32 *)int_p];
+    }
+    
+    double val = (double)[self unsignedLongLongValue];
+    return [self jaseDescriptorValueWithFloatP:&val byteCount:sizeof(val)];
+}
+
+- (NSAppleEventDescriptor *)aeDescriptorValue {
+    // NSNumber is unfortunately complicated, because the applescript 
+    // type we should use depends on the c type that our NSNumber corresponds to
+    
+    const char *type = [self objCType];
+    
+    // convert
+    if (areEqualEncodings(type, @encode(BOOL))) {
+        return [NSAppleEventDescriptor descriptorWithBoolean:[self boolValue]];
+    }
+    
+    if (areEqualEncodings(type, @encode(char))) {
+        char val = [self charValue];
+        return [self jaseDescriptorValueWithSignedIntP:&val byteCount:sizeof(val)];
+    }    
+    
+    if (areEqualEncodings(type, @encode(short))) {
+        short val = [self shortValue];
+        return [self jaseDescriptorValueWithSignedIntP:&val byteCount:sizeof(val)];
+    }        
+    
+    if (areEqualEncodings(type, @encode(int))) {
+        int val = [self intValue];
+        return [self jaseDescriptorValueWithSignedIntP:&val byteCount:sizeof(val)];
+    }  
+    
+    if (areEqualEncodings(type, @encode(long))) {
+        long val = [self longValue];
+        return [self jaseDescriptorValueWithSignedIntP:&val byteCount:sizeof(val)];
+    }
+    
+    if (areEqualEncodings(type, @encode(long long))) {
+        long long val = [self longLongValue];
+        return [self jaseDescriptorValueWithSignedIntP:&val byteCount:sizeof(val)];
+    }
+    
+    if (areEqualEncodings(type, @encode(unsigned char))) {
+        unsigned char val = [self unsignedCharValue];
+        return [self jaseDescriptorValueWithUnsignedIntP:&val byteCount:sizeof(val)];
+    }
+    
+    if (areEqualEncodings(type, @encode(unsigned short))) {
+        unsigned short val = [self unsignedShortValue];
+        return [self jaseDescriptorValueWithUnsignedIntP:&val byteCount:sizeof(val)];
+    }
+    
+    if (areEqualEncodings(type, @encode(unsigned int))) {
+        unsigned int val = [self unsignedIntValue];
+        return [self jaseDescriptorValueWithUnsignedIntP:&val byteCount:sizeof(val)];
+    }
+    
+    if (areEqualEncodings(type, @encode(unsigned long))) {
+        unsigned long val = [self unsignedLongValue];
+        return [self jaseDescriptorValueWithUnsignedIntP:&val byteCount:sizeof(val)];
+    }
+    
+    if (areEqualEncodings(type, @encode(unsigned long long))) {
+        unsigned long long val = [self unsignedLongLongValue];
+        return [self jaseDescriptorValueWithUnsignedIntP:&val byteCount:sizeof(val)];
+    }
+    
+    if (areEqualEncodings(type, @encode(float))) {
+        float val = [self floatValue];
+        return [self jaseDescriptorValueWithFloatP:&val byteCount:sizeof(val)];
+    }
+    
+    if (areEqualEncodings(type, @encode(double))) {
+        double val = [self doubleValue];
+        return [self jaseDescriptorValueWithFloatP:&val byteCount:sizeof(val)];
+    }
+    
+    [NSException raise:@"jaseUnsupportedAEDescriptorConversion"
+                format:@"JavaAppleScriptEngineAdditions: conversion of an NSNumber with objCType '%s' to an aeDescriptor is not supported.", type];
+    
+    return nil;
+}
+
++ (id)numberWithAEDesc:(NSAppleEventDescriptor *)desc {
+    DescType type = [desc descriptorType];
+    
+    if ((type == typeTrue) || (type == typeFalse) || (type == typeBoolean)) {
+        return [NSNumber numberWithBool:[desc booleanValue]];
+    }
+    
+    if (type == typeSInt16) {
+        SInt16 val = [desc int16Value];
+        return [NSNumber jaseNumberWithSignedIntP:&val byteCount:sizeof(val)];
+    }
+    
+    if (type == typeSInt32) {
+        SInt32 val = [desc int32Value];
+        return [NSNumber jaseNumberWithSignedIntP:&val byteCount:sizeof(val)];
+    }
+    
+    if (type == typeUInt32) {
+        UInt32 val = [desc unsignedInt32Value];
+        return [NSNumber jaseNumberWithUnsignedIntP:&val byteCount:sizeof(val)];
+    }
+    
+    if (type == typeIEEE32BitFloatingPoint) {
+        Float32 val = [desc float32Value];
+        return [NSNumber jaseNumberWithFloatP:&val byteCount:sizeof(val)];
+    }
+    
+    if (type == typeIEEE64BitFloatingPoint) {
+        Float64 val = [desc float64Value];
+        return [NSNumber jaseNumberWithFloatP:&val byteCount:sizeof(val)];
+    }
+   
+    // try to coerce to 64bit floating point
+    desc = [desc coerceToDescriptorType:typeIEEE64BitFloatingPoint];
+    if (desc != nil) {
+        Float64 val = [desc float64Value];
+        return [NSNumber jaseNumberWithFloatP:&val byteCount:sizeof(val)];
+    }
+    
+    [NSException raise:@"jaseUnsupportedAEDescriptorConversion"
+                format:@"JavaAppleScriptEngineAdditions: conversion of an NSAppleEventDescriptor with objCType '%s' to an aeDescriptor is not supported.", type];
+    
+    return nil;
+}
+
++ (id) jaseNumberWithSignedIntP:(void *)int_p byteCount:(int)bytes {
+    if (bytes == sizeof(char)) {
+        return [NSNumber numberWithChar:*(char *)int_p];
+    }
+    
+    if (bytes == sizeof(short)) {
+        return [NSNumber numberWithShort:*(short *)int_p];
+    }
+    
+    if (bytes == sizeof(int)) {
+        return [NSNumber numberWithInt:*(int *)int_p];
+    }
+    
+    if (bytes == sizeof(long)) {
+        return [NSNumber numberWithLong:*(long *)int_p];
+    }
+    
+    if (bytes == sizeof(long long)) {
+        return [NSNumber numberWithLongLong:*(long long *)int_p];
+    }
+    
+    [NSException raise:NSInvalidArgumentException
+                format:@"NSNumber jaseNumberWithSignedIntP:byteCount: number with %i bytes not supported.", bytes];
+    
+    return nil;
+}
+
++ (id) jaseNumberWithUnsignedIntP:(void *)int_p byteCount:(int)bytes {
+    if (bytes == sizeof(unsigned char)) {
+        return [NSNumber numberWithUnsignedChar:*(unsigned char *)int_p];
+    }
+    
+    if (bytes == sizeof(unsigned short)) {
+        return [NSNumber numberWithUnsignedShort:*(unsigned short *)int_p];
+    }
+    
+    if (bytes == sizeof(unsigned int)) {
+        return [NSNumber numberWithUnsignedInt:*(unsigned int *)int_p];
+    }
+    
+    if (bytes == sizeof(unsigned long)) {
+        return [NSNumber numberWithUnsignedLong:*(unsigned long *)int_p];
+    }
+    
+    if (bytes == sizeof(unsigned long long)) {
+        return [NSNumber numberWithUnsignedLongLong:*(unsigned long long *)int_p];
+    }   
+    
+    [NSException raise:NSInvalidArgumentException 
+                format:@"NSNumber numberWithUnsignedInt:byteCount: number with %i bytes not supported.", bytes];
+    
+    return nil;
+}
+
++ (id) jaseNumberWithFloatP:(void *)float_p byteCount:(int)bytes {
+    if (bytes == sizeof(float)) {
+        return [NSNumber numberWithFloat:*(float *)float_p];
+    }
+    
+    if (bytes == sizeof(double)) {
+        return [NSNumber numberWithFloat:*(double *)float_p];
+    }
+    
+    [NSException raise:NSInvalidArgumentException 
+                format:@"NSNumber numberWithFloat:byteCount: floating point number with %i bytes not supported.", bytes];
+    
+    return nil;
+}    
+
+@end
+
+@implementation NSValue (JavaAppleScriptEngineAdditions)
+
+- (NSAppleEventDescriptor *)aeDescriptorValue {
+    const char *type = [self objCType];
+    
+    if (areEqualEncodings(type, @encode(NSSize))) {
+        NSSize size = [self sizeValue];
+        return [[NSArray arrayWithObjects:
+                 [NSNumber numberWithFloat:size.width],
+                 [NSNumber numberWithFloat:size.height], nil] aeDescriptorValue];
+    }
+    
+    if (areEqualEncodings(type, @encode(NSPoint))) {
+        NSPoint point = [self pointValue];
+        return [[NSArray arrayWithObjects:
+                 [NSNumber numberWithFloat:point.x],
+                 [NSNumber numberWithFloat:point.y], nil] aeDescriptorValue];
+    }    
+    
+    if (areEqualEncodings(type, @encode(NSRange))) {
+        NSRange range = [self rangeValue];
+        return [[NSArray arrayWithObjects:
+                 [NSNumber numberWithUnsignedInt:range.location],
+                 [NSNumber numberWithUnsignedInt:range.location + range.length], nil] aeDescriptorValue];
+    }        
+    
+    if (areEqualEncodings(type, @encode(NSRect))) {
+        NSRect rect = [self rectValue];
+        return [[NSArray arrayWithObjects:
+                 [NSNumber numberWithFloat:rect.origin.x],
+                 [NSNumber numberWithFloat:rect.origin.y],
+                 [NSNumber numberWithFloat:rect.origin.x + rect.size.width],
+                 [NSNumber numberWithFloat:rect.origin.y + rect.size.height], nil] aeDescriptorValue];
+    }
+    
+    [NSException raise:@"jaseUnsupportedAEDescriptorConversion"
+                format:@"JavaAppleScriptEngineAdditions: conversion of an NSNumber with objCType '%s' to an aeDescriptor is not supported.", type];
+    
+    return nil;
+}
+
+@end
+
+
+@implementation NSImage (JavaAppleScriptEngineAdditions)
+
+- (NSAppleEventDescriptor *)aeDescriptorValue {
+    NSData *data = [self TIFFRepresentation];
+    return [NSAppleEventDescriptor descriptorWithDescriptorType:typeTIFF data:data];
+}
+
++ (NSImage *)imageWithAEDesc:(NSAppleEventDescriptor *)desc {
+    const AEDesc *d = [desc aeDesc];
+    NSMutableData *data = [NSMutableData dataWithLength:AEGetDescDataSize(d)];
+    AEGetDescData(d, [data mutableBytes], [data length]);
+    return [[[NSImage alloc] initWithData:data] autorelease];
+}
+
+@end
+
+
+
+@implementation NSAppleEventDescriptor (JavaAppleScriptEngineAdditions)
+
+// we're going to leak this.  It doesn't matter much for running apps, but 
+// for developers it might be nice to try to dispose of it (so it would not clutter the
+// output when testing for leaks)
+static NSMutableDictionary *handlerDict = nil;
+
+- (id)objCObjectValue {
+    if (handlerDict == nil) [NSAppleEventDescriptor jaseSetUpHandlerDict];
+    
+    id returnObj;
+    DescType type = [self descriptorType];
+    NSInvocation *handlerInvocation = [handlerDict objectForKey:[NSValue valueWithBytes:&type objCType:@encode(DescType)]];
+    if (handlerInvocation == nil) {
+        if (type == typeType) {
+            DescType subType;
+            AEGetDescData([self aeDesc], &subType, sizeof(subType));
+            if (subType == typeNull) return [NSNull null];
+        }
+        // return raw apple event descriptor if no handler is registered
+        returnObj = self;
+    } else {
+        [handlerInvocation setArgument:&self atIndex:2];
+        [handlerInvocation invoke];
+        [handlerInvocation getReturnValue:&returnObj];
+    }
+    
+    return returnObj;
+}
+
+// FIXME - error checking, non nil handler
++ (void)registerConversionHandler:(id)anObject selector:(SEL)aSelector forDescriptorTypes:(DescType)firstType, ... {
+    if (handlerDict == nil) [NSAppleEventDescriptor jaseSetUpHandlerDict];
+    
+    NSInvocation *handlerInvocation = [NSInvocation invocationWithMethodSignature:[anObject methodSignatureForSelector:aSelector]];
+    [handlerInvocation setTarget:anObject];
+    [handlerInvocation setSelector:aSelector];    
+    
+    DescType aType = firstType;
+    va_list typesList;
+    va_start(typesList, firstType);
+    do {
+        NSValue *type = [NSValue valueWithBytes:&aType objCType:@encode(DescType)];
+        [handlerDict setObject:handlerInvocation forKey:type];
+    } while((aType = va_arg(typesList, DescType)) != 0);
+    va_end(typesList);
+}
+
+
+- (NSAppleEventDescriptor *)aeDescriptorValue {
+    return self;
+}
+
++ (id)descriptorWithInt16:(SInt16)val {
+    return [NSAppleEventDescriptor descriptorWithDescriptorType:typeSInt16 bytes:&val length:sizeof(val)];    
+}
+
+- (SInt16)int16Value {
+    SInt16 retValue;
+    [[[self coerceToDescriptorType:typeSInt16] data] getBytes:&retValue];
+    return retValue;
+}
+
++ (id)descriptorWithUnsignedInt32:(UInt32)val {
+    return [NSAppleEventDescriptor descriptorWithDescriptorType:typeUInt32 bytes:&val length:sizeof(val)];        
+}
+
+- (UInt32)unsignedInt32Value {
+    UInt32 retValue;
+    [[[self coerceToDescriptorType:typeUInt32] data] getBytes:&retValue];
+    return retValue;
+}
+
+
++ (id)descriptorWithFloat32:(Float32)val {
+    return [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE32BitFloatingPoint bytes:&val length:sizeof(val)];        
+}
+
+- (Float32)float32Value {
+    Float32 retValue;
+    [[[self coerceToDescriptorType:typeIEEE32BitFloatingPoint] data] getBytes:&retValue];
+    return retValue;
+}
+
+
++ (id)descriptorWithFloat64:(Float64)val {
+    return [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE64BitFloatingPoint bytes:&val length:sizeof(val)];        
+}
+
+- (Float64)float64Value {
+    Float64 retValue;
+    [[[self coerceToDescriptorType:typeIEEE64BitFloatingPoint] data] getBytes:&retValue];
+    return retValue;
+}
+
++ (id)descriptorWithLongDateTime:(LongDateTime)val {
+    return [NSAppleEventDescriptor descriptorWithDescriptorType:typeLongDateTime bytes:&val length:sizeof(val)];        
+}
+
+- (LongDateTime)longDateTimeValue {
+    LongDateTime retValue;
+    [[[self coerceToDescriptorType:typeLongDateTime] data] getBytes:&retValue];
+    return retValue;
+}
+
++ (void)jaseSetUpHandlerDict {
+    handlerDict = [[NSMutableDictionary alloc] init];
+    
+    // register default handlers
+    // types are culled from AEDataModel.h and AERegistry.h
+    
+    // string -> NSStrings
+    [NSAppleEventDescriptor registerConversionHandler:[NSString class] selector:@selector(stringWithAEDesc:) forDescriptorTypes:
+     typeUnicodeText, typeText, typeUTF8Text, typeCString, typeChar, nil];
+    
+    // number/bool -> NSNumber
+    [NSAppleEventDescriptor registerConversionHandler:[NSNumber class] selector:@selector(numberWithAEDesc:) forDescriptorTypes:
+     typeBoolean, typeTrue, typeFalse,
+     typeSInt16, typeSInt32, typeUInt32, typeSInt64,
+     typeIEEE32BitFloatingPoint, typeIEEE64BitFloatingPoint, type128BitFloatingPoint, nil];
+    
+    // list -> NSArray
+    [NSAppleEventDescriptor registerConversionHandler:[NSArray class] selector:@selector(arrayWithAEDesc:) forDescriptorTypes:typeAEList, nil];
+    
+    // record -> NSDictionary
+    [NSAppleEventDescriptor registerConversionHandler:[NSDictionary class] selector:@selector(dictionaryWithAEDesc:) forDescriptorTypes:typeAERecord, nil];
+    
+    // date -> NSDate
+    [NSAppleEventDescriptor registerConversionHandler:[NSDate class] selector:@selector(dateWithAEDesc:) forDescriptorTypes:typeLongDateTime, nil];
+    
+    // images -> NSImage
+    [NSAppleEventDescriptor registerConversionHandler:[NSImage class] selector:@selector(imageWithAEDesc:) forDescriptorTypes:
+     typeTIFF, typeJPEG, typeGIF, typePict, typeIconFamily, typeIconAndMask, nil];
+    
+    // vers -> NSString
+    [NSAppleEventDescriptor registerConversionHandler:[NSString class] selector:@selector(versionWithAEDesc:) forDescriptorTypes:typeVersion, nil];
+    
+    // null -> NSNull
+    [NSAppleEventDescriptor registerConversionHandler:[NSNull class] selector:@selector(nullWithAEDesc:) forDescriptorTypes:typeNull, nil];
+}
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/apple/applescript/AppleScriptEngine.m	Tue Aug 30 11:13:12 2011 -0700
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import "apple_applescript_AppleScriptEngine.h"
+#import "apple_applescript_AppleScriptEngineFactory.h"
+
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+#import "NS_Java_ConversionUtils.h"
+#import "AppleScriptExecutionContext.h"
+
+//#define DEBUG 1
+
+
+/*
+ * Class:     apple_applescript_AppleScriptEngineFactory
+ * Method:    initNative
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_apple_applescript_AppleScriptEngineFactory_initNative
+(JNIEnv *env, jclass clazz)
+{
+    return;
+}
+
+
+/*
+ * Class:     apple_applescript_AppleScriptEngine
+ * Method:    initNative
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_apple_applescript_AppleScriptEngine_initNative
+(JNIEnv *env, jclass clazz)
+{
+    return;
+}
+
+
+/*
+ * Class:     apple_applescript_AppleScriptEngine
+ * Method:    createContextFrom
+ * Signature: (Ljava/lang/Object;)J
+ */
+JNIEXPORT jlong JNICALL Java_apple_applescript_AppleScriptEngine_createContextFrom
+(JNIEnv *env, jclass clazz, jobject javaContext)
+{
+    NSObject *obj = nil;
+    
+JNF_COCOA_ENTER(env);
+    
+    obj = [[JavaAppleScriptEngineCoercion coercer] coerceJavaObject:javaContext withEnv:env];
+    
+#ifdef DEBUG
+    NSLog(@"converted context: %@", obj);
+#endif
+    
+    CFRetain(obj);
+    
+JNF_COCOA_EXIT(env);
+    
+    return ptr_to_jlong(obj);
+}
+
+
+/*
+ * Class:     apple_applescript_AppleScriptEngine
+ * Method:    createObjectFrom
+ * Signature: (J)Ljava/lang/Object;
+ */
+JNIEXPORT jobject JNICALL Java_apple_applescript_AppleScriptEngine_createObjectFrom
+(JNIEnv *env, jclass clazz, jlong nativeContext)
+{
+    jobject obj = NULL;
+    
+JNF_COCOA_ENTER(env);
+    
+    obj = [[JavaAppleScriptEngineCoercion coercer] coerceNSObject:(id)jlong_to_ptr(nativeContext) withEnv:env];
+    
+JNF_COCOA_EXIT(env);
+    
+    return obj;
+}
+
+
+/*
+ * Class:     apple_applescript_AppleScriptEngine
+ * Method:    disposeContext
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_apple_applescript_AppleScriptEngine_disposeContext
+(JNIEnv *env, jclass clazz, jlong nativeContext)
+{
+    
+JNF_COCOA_ENTER(env);
+    
+    id obj = (id)jlong_to_ptr(nativeContext);
+    if (obj != nil) CFRelease(obj);
+    
+JNF_COCOA_EXIT(env);
+
+}
+
+
+/*
+ * Class:     apple_applescript_AppleScriptEngine
+ * Method:    evalScript
+ * Signature: (Ljava/lang/String;J)J
+ */
+JNIEXPORT jlong JNICALL Java_apple_applescript_AppleScriptEngine_evalScript
+(JNIEnv *env, jclass clazz, jstring ascript, jlong contextptr)
+{ 
+    id retval = nil;
+    
+JNF_COCOA_ENTER(env);
+    
+    NSDictionary *ncontext = jlong_to_ptr(contextptr);
+    NSString *source = JNFJavaToNSString(env, ascript);
+    
+#ifdef DEBUG
+    NSLog(@"evalScript(source:\"%@\" context: %@)", source, ncontext);
+#endif
+    
+    AppleScriptExecutionContext *scriptInvocationCtx = [[[AppleScriptExecutionContext alloc] initWithSource:source context:ncontext] autorelease];
+    retval = [scriptInvocationCtx invokeWithEnv:env];
+    
+#ifdef DEBUG
+    NSLog(@"returning: %@", retval);
+#endif
+    
+    if (retval) CFRetain(retval);
+    
+JNF_COCOA_EXIT(env);
+    
+    return ptr_to_jlong(retval);
+}
+
+
+/*
+ * Class:     apple_applescript_AppleScriptEngine
+ * Method:    evalScriptFromURL
+ * Signature: (Ljava/lang/String;J)J
+ */
+JNIEXPORT jlong JNICALL Java_apple_applescript_AppleScriptEngine_evalScriptFromURL
+(JNIEnv *env, jclass clazz, jstring afilename, jlong contextptr)
+{
+    id retval = nil;
+    
+JNF_COCOA_ENTER(env); 
+    
+    NSDictionary *ncontext = jlong_to_ptr(contextptr);
+    NSString *filename = JNFJavaToNSString(env, afilename);
+    
+#ifdef DEBUG
+    NSLog(@"evalScript(filename:\"%@\" context: %@)", filename, ncontext);
+#endif
+    
+    AppleScriptExecutionContext *scriptInvocationCtx = [[[AppleScriptExecutionContext alloc] initWithFile:filename context:ncontext] autorelease];
+    retval = [scriptInvocationCtx invokeWithEnv:env];
+    
+#ifdef DEBUG
+    NSLog(@"returning: %@", retval);
+#endif
+    
+    if (retval) CFRetain(retval);
+    
+JNF_COCOA_EXIT(env);
+    
+    return ptr_to_jlong(retval);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/apple/applescript/AppleScriptExecutionContext.h	Tue Aug 30 11:13:12 2011 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+
+@interface AppleScriptExecutionContext : NSObject {
+    NSString *source;
+    BOOL isFile;
+    NSDictionary *context;
+    NSDictionary *error;
+    id returnValue;
+}
+
+@property (nonatomic, retain) NSString *source;
+@property (nonatomic, retain) NSDictionary *context;
+@property (nonatomic, retain) NSDictionary *error;
+@property (nonatomic, retain) id returnValue;
+
+- (id) initWithSource:(NSString *)source context:(NSDictionary *)context;
+- (id) initWithFile:(NSString *)filename context:(NSDictionary *)context;
+- (id) invokeWithEnv:(JNIEnv *)env;
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/apple/applescript/AppleScriptExecutionContext.m	Tue Aug 30 11:13:12 2011 -0700
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import "AppleScriptExecutionContext.h"
+
+#import <Carbon/Carbon.h>
+
+#import "AS_NS_ConversionUtils.h"
+
+
+@implementation AppleScriptExecutionContext
+
+@synthesize source;
+@synthesize context;
+@synthesize error;
+@synthesize returnValue;
+
+- (id) init:(NSString *)sourceIn context:(id)contextIn {
+    self = [super init];
+    if (!self) return self;
+    
+    self.source = sourceIn;
+    self.context = contextIn;
+    self.returnValue = nil;
+    self.error = nil;
+    
+    return self;
+}
+
+- (id) initWithSource:(NSString *)sourceIn context:(NSDictionary *)contextIn {
+    self = [self init:sourceIn context:contextIn];
+    isFile = NO;
+    return self;
+}
+
+- (id) initWithFile:(NSString *)filenameIn context:(NSDictionary *)contextIn {
+    self = [self init:filenameIn context:contextIn];
+    isFile = YES;
+    return self;
+}
+
+- (void) dealloc {
+    self.source = nil;
+    self.context = nil;
+    self.returnValue = nil;
+    self.error = nil;
+    
+    [super dealloc];
+}
+
+- (NSAppleScript *) scriptFromURL {
+    NSURL *url = [NSURL URLWithString:source];
+    NSDictionary *err = nil;
+    NSAppleScript *script = [[[NSAppleScript alloc] initWithContentsOfURL:url error:(&err)] autorelease];
+    if (err != nil) self.error = err;
+    return script;
+}
+
+- (NSAppleScript *) scriptFromSource {
+    return [[[NSAppleScript alloc] initWithSource:source] autorelease];
+}
+
+- (NSAppleEventDescriptor *) functionInvocationEvent {
+    NSString *function = [[context objectForKey:@"javax_script_function"] description];
+    if (function == nil) return nil;
+    
+    // wrap the arg in an array if it is not already a list
+    id args = [context objectForKey:@"javax_script_argv"];
+    if (![args isKindOfClass:[NSArray class]]) {
+        args = [NSArray arrayWithObjects:args, nil];
+    }
+    
+    // triangulate our target
+    int pid = [[NSProcessInfo processInfo] processIdentifier];
+    NSAppleEventDescriptor* targetAddress = [NSAppleEventDescriptor descriptorWithDescriptorType:typeKernelProcessID
+                                                                                           bytes:&pid
+                                                                                          length:sizeof(pid)];
+    
+    // create the event to call a subroutine in the script
+    NSAppleEventDescriptor* event = [[NSAppleEventDescriptor alloc] initWithEventClass:kASAppleScriptSuite
+                                                                               eventID:kASSubroutineEvent
+                                                                      targetDescriptor:targetAddress
+                                                                              returnID:kAutoGenerateReturnID
+                                                                         transactionID:kAnyTransactionID];
+    
+    // set up the handler
+    NSAppleEventDescriptor* subroutineDescriptor = [NSAppleEventDescriptor descriptorWithString:[function lowercaseString]];
+    [event setParamDescriptor:subroutineDescriptor forKeyword:keyASSubroutineName];
+    
+    // set up the arguments
+    [event setParamDescriptor:[args aeDescriptorValue] forKeyword:keyDirectObject];
+    
+    return [event autorelease];
+}
+
+- (void) invoke {
+    // create our script
+    NSAppleScript *script = isFile ? [self scriptFromURL] : [self scriptFromSource];
+    if (self.error != nil) return;
+    
+    // find out if we have a subroutine to call
+    NSAppleEventDescriptor *fxnInvkEvt = [self functionInvocationEvent];
+    
+    // exec!
+    NSAppleEventDescriptor *desc = nil;
+    NSDictionary *err = nil;
+    if (fxnInvkEvt == nil) {
+        desc = [script executeAndReturnError:(&err)];
+    } else {
+        desc = [script executeAppleEvent:fxnInvkEvt error:(&err)];
+    }
+    
+    // if we encountered an exception, stash and bail
+    if (err != nil) {
+        self.error = err;
+        return;
+    }
+    
+    // convert to NSObjects, and return in ivar
+    self.returnValue = [desc objCObjectValue];
+}
+
+- (id) invokeWithEnv:(JNIEnv *)env {
+    BOOL useAnyThread = [@"any-thread" isEqual:[context valueForKey:@"javax_script_threading"]];
+    
+    // check if we are already on the AppKit thread, if desired
+    if(pthread_main_np() || useAnyThread) {
+        [self invoke];
+    } else {
+        [JNFRunLoop performOnMainThread:@selector(invoke) on:self withObject:nil waitUntilDone:YES];
+    }
+    
+    // if we have an exception parked in our ivar, snarf the message (if there is one), and toss a ScriptException
+    if (self.error != nil) {
+        NSString *asErrString = [self.error objectForKey:NSAppleScriptErrorMessage];
+        if (!asErrString) asErrString = @"AppleScriptEngine failed to execute script."; // usually when we fail to load a file
+        [JNFException raise:env as:"javax/script/ScriptException" reason:[asErrString UTF8String]];
+    }
+    
+    return self.returnValue;
+}
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/apple/applescript/NS_Java_ConversionUtils.h	Tue Aug 30 11:13:12 2011 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+
+@interface JavaAppleScriptEngineCoercion : NSObject
+
++ (JNFTypeCoercer *) coercer;
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/apple/applescript/NS_Java_ConversionUtils.m	Tue Aug 30 11:13:12 2011 -0700
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import "NS_Java_ConversionUtils.h"
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface JavaAppleScriptBaseConverter : NSObject <JNFTypeCoercion>
+@end
+
+@interface JavaAppleScriptImageConverter : NSObject <JNFTypeCoercion>
+@end
+
+@interface JavaAppleScriptVersionConverter : NSObject <JNFTypeCoercion>
+@end
+
+@interface JavaAppleScriptNullConverter : NSObject <JNFTypeCoercion>
+@end
+
+
+@implementation JavaAppleScriptEngineCoercion
+
+static JNFTypeCoercer *appleScriptCoercer = nil;
+
++ (JNFTypeCoercer *) coercer {
+    if (appleScriptCoercer) return appleScriptCoercer;
+    
+    id asSpecificCoercions = [[JNFDefaultCoercions defaultCoercer] deriveCoercer];
+    [asSpecificCoercions addCoercion:[[[JavaAppleScriptImageConverter alloc] init] autorelease] forNSClass:[NSImage class] javaClass:@"java/awt/Image"];
+    [asSpecificCoercions addCoercion:[[[JavaAppleScriptVersionConverter alloc] init] autorelease] forNSClass:[NSAppleEventDescriptor class] javaClass:nil];
+    [asSpecificCoercions addCoercion:[[[JavaAppleScriptNullConverter alloc] init] autorelease] forNSClass:[NSNull class] javaClass:nil];
+    
+    return appleScriptCoercer = [asSpecificCoercions retain];
+}
+
+@end
+
+
+// [NSObject description] <-> java.lang.Object.toString()
+@implementation JavaAppleScriptBaseConverter
+
+// by default, bizzare NSObjects will have -description called on them, and passed back to Java like that
+- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
+    return JNFNSToJavaString(env, [obj description]);
+}
+
+// by default, bizzare Java objects will be toString()'d and passed to AppleScript like that
+- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
+    return JNFObjectToString(env, obj);
+}
+
+@end
+
+
+// NSImage <-> apple.awt.CImage
+@implementation JavaAppleScriptImageConverter
+
+static JNF_CLASS_CACHE(jc_CImage, "apple/awt/CImage");
+static JNF_STATIC_MEMBER_CACHE(jm_CImage_getCreator, jc_CImage, "getCreator", "()Lapple/awt/CImage$Creator;");
+static JNF_MEMBER_CACHE(jm_CImage_getNSImage, jc_CImage, "getNSImage", "()J");
+
+static JNF_CLASS_CACHE(jc_CImage_Generator, "apple/awt/CImage$Creator");
+static JNF_MEMBER_CACHE(jm_CImage_Generator_createImageFromPtr, jc_CImage_Generator, "createImage", "(J)Ljava/awt/image/BufferedImage;");
+static JNF_MEMBER_CACHE(jm_CImage_Generator_createImageFromImg, jc_CImage_Generator, "createImage", "(Ljava/awt/Image;)Lapple/awt/CImage;");
+
+- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
+    NSImage *img = (NSImage *)obj;
+    CFRetain(img);
+    jobject creator = JNFCallStaticObjectMethod(env, jm_CImage_getCreator);
+    jobject jobj = JNFCallObjectMethod(env, creator, jm_CImage_Generator_createImageFromPtr, ptr_to_jlong(img));
+    return jobj;
+}
+
+- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
+    jobject cimage = obj;
+    if (!JNFIsInstanceOf(env, obj, &jc_CImage)) {
+        jobject creator = JNFCallStaticObjectMethod(env, jm_CImage_getCreator);
+        cimage = JNFCallObjectMethod(env, creator, jm_CImage_Generator_createImageFromImg, obj);
+    }
+    
+    jlong nsImagePtr = JNFCallLongMethod(env, cimage, jm_CImage_getNSImage);
+    
+    NSImage *img = (NSImage *)jlong_to_ptr(nsImagePtr);
+    return [[img retain] autorelease];
+}
+
+@end
+
+
+// NSAppleEventDescriptor('vers') -> java.lang.String
+@implementation JavaAppleScriptVersionConverter
+
+- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
+    NSAppleEventDescriptor *desc = (NSAppleEventDescriptor *)obj;
+    
+    const AEDesc *aeDesc = [desc aeDesc];
+    if (aeDesc->descriptorType == typeNull) {
+        return NULL;
+    }
+    
+    return JNFNSToJavaString(env, [obj description]);
+}
+
+- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
+    return nil; // there is no Java object that represents a "version"
+}
+
+@end
+
+
+// NSNull <-> null
+@implementation JavaAppleScriptNullConverter
+
+- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
+    return NULL;
+}
+
+- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
+    return nil;
+}
+
+@end