Index: src/test/org/codehaus/groovy/jsr223/JSR223Test.java =================================================================== --- src/test/org/codehaus/groovy/jsr223/JSR223Test.java (revision 0) +++ src/test/org/codehaus/groovy/jsr223/JSR223Test.java (revision 0) @@ -0,0 +1,86 @@ +package org.codehaus.groovy.jsr223; + +import junit.framework.TestCase; + +import javax.script.ScriptEngineManager; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptException; + +import org.codehaus.groovy.runtime.InvokerHelper; + +import java.util.List; +import java.util.Iterator; + +/** + * Tests JSR-223 Groovy engine implementation. + * @author Jim White + */ +public class JSR223Test extends TestCase { + protected ScriptEngineManager manager; + + protected void setUp() { + manager = new ScriptEngineManager(); + } + + public void testGetEngineByEngineName() { + ScriptEngine engine = manager.getEngineByName("groovy"); + assertNotNull(engine); + } + +// public void testGetEngineByLanguageName() { +// ScriptEngine engine = manager.getEngineByName("Groovy"); +// assertNotNull(engine); +// } + + public void testGetEngineByExtension() { + ScriptEngine engine = manager.getEngineByExtension("groovy"); + assertNotNull(engine); + } + +// public void testGetEngineByMIMEType() { +// ScriptEngine engine = manager.getEngineByMimeType("x-application/groovy"); +// assertNotNull(engine); +// } + + public void testCheckParameters() { + ScriptEngine engine = manager.getEngineByName("groovy"); + assertNotNull(engine); + + ScriptEngineFactory factory = engine.getFactory(); + assertNotNull(factory); + + boolean gotname = false; + + Iterator names = factory.getNames().iterator(); + while (names.hasNext()) { + if (names.next().equals("groovy")) gotname = true; + } + assertTrue("Short name missing from factory", gotname); + + assertEquals("Groovy", factory.getLanguageName()); + assertNotNull(factory.getEngineVersion()); + assertNotNull(factory.getExtensions()); + assertNotNull(factory.getMimeTypes()); + + assertEquals(InvokerHelper.getVersion(), factory.getLanguageVersion()); + } + + public void testSimpleExpr() throws ScriptException { + ScriptEngine engine = manager.getEngineByName("groovy"); + assertNotNull(engine); + + assertEquals(Integer.valueOf(3), engine.eval("1 + 2")); + } + + public void testSyntaxError() { + ScriptEngine engine = manager.getEngineByName("groovy"); + assertNotNull(engine); + + try { + Object x = engine.eval("z"); + assertFalse("Didn't get ScriptException for syntax error", true); + } catch (ScriptException e) { + } + } +} Index: src/test/JavaSourceCodehausPackagesSuite.java =================================================================== --- src/test/JavaSourceCodehausPackagesSuite.java (revision 14002) +++ src/test/JavaSourceCodehausPackagesSuite.java (working copy) @@ -19,6 +19,7 @@ import org.codehaus.groovy.control.CompilationUnitTest; import org.codehaus.groovy.control.CompilerConfigurationTest; import org.codehaus.groovy.control.messages.SyntaxErrorMessageTest; +import org.codehaus.groovy.jsr223.JSR223Test; import org.codehaus.groovy.runtime.*; import org.codehaus.groovy.syntax.TokenTest; import org.codehaus.groovy.tools.CompilerTest; @@ -34,6 +35,7 @@ public static Test suite() { TestSuite suite = new TestSuite(); suite.addTestSuite(BSFTest.class); + suite.addTestSuite(JSR223Test.class); suite.addTestSuite(BytecodeHelperTest.class); suite.addTestSuite(CacheBSFTest.class); suite.addTestSuite(CapitalizeTest.class); Index: src/main/META-INF/services/javax.script.ScriptEngineFactory =================================================================== --- src/main/META-INF/services/javax.script.ScriptEngineFactory (revision 0) +++ src/main/META-INF/services/javax.script.ScriptEngineFactory (revision 0) @@ -0,0 +1 @@ +org.codehaus.groovy.jsr223.GroovyScriptEngineFactory Index: src/main/org/codehaus/groovy/jsr223/GroovyScriptEngine.java =================================================================== --- src/main/org/codehaus/groovy/jsr223/GroovyScriptEngine.java (revision 0) +++ src/main/org/codehaus/groovy/jsr223/GroovyScriptEngine.java (revision 0) @@ -0,0 +1,407 @@ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: Redistributions of source code + * must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. Neither the name of the Sun Microsystems nor the names of + * is contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/* + * GroovyScriptEngine.java + * @author Mike Grogan + * @author A. Sundararajan + * @author Jim White + */ +package org.codehaus.groovy.jsr223; + +import groovy.lang.Binding; +import groovy.lang.Closure; +import groovy.lang.DelegatingMetaClass; +import groovy.lang.GroovyClassLoader; +import groovy.lang.MetaClass; +import groovy.lang.MissingMethodException; +import groovy.lang.MissingPropertyException; +import groovy.lang.Script; +import groovy.lang.Tuple; + +import org.codehaus.groovy.control.CompilationFailedException; +import org.codehaus.groovy.control.CompilerConfiguration; +import org.codehaus.groovy.syntax.SyntaxException; +import org.codehaus.groovy.runtime.InvokerHelper; +import org.codehaus.groovy.runtime.MetaClassHelper; +import org.codehaus.groovy.runtime.MethodClosure; + +import javax.script.AbstractScriptEngine; +import javax.script.Bindings; +import javax.script.Compilable; +import javax.script.CompiledScript; +import javax.script.Invocable; +import javax.script.ScriptContext; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptException; +import javax.script.SimpleBindings; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class GroovyScriptEngine + extends AbstractScriptEngine implements Compilable, Invocable { + + private static boolean DEBUG = false; + + // script-string-to-generated Class map + private Map classMap; + // global closures map - this is used to simulate a single + // global functions namespace + private Map globalClosures; + // class loader for Groovy generated classes + private GroovyClassLoader loader; + // lazily initialized factory + private volatile GroovyScriptEngineFactory factory; + + // counter used to generate unique global Script class names + private static int counter; + + static { + counter = 0; + } + + public GroovyScriptEngine() { + classMap = Collections.synchronizedMap(new HashMap()); + globalClosures = Collections.synchronizedMap(new HashMap()); + loader = new GroovyClassLoader(getParentLoader(), + new CompilerConfiguration()); + } + + public Object eval(Reader reader, ScriptContext ctx) + throws ScriptException { + return eval(readFully(reader), ctx); + } + + public Object eval(String script, ScriptContext ctx) + throws ScriptException { + try { + return eval(getScriptClass(script), ctx); + } catch (SyntaxException e) { + throw new ScriptException(e.getMessage(), + e.getSourceLocator(), e.getLine()); + } catch (Exception e) { + if (DEBUG) e.printStackTrace(); + throw new ScriptException(e); + } + } + + public Bindings createBindings() { + return new SimpleBindings(); + } + + public ScriptEngineFactory getFactory() { + if (factory == null) { + synchronized (this) { + if (factory == null) { + factory = new GroovyScriptEngineFactory(); + } + } + } + return factory; + } + + // javax.script.Compilable methods + public CompiledScript compile(String scriptSource) throws ScriptException { + try { + return new GroovyCompiledScript(this, + getScriptClass(scriptSource)); + } catch (SyntaxException e) { + throw new ScriptException(e.getMessage(), + e.getSourceLocator(), e.getLine()); + } catch (IOException e) { + throw new ScriptException(e); + } catch (CompilationFailedException ee) { + throw new ScriptException(ee); + } + } + + public CompiledScript compile(Reader reader) throws ScriptException { + return compile(readFully(reader)); + } + + // javax.script.Invocable methods. + public Object invokeFunction(String name, Object... args) + throws ScriptException, NoSuchMethodException { + return invokeImpl(null, name, args); + } + + public Object invokeMethod(Object thiz, String name, Object... args) + throws ScriptException, NoSuchMethodException { + if (thiz == null) { + throw new IllegalArgumentException("script object is null"); + } + return invokeImpl(thiz, name, args); + } + + public T getInterface(Class clasz) { + return makeInterface(null, clasz); + } + + public T getInterface(Object thiz, Class clasz) { + if (thiz == null) { + throw new IllegalArgumentException("script object is null"); + } + return makeInterface(thiz, clasz); + } + + // package-privates + Object eval(Class scriptClass, final ScriptContext ctx) throws ScriptException { + // Bindings so script has access to this environment. + // Only initialize once. + if (null == ctx.getAttribute("context")) { + // add context to bindings + ctx.setAttribute("context", ctx, ScriptContext.ENGINE_SCOPE); + + // direct output to ctx.getWriter + final Writer writer = ctx.getWriter(); + ctx.setAttribute("out", (writer instanceof PrintWriter) ? + writer : + new PrintWriter(writer), + ScriptContext.ENGINE_SCOPE); + +// TODO: JPW: I like this idea, but not sure if these are the right names. +// They aren't really necessary because you can say context.reader or +// context.errorWriter instead. +// // direct errors to ctx.getErrorWriter +// final Writer errorWriter = ctx.getErrorWriter(); +// ctx.setAttribute("err", (errorWriter instanceof PrintWriter) ? +// errorWriter : +// new PrintWriter(errorWriter), +// ScriptContext.ENGINE_SCOPE); +// +// // get input from ctx.getReader +// ctx.setAttribute("input", ctx.getReader(), ScriptContext.ENGINE_SCOPE); + } + + + /* + * We use the following Binding instance so that global variable lookup + * will be done in the current ScriptContext instance. + */ + Binding binding = new Binding(ctx.getBindings(ScriptContext.ENGINE_SCOPE)) { + @Override + public Object getVariable(String name) { + synchronized (ctx) { + int scope = ctx.getAttributesScope(name); + if (scope != -1) { + return ctx.getAttribute(name, scope); + } + } + throw new MissingPropertyException(name, getClass()); + } + @Override + public void setVariable(String name, Object value) { + synchronized (ctx) { + int scope = ctx.getAttributesScope(name); + if (scope == -1) { + scope = ScriptContext.ENGINE_SCOPE; + } + ctx.setAttribute(name, value, scope); + } + } + }; + + try { + Script scriptObject = InvokerHelper.createScript(scriptClass, binding); + + // create a Map of MethodClosures from this new script object + Method[] methods = scriptClass.getMethods(); + Map closures = new HashMap(); + for (Method m : methods) { + String name = m.getName(); + closures.put(name, new MethodClosure(scriptObject, name)); + } + + // save all current closures into global closures map + globalClosures.putAll(closures); + + MetaClass oldMetaClass = scriptObject.getMetaClass(); + + /* + * We override the MetaClass of this script object so that we can + * forward calls to global closures (of previous or future "eval" calls) + * This gives the illusion of working on the same "global" scope. + */ + scriptObject.setMetaClass(new DelegatingMetaClass(oldMetaClass) { + @Override + public Object invokeMethod(Object object, String name, Object args) { + if (args == null) { + return invokeMethod(object, name, MetaClassHelper.EMPTY_ARRAY); + } + if (args instanceof Tuple) { + return invokeMethod(object, name, ((Tuple)args).toArray()); + } + if (args instanceof Object[]) { + return invokeMethod(object, name, (Object[]) args); + } else { + return invokeMethod(object, name, new Object[] { args }); + } + } + + @Override + public Object invokeMethod(Object object, String name, Object[] args) { + try { + return super.invokeMethod(object, name, args); + } catch (MissingMethodException mme) { + return callGlobal(name, args, ctx); + } + } + @Override + public Object invokeStaticMethod(Object object, String name, Object[] args) { + try { + return super.invokeStaticMethod(object, name, args); + } catch (MissingMethodException mme) { + return callGlobal(name, args, ctx); + } + } + }); + + return scriptObject.run(); + } catch (Exception e) { + throw new ScriptException(e); + } + } + + Class getScriptClass(String script) + throws SyntaxException, + CompilationFailedException, + IOException { + Class clazz = classMap.get(script); + if (clazz != null) { + return clazz; + } + + InputStream stream = new ByteArrayInputStream(script.getBytes()); + clazz = loader.parseClass(stream, generateScriptName()); + classMap.put(script, clazz); + return clazz; + } + + //-- Internals only below this point + + // invokes the specified method/function on the given object. + private Object invokeImpl(Object thiz, String name, Object... args) + throws ScriptException, NoSuchMethodException { + if (name == null) { + throw new NullPointerException("method name is null"); + } + + try { + if (thiz != null) { + return InvokerHelper.invokeMethod(thiz, name, args); + } else { + return callGlobal(name, args); + } + } catch (MissingMethodException mme) { + throw new NoSuchMethodException(mme.getMessage()); + } catch (Exception e) { + throw new ScriptException(e); + } + } + + // call the script global function of the given name + private Object callGlobal(String name, Object[] args) { + return callGlobal(name, args, context); + } + + private Object callGlobal(String name, Object[] args, ScriptContext ctx) { + Closure closure = globalClosures.get(name); + if (closure != null) { + return closure.call(args); + } else { + // Look for closure valued variable in the + // given ScriptContext. If available, call it. + Object value = ctx.getAttribute(name); + if (value instanceof Closure) { + return ((Closure)value).call(args); + } // else fall thru.. + } + throw new MissingMethodException(name, getClass(), args); + } + + // generate a unique name for top-level Script classes + private synchronized String generateScriptName() { + return "Script" + (++counter) + ".groovy"; + } + + private T makeInterface(Object obj, Class clazz) { + final Object thiz = obj; + if (clazz == null || !clazz.isInterface()) { + throw new IllegalArgumentException("interface Class expected"); + } + return (T) Proxy.newProxyInstance( + clazz.getClassLoader(), + new Class[] { clazz }, + new InvocationHandler() { + public Object invoke(Object proxy, Method m, Object[] args) + throws Throwable { + return invokeImpl(thiz, m.getName(), args); + } + }); + } + + // determine appropriate class loader to serve as parent loader + // for GroovyClassLoader instance + private ClassLoader getParentLoader() { + // check whether thread context loader can "see" Groovy Script class + ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader(); + try { + Class c = ctxtLoader.loadClass(Script.class.getName()); + if (c == Script.class) { + return ctxtLoader; + } + } catch (ClassNotFoundException cnfe) { + } + // exception was thrown or we get wrong class + return Script.class.getClassLoader(); + } + + private String readFully(Reader reader) throws ScriptException { + char[] arr = new char[8*1024]; // 8K at a time + StringBuilder buf = new StringBuilder(); + int numChars; + try { + while ((numChars = reader.read(arr, 0, arr.length)) > 0) { + buf.append(arr, 0, numChars); + } + } catch (IOException exp) { + throw new ScriptException(exp); + } + return buf.toString(); + } +} Index: src/main/org/codehaus/groovy/jsr223/GroovyCompiledScript.java =================================================================== --- src/main/org/codehaus/groovy/jsr223/GroovyCompiledScript.java (revision 0) +++ src/main/org/codehaus/groovy/jsr223/GroovyCompiledScript.java (revision 0) @@ -0,0 +1,57 @@ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: Redistributions of source code + * must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. Neither the name of the Sun Microsystems nor the names of + * is contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * GroovyCompiledScript.java + * @author Mike Grogan + * @author A. Sundararajan + */ + +package org.codehaus.groovy.jsr223; + +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptException; + + +public class GroovyCompiledScript extends CompiledScript { + + private GroovyScriptEngine engine; + private Class clasz; + + public GroovyCompiledScript(GroovyScriptEngine engine, Class clasz) { + this.engine = engine; + this.clasz = clasz; + } + + public Object eval(ScriptContext context) throws ScriptException { + return engine.eval(clasz, context); + } + + public ScriptEngine getEngine() { + return engine; + } + +} Index: src/main/org/codehaus/groovy/jsr223/GroovyScriptEngineFactory.java =================================================================== --- src/main/org/codehaus/groovy/jsr223/GroovyScriptEngineFactory.java (revision 0) +++ src/main/org/codehaus/groovy/jsr223/GroovyScriptEngineFactory.java (revision 0) @@ -0,0 +1,180 @@ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: Redistributions of source code + * must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. Neither the name of the Sun Microsystems nor the names of + * is contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * GroovyScriptEngineFactory.java + * @author Mike Grogan + * @author A. Sundararajan + * @author Jim White + */ + +package org.codehaus.groovy.jsr223; + +import org.codehaus.groovy.runtime.InvokerHelper; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class GroovyScriptEngineFactory implements ScriptEngineFactory { + + private static final String SHORT_NAME = "groovy"; + + private static String VERSION = "2.0d1"; + + public String getEngineName() { + return "Groovy Scripting Engine"; + } + +/** + Note that the scripting.dev.java.net engine had this backwards. + The engine version refers to this engine implementation. + Whereas language version refers to the groovy implementation + (which is obtained from the runtime). +*/ + + public String getEngineVersion() { + return VERSION; + } + +/** + This is also different than scripting.dev.java.net which used an + initial lowercase. But these are proper names and should be capitalized. +*/ + public String getLanguageName() { + return "Groovy"; + } + + public String getLanguageVersion() { + return InvokerHelper.getVersion(); + } + + public List getExtensions() { + return extensions; + } + + public List getMimeTypes() { + return mimeTypes; + } + + public List getNames() { + return names; + } + + public Object getParameter(String key) { + + if (ScriptEngine.NAME.equals(key)) { + return SHORT_NAME; + } else if (ScriptEngine.ENGINE.equals(key)) { + return getEngineName(); + } else if (ScriptEngine.ENGINE_VERSION.equals(key)) { + return VERSION; + } else if (ScriptEngine.LANGUAGE.equals(key)) { + return getLanguageName(); + } else if (ScriptEngine.LANGUAGE_VERSION.equals(key)) { + return InvokerHelper.getVersion(); + } else if ("THREADING".equals(key)) { + return "MULTITHREADED"; + } else { + throw new IllegalArgumentException("Invalid key"); + } + + } + + + public ScriptEngine getScriptEngine() { + return new GroovyScriptEngine(); + } + + public String getMethodCallSyntax(String obj, String method, + String... args) { + + String ret = obj + "." + method + "("; + int len = args.length; + if (len == 0) { + ret += ")"; + return ret; + } + + for (int i = 0; i < len; i++) { + ret += args[i]; + if (i != len - 1) { + ret += ","; + } else { + ret += ")"; + } + } + return ret; + } + + public String getOutputStatement(String toDisplay) { + StringBuilder buf = new StringBuilder(); + buf.append("println(\""); + int len = toDisplay.length(); + for (int i = 0; i < len; i++) { + char ch = toDisplay.charAt(i); + switch (ch) { + case '"': + buf.append("\\\""); + break; + case '\\': + buf.append("\\\\"); + break; + default: + buf.append(ch); + break; + } + } + buf.append("\")"); + return buf.toString(); + } + + public String getProgram(String... statements) { + StringBuilder ret = new StringBuilder(); + int len = statements.length; + for (int i = 0; i < len; i++) { + ret.append(statements[i]); + ret.append('\n'); + } + return ret.toString(); + } + + private static List names; + private static List extensions; + private static List mimeTypes; + + static { + names = new ArrayList(1); + names.add(SHORT_NAME); + names = Collections.unmodifiableList(names); + + extensions = names; + + mimeTypes = new ArrayList(0); + mimeTypes = Collections.unmodifiableList(mimeTypes); + } +} Index: pom.xml =================================================================== --- pom.xml (revision 14002) +++ pom.xml (working copy) @@ -610,6 +610,14 @@ + org.livetribe + livetribe-jsr223 + 2.0.3 + compile + true + + + xmlunit xmlunit 1.2