You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by mr...@apache.org on 2005/02/21 03:13:40 UTC
svn commit: r154604 - in struts/flow/trunk/src/java/org/apache/struts/flow:
core/ sugar/
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: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org