You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by gb...@apache.org on 2009/06/12 19:00:08 UTC
svn commit: r784193 - in /incubator/pivot/trunk:
demos/src/pivot/demos/scripting/ wtk/src/pivot/wtkx/
Author: gbrown
Date: Fri Jun 12 17:00:08 2009
New Revision: 784193
URL: http://svn.apache.org/viewvc?rev=784193&view=rev
Log:
Add support for inline scripts to WTKXSerializer; allow event handlers to be specified using a simplified function-based syntax.
Modified:
incubator/pivot/trunk/demos/src/pivot/demos/scripting/ScriptingDemo.java
incubator/pivot/trunk/demos/src/pivot/demos/scripting/demo.groovy
incubator/pivot/trunk/demos/src/pivot/demos/scripting/demo.js
incubator/pivot/trunk/demos/src/pivot/demos/scripting/scripting_demo.wtkx
incubator/pivot/trunk/wtk/src/pivot/wtkx/WTKXSerializer.java
Modified: incubator/pivot/trunk/demos/src/pivot/demos/scripting/ScriptingDemo.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/demos/src/pivot/demos/scripting/ScriptingDemo.java?rev=784193&r1=784192&r2=784193&view=diff
==============================================================================
--- incubator/pivot/trunk/demos/src/pivot/demos/scripting/ScriptingDemo.java (original)
+++ incubator/pivot/trunk/demos/src/pivot/demos/scripting/ScriptingDemo.java Fri Jun 12 17:00:08 2009
@@ -17,6 +17,7 @@
package pivot.demos.scripting;
import pivot.collections.Dictionary;
+import pivot.collections.List;
import pivot.wtk.Application;
import pivot.wtk.Button;
import pivot.wtk.ButtonPressListener;
@@ -36,6 +37,7 @@
private Window window = null;
@WTKX private String foo;
+ @WTKX private List<?> listData;
public void startup(Display display, Dictionary<String, String> properties)
throws Exception {
@@ -43,7 +45,9 @@
window = (Window)wtkxSerializer.readObject(this, "scripting_demo.wtkx");
wtkxSerializer.bind(this);
- System.out.println("foo = " + foo);
+ System.out.println("foo = \"" + foo + "\"");
+ System.out.println("listData.getLength() = " + listData.getLength());
+
window.open(display);
}
Modified: incubator/pivot/trunk/demos/src/pivot/demos/scripting/demo.groovy
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/demos/src/pivot/demos/scripting/demo.groovy?rev=784193&r1=784192&r2=784193&view=diff
==============================================================================
--- incubator/pivot/trunk/demos/src/pivot/demos/scripting/demo.groovy (original)
+++ incubator/pivot/trunk/demos/src/pivot/demos/scripting/demo.groovy Fri Jun 12 17:00:08 2009
@@ -14,40 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import pivot.collections.adapter.*
import pivot.wtk.*
-foo = "ABCDE"
-
-def doSomething(button) {
+def showAlert(button) {
Alert.alert("You clicked me!", button.getWindow())
}
-
-public class MyButtonPressListener1 implements ButtonPressListener {
- private Script script;
-
- public MyButtonPressListener1(Script script) {
- this.script = script
- }
-
- public void buttonPressed(Button button) {
- script.doSomething(button)
- }
-}
-
-buttonPressListener1 = new MyButtonPressListener1(this)
-
-public class MyButtonPressListener2 implements ButtonPressListener {
- public void buttonPressed(Button button) {
- System.out.println("[Groovy] A button was clicked.");
- }
-}
-
-buttonPressListener2 = new MyButtonPressListener2()
-
-listData = []
-listData << "One"
-listData << "Two"
-listData << "Three"
-
-listData = new ListAdapter(listData)
Modified: incubator/pivot/trunk/demos/src/pivot/demos/scripting/demo.js
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/demos/src/pivot/demos/scripting/demo.js?rev=784193&r1=784192&r2=784193&view=diff
==============================================================================
--- incubator/pivot/trunk/demos/src/pivot/demos/scripting/demo.js (original)
+++ incubator/pivot/trunk/demos/src/pivot/demos/scripting/demo.js Fri Jun 12 17:00:08 2009
@@ -14,29 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-importPackage(Packages.java.lang);
-importPackage(Packages.pivot.collections);
importPackage(Packages.pivot.wtk);
-var foo = "Hello World";
-
-function doSomething(button) {
+function showAlert(button) {
Alert.alert("You clicked me!", button.getWindow());
}
-
-var buttonPressListener1 = new ButtonPressListener() {
- buttonPressed: function(button) {
- doSomething(button);
- }
-};
-
-var buttonPressListener2 = new ButtonPressListener() {
- buttonPressed: function(button) {
- System.out.println("[JavaScript] A button was clicked.");
- }
-};
-
-var listData = new ArrayList();
-listData.add("One");
-listData.add("Two");
-listData.add("Three");
Modified: incubator/pivot/trunk/demos/src/pivot/demos/scripting/scripting_demo.wtkx
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/demos/src/pivot/demos/scripting/scripting_demo.wtkx?rev=784193&r1=784192&r2=784193&view=diff
==============================================================================
--- incubator/pivot/trunk/demos/src/pivot/demos/scripting/scripting_demo.wtkx (original)
+++ incubator/pivot/trunk/demos/src/pivot/demos/scripting/scripting_demo.wtkx Fri Jun 12 17:00:08 2009
@@ -20,17 +20,75 @@
xmlns:wtkx="http://incubator.apache.org/pivot/wtkx/1.1"
xmlns:scripting="pivot.demos.scripting"
xmlns="pivot.wtk">
+ <wtkx:script language="javascript">
+ <![CDATA[
+ importPackage(Packages.pivot.collections);
+
+ var foo = "Hello World";
+
+ var listData = new ArrayList();
+ listData.add("One");
+ listData.add("Two");
+ listData.add("Three");
+ ]]>
+ </wtkx:script>
+ <wtkx:script src="demo.js"/>
+
+ <!--
+ <wtkx:script language="groovy">
+ <![CDATA[
+ import pivot.collections.adapter.*
+
+ def foo = "ABCDE"
+
+ def listData = []
+ listData << "One"
+ listData << "Two"
+ listData << "Three"
+
+ listData = new ListAdapter(listData)
+ ]]>
+ </wtkx:script>
+ <wtkx:script src="demo.groovy"/>
+ -->
+
<content>
<Border>
<content>
<FlowPane orientation="vertical" styles="{padding:6}">
- <wtkx:script src="demo.js"/>
- <!-- <wtkx:script src="demo.groovy"/> -->
-
- <PushButton wtkx:id="pushButton" buttonData="Click Me!"
- buttonPressListeners="buttonPressListener1, buttonPressListener2">
+ <PushButton wtkx:id="pushButton" buttonData="Click Me!">
<buttonPressListeners>
- <scripting:ScriptingDemo.MyButtonPressListener/>
+ <wtkx:script language="javascript">
+ <![CDATA[
+ function buttonPressed(button) {
+ showAlert(button);
+ }
+ ]]>
+ </wtkx:script>
+ <wtkx:script language="javascript">
+ <![CDATA[
+ function buttonPressed(button) {
+ java.lang.System.out.println("[JavaScript] A button was clicked.");
+ }
+ ]]>
+ </wtkx:script>
+
+ <!--
+ <wtkx:script language="groovy">
+ <![CDATA[
+ def buttonPressed(button) {
+ showAlert(button);
+ }
+ ]]>
+ </wtkx:script>
+ <wtkx:script language="groovy">
+ <![CDATA[
+ def buttonPressed(Button button) {
+ System.out.println("[Groovy] A button was clicked.");
+ }
+ ]]>
+ </wtkx:script>
+ -->
</buttonPressListeners>
</PushButton>
Modified: incubator/pivot/trunk/wtk/src/pivot/wtkx/WTKXSerializer.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/pivot/wtkx/WTKXSerializer.java?rev=784193&r1=784192&r2=784193&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/pivot/wtkx/WTKXSerializer.java (original)
+++ incubator/pivot/trunk/wtk/src/pivot/wtkx/WTKXSerializer.java Fri Jun 12 17:00:08 2009
@@ -23,9 +23,11 @@
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
@@ -33,9 +35,12 @@
import java.util.Set;
import javax.script.Bindings;
+import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import javax.script.SimpleBindings;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
@@ -534,7 +539,7 @@
// Apply remaining attributes
if (element.value instanceof Dictionary) {
- // The element is an untyped object
+ // The element is already a dictionary
Dictionary<String, Object> dictionary = (Dictionary<String, Object>)element.value;
for (Attribute attribute : attributes) {
@@ -547,7 +552,7 @@
dictionary.put(attribute.localName, resolve(attribute.value, null));
}
} else {
- // The element represents a typed object; apply the attributes
+ // The element is not a dictionary; wrap it in a bean dictionary
BeanDictionary beanDictionary = new BeanDictionary(element.value);
for (Attribute attribute : attributes) {
@@ -596,8 +601,170 @@
}
case SCRIPT: {
- // TODO Process attributes looking for src and language; create invocation
- // handler if parent element is a listener list
+ // Load the script engine manager
+ if (scriptEngineManager == null) {
+ scriptEngineManager = new javax.script.ScriptEngineManager();
+ scriptEngineManager.setBindings(new NamedObjectBindings());
+ }
+
+ // Process attributes looking for src and language
+ String src = null;
+ String language = null;
+ for (Attribute attribute : element.attributes) {
+ if (attribute.prefix != null) {
+ throw new SerializationException(WTKX_PREFIX + ":" + attribute.localName
+ + " is not a valid attribute.");
+ } else {
+ if (attribute.prefix != null) {
+ throw new SerializationException(attribute.prefix + ":" +
+ attribute.localName + " is not a valid" + " attribute for the "
+ + WTKX_PREFIX + ":" + SCRIPT_TAG + " tag.");
+ }
+
+ if (attribute.localName.equals(SCRIPT_SRC_ATTRIBUTE)) {
+ src = attribute.value;
+ } else if (attribute.localName.equals(SCRIPT_LANGUAGE_ATTRIBUTE)) {
+ language = attribute.value;
+ } else {
+ throw new SerializationException(attribute.localName + " is not a valid"
+ + " attribute for the " + WTKX_PREFIX + ":" + SCRIPT_TAG + " tag.");
+ }
+ }
+ }
+
+ Bindings bindings;
+ if (element.parent.value instanceof ListenerList<?>) {
+ // Don't pollute the engine namespace with the listener functions
+ bindings = new SimpleBindings();
+ } else {
+ bindings = scriptEngineManager.getBindings();
+ }
+
+ // Execute script
+ final ScriptEngine scriptEngine;
+
+ if (src != null) {
+ // The script is located in an external file
+ if (language != null) {
+ throw new SerializationException("Cannot combine " + SCRIPT_SRC_ATTRIBUTE
+ + " and " + SCRIPT_LANGUAGE_ATTRIBUTE + " in a "
+ + WTKX_PREFIX + ":" + SCRIPT_TAG + " tag.");
+ }
+
+ int i = src.lastIndexOf(".");
+ if (i == -1) {
+ throw new SerializationException("Cannot determine type of script \""
+ + src + "\".");
+ }
+
+ String extension = src.substring(i + 1);
+ scriptEngine = scriptEngineManager.getEngineByExtension(extension);
+
+ if (scriptEngine == null) {
+ throw new SerializationException("Unable to find scripting engine for "
+ + " extension " + extension + ".");
+ }
+
+ scriptEngine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
+
+ try {
+ URL scriptLocation;
+ if (src.charAt(0) == '/') {
+ ClassLoader classLoader = ThreadUtilities.getClassLoader();
+ scriptLocation = classLoader.getResource(src);
+ } else {
+ scriptLocation = new URL(location, src);
+ }
+
+ BufferedReader scriptReader = null;
+ try {
+ scriptReader = new BufferedReader(new InputStreamReader(scriptLocation.openStream()));
+ scriptEngine.eval(scriptReader);
+ } catch(ScriptException exception) {
+ throw new SerializationException(exception);
+ } finally {
+ if (scriptReader != null) {
+ scriptReader.close();
+ }
+ }
+ } catch (IOException exception) {
+ throw new SerializationException(exception);
+ }
+ } else if (language != null) {
+ // The script is inline
+ scriptEngine = scriptEngineManager.getEngineByName(language);
+
+ if (scriptEngine == null) {
+ throw new SerializationException("Unable to find scripting engine for "
+ + " language " + language + ".");
+ }
+
+ scriptEngine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
+
+ if (element.value != null) {
+ try {
+ scriptEngine.eval((String)element.value);
+ } catch (ScriptException exception) {
+ throw new SerializationException(exception);
+ }
+ }
+ } else {
+ throw new SerializationException("Either " + SCRIPT_SRC_ATTRIBUTE + " or "
+ + SCRIPT_LANGUAGE_ATTRIBUTE + " is required for the "
+ + WTKX_PREFIX + ":" + SCRIPT_TAG + " tag.");
+ }
+
+ if (element.parent.value instanceof ListenerList<?>) {
+ // Create an invocation handler for this listener
+ Class<?> listenerListClass = element.parent.value.getClass();
+
+ Method addMethod;
+ try {
+ addMethod = listenerListClass.getMethod("add",
+ new Class<?>[] {Object.class});
+ } catch (NoSuchMethodException exception) {
+ throw new RuntimeException(exception);
+ }
+
+ InvocationHandler handler = new InvocationHandler() {
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ Object result = null;
+ String methodName = method.getName();
+
+ Bindings bindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE);
+ if (bindings.containsKey(methodName)) {
+ Invocable invocable;
+ try {
+ invocable = (Invocable)scriptEngine;
+ } catch (ClassCastException exception) {
+ throw new SerializationException(exception);
+ }
+
+ result = invocable.invokeFunction(methodName, args);
+ }
+
+ return result;
+ }
+ };
+
+ // Create the listener and add it to the list
+ java.lang.reflect.Type[] genericInterfaces = listenerListClass.getGenericInterfaces();
+ Class<?> listenerClass = (Class<?>)genericInterfaces[0];
+
+ Object listener =
+ Proxy.newProxyInstance(ThreadUtilities.getClassLoader(),
+ new Class[]{listenerClass}, handler);
+
+ try {
+ addMethod.invoke(element.parent.value, new Object[] {listener});
+ } catch (IllegalAccessException exception) {
+ throw new SerializationException(exception);
+ } catch (InvocationTargetException exception) {
+ throw new SerializationException(exception);
+ }
+ }
+
break;
}
}
@@ -719,10 +886,12 @@
}
public Object put(String name, Object value) {
+ // TODO
throw new UnsupportedOperationException();
}
public Object remove(String name) {
+ // TODO
throw new UnsupportedOperationException();
}