Author: mrdon Date: Sun Feb 20 18:13:38 2005 New Revision: 154604 URL: http://svn.apache.org/viewcvs?view=rev&rev=154604 Log: * Adding new sugar package to hold all JVM function extensions * Adding List and File function extensions * Adding a system to support runtime registration of function extensions
Added: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ExtensionFunction.java (with props) struts/flow/trunk/src/java/org/apache/struts/flow/sugar/FileExtensions.java (with props) struts/flow/trunk/src/java/org/apache/struts/flow/sugar/JavaObjectWrapper.java (with props) struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ListExtensions.java (with props) struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ScriptableList.java - copied, changed from r154003, struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableList.java struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ScriptableMap.java - copied, changed from r154003, struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableMap.java struts/flow/trunk/src/java/org/apache/struts/flow/sugar/SugarWrapFactory.java - copied, changed from r154003, struts/flow/trunk/src/java/org/apache/struts/flow/core/SugarWrapFactory.java Removed: struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableList.java struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableMap.java struts/flow/trunk/src/java/org/apache/struts/flow/core/SugarWrapFactory.java Added: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ExtensionFunction.java URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ExtensionFunction.java?view=auto&rev=154604 ============================================================================== --- struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ExtensionFunction.java (added) +++ struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ExtensionFunction.java Sun Feb 20 18:13:38 2005 @@ -0,0 +1,57 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.struts.flow.sugar; + +import org.mozilla.javascript.*; +import java.util.*; +import java.io.Serializable; + +/** + * Base class for function extensions. A function extension is a function + * is added to an existing Java object at the Rhino level. + */ +public abstract class ExtensionFunction extends ScriptableObject implements Function { + + protected Object target; + protected Scriptable wrapper; + + public Object call(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) { + try { + return execute(cx, scope, thisObj, args); + } catch (Exception ex) { + throw Context.throwAsScriptRuntimeEx(ex); + } + } + + public abstract Object execute(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) throws Exception; + + public Scriptable construct(Context cx, Scriptable scope, java.lang.Object[] args) { + return null; + } + + public String getClassName() { + return getClass().getName(); + } + + public void setTarget(Object target) { + this.target = target; + } + + public void setWrapper(Scriptable wrapper) { + this.wrapper = wrapper; + } +} Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ExtensionFunction.java ------------------------------------------------------------------------------ svn:executable = * Added: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/FileExtensions.java URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/sugar/FileExtensions.java?view=auto&rev=154604 ============================================================================== --- struts/flow/trunk/src/java/org/apache/struts/flow/sugar/FileExtensions.java (added) +++ struts/flow/trunk/src/java/org/apache/struts/flow/sugar/FileExtensions.java Sun Feb 20 18:13:38 2005 @@ -0,0 +1,80 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.struts.flow.sugar; + +import org.mozilla.javascript.*; + +import java.io.*; +import java.util.*; + +/** + * Adds various functions to java.io.File + */ +public class FileExtensions { + + public static ExtensionFunction append(final File file) { + return new ExtensionFunction() { + public Object execute(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) + throws IOException { + String text = args[0].toString(); + BufferedWriter writer = new BufferedWriter(new FileWriter(file, true)); + writer.write(text); + writer.close(); + return file; + } + }; + } + + public static ExtensionFunction getText(final File file) { + return new ExtensionFunction() { + public Object execute(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) + throws IOException { + + BufferedReader reader = new BufferedReader(new FileReader(file)); + StringBuffer answer = new StringBuffer(); + // reading the content of the file within a char buffer allow to keep the correct line endings + char[] charBuffer = new char[4096]; + int nbCharRead = 0; + while ((nbCharRead = reader.read(charBuffer)) != -1) { + // appends buffer + answer.append(charBuffer, 0, nbCharRead); + } + reader.close(); + return answer.toString(); + } + }; + } + + public static ExtensionFunction eachLine(final File file) { + return new ExtensionFunction() { + public Object execute(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) + throws IOException { + + BufferedReader reader = new BufferedReader(new FileReader(file)); + Function func = (Function)args[0]; + Object[] params = new Object[1]; + String line = null; + while ((line = reader.readLine()) != null) { + params[0] = line; + func.call(cx, scope, thisObj, params); + } + reader.close(); + return null; + } + }; + } + +} Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/FileExtensions.java ------------------------------------------------------------------------------ svn:executable = * Added: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/JavaObjectWrapper.java URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/sugar/JavaObjectWrapper.java?view=auto&rev=154604 ============================================================================== --- struts/flow/trunk/src/java/org/apache/struts/flow/sugar/JavaObjectWrapper.java (added) +++ struts/flow/trunk/src/java/org/apache/struts/flow/sugar/JavaObjectWrapper.java Sun Feb 20 18:13:38 2005 @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.struts.flow.sugar; + +import org.mozilla.javascript.*; + +import java.util.*; +import java.io.Serializable; +import java.lang.reflect.*; + +/** + * Adds support for extended functions to wrapped Java objects. + */ +public class JavaObjectWrapper extends NativeJavaObject implements Scriptable, Wrapper, Serializable { + + private Map functions; + + public JavaObjectWrapper() { + super(); + } + + public JavaObjectWrapper(Scriptable scope, Object javaObject, Class staticType, Map functions) { + super(scope, javaObject, staticType); + this.functions = functions; + } + + public Object get(String name, Scriptable start) { + //System.out.println("looking up function "+name); + Method func = (Method)functions.get(name); + if (func != null) { + try { + ExtensionFunction f = (ExtensionFunction)func.invoke(null, new Object[]{javaObject}); + f.setTarget(javaObject); + f.setWrapper(this); + return f; + } catch (Exception ex) { + throw new RuntimeException("Unable to create function "+name+" on "+javaObject); + } + } else { + return super.get(name, start); + } + } +} Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/JavaObjectWrapper.java ------------------------------------------------------------------------------ svn:executable = * Added: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ListExtensions.java URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ListExtensions.java?view=auto&rev=154604 ============================================================================== --- struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ListExtensions.java (added) +++ struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ListExtensions.java Sun Feb 20 18:13:38 2005 @@ -0,0 +1,106 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.struts.flow.sugar; + +import org.mozilla.javascript.*; + +import java.util.*; +import java.io.Serializable; + +/** + * Adds various function extensions to java.util.List implementations. + */ +public class ListExtensions { + + public static ExtensionFunction each(final List list) { + return new ExtensionFunction() { + public Object execute(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) { + Function func = (Function)args[0]; + Object[] param = new Object[1]; + + for (Iterator i = list.iterator(); i.hasNext(); ) { + param[0] = i.next(); + func.call(cx, scope, thisObj, param); + } + return null; + } + }; + } + + public static ExtensionFunction asImmutable(final List list) { + return new ExtensionFunction() { + public Object execute(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) { + return Collections.unmodifiableList(list); + } + }; + } + + public static ExtensionFunction asSynchronized(final List list) { + return new ExtensionFunction() { + public Object execute(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) { + return Collections.synchronizedList(list); + } + }; + } + + public static ExtensionFunction pop(final List list) { + return new ExtensionFunction() { + public Object execute(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) { + Object o = null; + if (list.size() > 0) { + o = list.get(list.size() - 1); + list.remove(list.size()); + } + return o; + } + }; + } + + public static ExtensionFunction sort(final List list) { + return new ExtensionFunction() { + public Object execute(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) { + Collections.sort(list); + return null; + } + }; + } + + public static ExtensionFunction sortEach(final List list) { + return new ExtensionFunction() { + public Object execute(final Context cx, final Scriptable scope, final Scriptable thisObj, java.lang.Object[] args) { + final Object[] params = new Object[2]; + final Function func = (Function)args[0]; + Comparator comp = new Comparator() { + public int compare(Object o1, Object o2) { + params[0] = o1; + params[1] = o2; + Object result = func.call(cx, scope, thisObj,params); + if (result instanceof Number) { + return ((Number)result).intValue(); + } else { + throw new RuntimeException("Invalid sorting function - should return a number. Returned "+result); + } + } + + public boolean equals(Object o) {return false;} + }; + + Collections.sort(list, comp); + return list; + } + }; + } +} Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ListExtensions.java ------------------------------------------------------------------------------ svn:executable = * Copied: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ScriptableList.java (from r154003, struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableList.java) URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ScriptableList.java?view=diff&rev=154604&p1=struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableList.java&r1=154003&p2=struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ScriptableList.java&r2=154604 ============================================================================== --- struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableList.java (original) +++ struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ScriptableList.java Sun Feb 20 18:13:38 2005 @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.struts.flow.core; +package org.apache.struts.flow.sugar; import org.mozilla.javascript.*; @@ -23,7 +23,7 @@ /** * Wrap a java.util.List for JavaScript. */ -public class ScriptableList extends NativeJavaObject implements Scriptable, Wrapper, Serializable { +public class ScriptableList extends JavaObjectWrapper implements Scriptable, Wrapper, Serializable { private List list; @@ -36,8 +36,8 @@ this.javaObject = javaObject; } - public ScriptableList(Scriptable scope, Object javaObject, Class staticType) { - super(scope, javaObject, staticType); + public ScriptableList(Scriptable scope, Object javaObject, Class staticType, Map funcs) { + super(scope, javaObject, staticType, funcs); if (javaObject instanceof List) { this.list = (List)javaObject; } else { @@ -56,14 +56,6 @@ public Object get(int index, Scriptable start) { return list.get(index); } - - public Object get(String name, Scriptable start) { - if ("each".equals(name)) { - return new EachClosure(); - } else { - return super.get(name, start); - } - } public void put(int index, Scriptable start, Object value) { list.add(index, value); @@ -85,28 +77,6 @@ public Object unwrap() { return this.list; - } - - class EachClosure extends ScriptableObject implements Function { - - public Object call(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) { - Function func = (Function)args[0]; - Object[] param = new Object[1]; - - for (Iterator i = list.iterator(); i.hasNext(); ) { - param[0] = i.next(); - func.call(cx, scope, thisObj, param); - } - return null; - } - - public Scriptable construct(Context cx, Scriptable scope, java.lang.Object[] args) { - return null; - } - - public String getClassName() { - return "EachClosure"; - } } } Copied: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ScriptableMap.java (from r154003, struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableMap.java) URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ScriptableMap.java?view=diff&rev=154604&p1=struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableMap.java&r1=154003&p2=struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ScriptableMap.java&r2=154604 ============================================================================== --- struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableMap.java (original) +++ struts/flow/trunk/src/java/org/apache/struts/flow/sugar/ScriptableMap.java Sun Feb 20 18:13:38 2005 @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.struts.flow.core; +package org.apache.struts.flow.sugar; import org.mozilla.javascript.NativeJavaObject; import org.mozilla.javascript.Scriptable; @@ -25,7 +25,7 @@ /** * Wrap a java.util.Map for JavaScript. */ -public class ScriptableMap extends NativeJavaObject implements Scriptable, Wrapper, Serializable { +public class ScriptableMap extends JavaObjectWrapper implements Scriptable, Wrapper, Serializable { private Map map; private String functionPrefix = null; @@ -38,8 +38,8 @@ this.map = map; } - public ScriptableMap(Scriptable scope, Object javaObject, Class staticType, String functionPrefix) { - super(scope, javaObject, staticType); + public ScriptableMap(Scriptable scope, Object javaObject, Class staticType, String functionPrefix, Map functions) { + super(scope, javaObject, staticType, functions); this.functionPrefix = functionPrefix; if (javaObject instanceof Map) { this.map = (Map)javaObject; Copied: struts/flow/trunk/src/java/org/apache/struts/flow/sugar/SugarWrapFactory.java (from r154003, struts/flow/trunk/src/java/org/apache/struts/flow/core/SugarWrapFactory.java) URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/sugar/SugarWrapFactory.java?view=diff&rev=154604&p1=struts/flow/trunk/src/java/org/apache/struts/flow/core/SugarWrapFactory.java&r1=154003&p2=struts/flow/trunk/src/java/org/apache/struts/flow/sugar/SugarWrapFactory.java&r2=154604 ============================================================================== --- struts/flow/trunk/src/java/org/apache/struts/flow/core/SugarWrapFactory.java (original) +++ struts/flow/trunk/src/java/org/apache/struts/flow/sugar/SugarWrapFactory.java Sun Feb 20 18:13:38 2005 @@ -13,22 +13,59 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.struts.flow.core; +package org.apache.struts.flow.sugar; import org.mozilla.javascript.*; import java.io.*; import java.util.*; +import java.lang.reflect.*; /** - * Wrap a java.util.Collection for JavaScript. + * Wraps Java objects by adding support for function extensions, which are + * functions that extend existing Java objects at the Rhino level. */ public class SugarWrapFactory extends WrapFactory { private String mapFuncPrefix = "fn_"; + private List functionRegistry = new ArrayList(); + private Map functionMappings = new HashMap(); + + public SugarWrapFactory() { + super(); + + // Add default methods + addExtensionFunctions(ListExtensions.class); + addExtensionFunctions(FileExtensions.class); + } + public void setMapFunctionPrefix(String prefix) { this.mapFuncPrefix = prefix; } + + public void addExtensionFunction(Class cls, String name, Method func) { + int modifier = func.getModifiers(); + if (Modifier.isStatic(modifier) && Modifier.isPublic(modifier)) { + ExtensionFunctionEntry entry = new ExtensionFunctionEntry(cls, name, func); + functionRegistry.add(entry); + } else { + throw new IllegalArgumentException("Method "+func+" must be static and public"); + } + } + + public void addExtensionFunctions(Class holder) { + Method[] methods = holder.getDeclaredMethods(); + for (int x=0; x<methods.length; x++) { + int modifier = methods[x].getModifiers(); + if (Modifier.isStatic(modifier) && Modifier.isPublic(modifier)) { + String name = methods[x].getName(); + Class target = methods[x].getParameterTypes()[0]; + ExtensionFunctionEntry entry = new ExtensionFunctionEntry(target, name, methods[x]); + functionRegistry.add(entry); + } + } + + } /** * Wrap Java object as Scriptable instance to allow full access to its @@ -48,17 +85,34 @@ public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class staticType) { + Map map = getExtensionFunctions(javaObject.getClass()); + Scriptable wrap = null; if (javaObject instanceof Map) { wrap = new ScriptableMap(scope, javaObject, staticType, mapFuncPrefix); } else if (javaObject instanceof List) { - wrap = new ScriptableList(scope, javaObject, staticType); + wrap = new ScriptableList(scope, javaObject, staticType, map); } else { - wrap = super.wrapAsJavaObject(cx, scope, javaObject, staticType); + wrap = new JavaObjectWrapper(scope, javaObject, staticType, map); } return wrap; } + private Map getExtensionFunctions(Class cls) { + Map map = (Map)functionMappings.get(cls); + ExtensionFunctionEntry entry; + if (map == null) { + map = new HashMap(); + for (Iterator i = functionRegistry.iterator(); i.hasNext(); ) { + entry = (ExtensionFunctionEntry)i.next(); + if (entry.clazz.isAssignableFrom(cls)) { + map.put(entry.name, entry.function); + } + } + } + return map; + } + // temporary method for testing public static final void main(String[] args) throws Exception { // Creates and enters a Context. The Context stores information @@ -88,6 +142,18 @@ // Exit from the context. Context.exit(); } + } + + class ExtensionFunctionEntry { + public Class clazz; + public String name; + public Method function; + + public ExtensionFunctionEntry(Class cls, String name, Method func) { + this.clazz = cls; + this.name = name; + this.function = func; + } } } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]