You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by tv...@apache.org on 2009/05/11 22:34:16 UTC

svn commit: r773679 - in /incubator/pivot/trunk/wtk/src/pivot/wtkx: BindProcessor.java Bindable.java WTKXSerializer.java

Author: tvolkert
Date: Mon May 11 20:34:16 2009
New Revision: 773679

URL: http://svn.apache.org/viewvc?rev=773679&view=rev
Log:
Added getNamedObjects():Dictionary<String,Object> method to WTKXSerializer, and made getObjectByName() call into it.  Changed Bindable#bind overload to use this new concept and take a namedObjectsDictionaries parameter instead of a wtkxSerializers parameter; added compile():boolean to @Load annotation.  This is all in preparation for working compile-time WTKX loading

Modified:
    incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java
    incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java
    incubator/pivot/trunk/wtk/src/pivot/wtkx/WTKXSerializer.java

Modified: incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java?rev=773679&r1=773678&r2=773679&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java (original)
+++ incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java Mon May 11 20:34:16 2009
@@ -259,17 +259,19 @@
                 // creating the source code buffer
                 StringBuilder sourceCode = new StringBuilder("class _A {");
                 sourceCode.append("@Override ");
-                sourceCode.append("protected void bind(pivot.collections.Map<String,pivot.wtkx.WTKXSerializer> namedSerializers) {");
-                sourceCode.append("super.bind(namedSerializers);");
+                sourceCode.append("protected void bind(pivot.collections.Dictionary<String,");
+                sourceCode.append("pivot.collections.Dictionary<String, Object>> namedObjectsDictionaries) {");
+                sourceCode.append("super.bind(namedObjectsDictionaries);");
 
-                // Local variable declarations
                 sourceCode.append("pivot.wtkx.WTKXSerializer wtkxSerializer;");
                 sourceCode.append("Object object;");
-                sourceCode.append("java.net.URL location;");
-                sourceCode.append("java.util.Locale locale;");
-                sourceCode.append("pivot.util.Resources resources;");
 
                 if (loadGroups != null) {
+                    // Process WTKX loads in this class
+                    sourceCode.append("java.net.URL location;");
+                    sourceCode.append("java.util.Locale locale;");
+                    sourceCode.append("pivot.util.Resources resources;");
+
                     for (String loadFieldName : loadGroups) {
                         AnnotationDossier.LoadGroup loadGroup = loadGroups.get(loadFieldName);
                         JCVariableDecl loadField = loadGroup.loadField;
@@ -278,6 +280,7 @@
                         String resourceName = getAnnotationProperty(loadAnnotation, "name");
                         String baseName = getAnnotationProperty(loadAnnotation, "resources");
                         String language = getAnnotationProperty(loadAnnotation, "locale");
+                        //Boolean compile = getAnnotationProperty(loadAnnotation, "compile");
                         boolean defaultResources = (baseName == null);
 
                         if (DEBUG) {
@@ -302,7 +305,8 @@
                                 sourceCode.append(String.format("locale = new java.util.Locale(\"%s\");", language));
                             }
                             sourceCode.append("try {");
-                            sourceCode.append(String.format("resources = new pivot.util.Resources(%s, locale, \"UTF8\");",
+                            sourceCode.append(String.format
+                                ("resources = new pivot.util.Resources(%s, locale, \"UTF8\");",
                                 defaultResources ? (baseName + ".class.getName()") : ("\"" + baseName + "\"")));
                             sourceCode.append("} catch(java.io.IOException ex) {");
                             sourceCode.append("throw new pivot.wtkx.BindException(ex);");
@@ -330,8 +334,8 @@
 
                         // Public and protected fields get kept for subclasses
                         if ((loadField.mods.flags & (Flags.PUBLIC | Flags.PROTECTED)) != 0) {
-                            sourceCode.append(String.format("namedSerializers.put(\"%s\", wtkxSerializer);",
-                                loadFieldName));
+                            sourceCode.append(String.format
+                                ("namedObjectsDictionaries.put(\"%s\", wtkxSerializer.getNamedObjects());", loadFieldName));
                         }
 
                         // Bind the resource lookups to their corresponding fields
@@ -353,19 +357,25 @@
                                         bindName, classDeclaration.name.toString(), bindFieldName));
                                 }
 
-                                sourceCode.append(String.format("object = wtkxSerializer.getObjectByName(\"%s\");",
-                                    bindName));
-                                sourceCode.append("if (object == null) {");
-                                sourceCode.append(String.format("throw new pivot.wtkx.BindException(\"Element not found: %s.\");", bindName));
-                                sourceCode.append("}");
-                                sourceCode.append(String.format("%s = (%s)object;", bindFieldName,
-                                    bindField.vartype.toString()));
+                                sourceCode.append(String.format
+                                    ("object = wtkxSerializer.getObjectByName(\"%s\");", bindName));
+                                sourceCode.append
+                                    ("if (object == null) {");
+                                sourceCode.append(String.format
+                                    ("throw new pivot.wtkx.BindException(\"Element not found: %s.\");", bindName));
+                                sourceCode.append
+                                    ("}");
+                                sourceCode.append(String.format
+                                    ("%s = (%s)object;", bindFieldName, bindField.vartype.toString()));
                             }
                         }
                     }
                 }
 
                 if (strandedBindFields != null) {
+                    // Process binds to superclass-loaded fields
+                    sourceCode.append("pivot.collections.Dictionary<String, Object> namedObjects;");
+
                     for (JCVariableDecl bindField : strandedBindFields) {
                         String bindFieldName = bindField.name.toString();
                         JCAnnotation bindAnnotation = getBindAnnotation(bindField);
@@ -377,20 +387,26 @@
                             bindName = bindFieldName;
                         }
 
-                        sourceCode.append(String.format("wtkxSerializer = namedSerializers.get(\"%s\");",
-                            loadFieldName));
-
-                        sourceCode.append("if (wtkxSerializer == null) {");
-                        sourceCode.append(String.format("throw new pivot.wtkx.BindException(\"Property not found: %s.\");", loadFieldName));
-                        sourceCode.append("}");
+                        sourceCode.append(String.format
+                            ("namedObjects = namedObjectsDictionaries.get(\"%s\");", loadFieldName));
 
-                        sourceCode.append(String.format("object = wtkxSerializer.getObjectByName(\"%s\");",
-                            bindName));
-                        sourceCode.append("if (object == null) {");
-                        sourceCode.append(String.format("throw new pivot.wtkx.BindException(\"Element not found: %s.\");", bindName));
-                        sourceCode.append("}");
-                        sourceCode.append(String.format("%s = (%s)object;", bindFieldName,
-                            bindField.vartype.toString()));
+                        sourceCode.append
+                            ("if (namedObjects == null) {");
+                        sourceCode.append(String.format
+                            ("throw new pivot.wtkx.BindException(\"Property not found: %s.\");", loadFieldName));
+                        sourceCode.append
+                            ("}");
+
+                        sourceCode.append(String.format
+                            ("object = namedObjects.get(\"%s\");", bindName));
+                        sourceCode.append
+                            ("if (object == null) {");
+                        sourceCode.append(String.format
+                            ("throw new pivot.wtkx.BindException(\"Element not found: %s.\");", bindName));
+                        sourceCode.append
+                            ("}");
+                        sourceCode.append(String.format
+                            ("%s = (%s)object;", bindFieldName, bindField.vartype.toString()));
                     }
                 }
 
@@ -563,8 +579,9 @@
      * The value of the property, or <tt>null</tt> if it is not explicitly
      * set in the annotation
      */
-    private static String getAnnotationProperty(JCAnnotation annotation, String propertyName) {
-        String result = null;
+    @SuppressWarnings("unchecked")
+    private static <T> T getAnnotationProperty(JCAnnotation annotation, String propertyName) {
+        Object result = null;
 
         for (JCExpression arg : annotation.args) {
             JCAssign assign = (JCAssign)arg;
@@ -572,11 +589,11 @@
 
             if (key.name.contentEquals(propertyName)) {
                 JCLiteral value = (JCLiteral)assign.rhs;
-                result = (String)value.value;
+                result = value.getValue();
                 break;
             }
         }
 
-        return result;
+        return (T)result;
     }
 }

Modified: incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java?rev=773679&r1=773678&r2=773679&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java (original)
+++ incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java Mon May 11 20:34:16 2009
@@ -29,8 +29,8 @@
 import java.util.MissingResourceException;
 
 import pivot.collections.ArrayList;
+import pivot.collections.Dictionary;
 import pivot.collections.HashMap;
-import pivot.collections.Map;
 import pivot.serialization.SerializationException;
 import pivot.util.Resources;
 
@@ -67,19 +67,36 @@
         public String name();
 
         /**
-         * The base name of the resources to associate with the WTKX load
-         * (optional). The base name should be of the form defined by the
-         * {@link Resources} class. If unspecified, the WTKX load will be
-         * assumed to not use resource strings.
+         * The base name of the resources to associate with the WTKX load.
+         * The base name should be of the form defined by the {@link Resources}
+         * class. If unspecified, the WTKX load will be assumed to not use
+         * resource strings.
          */
         public String resources() default "\0";
 
         /**
-         * The locale with which to load the WTKX (optional). This should be a
-         * lowercase two-letter ISO-639 code. If unspecified, the user's
-         * default locale will be used.
+         * The locale with which to load the WTKX. This should be a lowercase
+         * two-letter ISO-639 code. If unspecified, the user's default locale
+         * will be used.
          */
         public String locale() default "\0";
+
+        /**
+         * Indicates whether the loaded WTKX should be compiled into the class
+         * or if it should be loaded at runtime via the <tt>WTKXSerializer</tt>
+         * class. If unspecified, the WTKX loading will be done at runtime.
+         * <p>
+         * <b>Note</b>: This option only has meaning when the annotations are
+         * processed during compilation using {@link BindProcessor}. Callers
+         * who choose to skip the annotation processing will always be using a
+         * runtime implementation of WTKX loading, and in such cases, the
+         * <tt>compile</tt> flag will be ignored.
+         * <p>
+         * Also note that if the loaded WTKX is compiled into the class, the
+         * WTKX resource may not be needed at runtime; in such cases, the
+         * caller may wish to exclude it from their JAR file.
+         */
+        public boolean compile() default false;
     }
 
     /**
@@ -103,8 +120,8 @@
         public String property();
 
         /**
-         * The name of the WTKX variable that references the element to bind
-         * (optional). It should be a valid <tt>wtkx:id</tt> from the loaded
+         * The name of the WTKX variable that references the element to bind.
+         * It should be a valid <tt>wtkx:id</tt> from the loaded
          * WTKX resource. If unspecified, the name of the annotated field will
          * be used.
          *
@@ -153,7 +170,7 @@
         for (int i = 0, n = typeHierarchy.getLength(); i < n; i++) {
             type = typeHierarchy.get(i);
             try {
-                bindOverload = type.getDeclaredMethod("bind", new Class<?>[] {Map.class});
+                bindOverload = type.getDeclaredMethod("bind", new Class<?>[] {Dictionary.class});
                 break;
             } catch(NoSuchMethodException exception) {
                 // No-op
@@ -306,8 +323,9 @@
             }
         } else {
             // Invoke the bind overload
-            HashMap<String, WTKXSerializer> namedSerializers = new HashMap<String, WTKXSerializer>();
-            bind(namedSerializers);
+            HashMap<String, Dictionary<String, Object>> namedObjectsDictionaries =
+                new HashMap<String, Dictionary<String, Object>>();
+            bind(namedObjectsDictionaries);
         }
     }
 
@@ -316,7 +334,7 @@
      * override. It exists to support {@link BindProcessor}. Dealing directly
      * with this method in any way may yield unpredictable behavior.
      */
-    protected void bind(Map<String, WTKXSerializer> namedSerializers) {
+    protected void bind(Dictionary<String, Dictionary<String, Object>> namedObjectsDictionaries) {
         // No-op
     }
 }

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=773679&r1=773678&r2=773679&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/pivot/wtkx/WTKXSerializer.java (original)
+++ incubator/pivot/trunk/wtk/src/pivot/wtkx/WTKXSerializer.java Mon May 11 20:34:16 2009
@@ -92,15 +92,120 @@
         }
     }
 
+    /**
+     * Dictionary used for named object lookup.
+     *
+     * @author tvolkert
+     */
+    private class NamedObjectsDictionary implements Dictionary<String, Object> {
+        /**
+         * Retrieves a named object.
+         *
+         * @param name
+         * The name of the object, relative to this loader. The values's name
+         * is the concatentation of its parent namespaces and its ID, separated
+         * by periods (e.g. "foo.bar.baz").
+         *
+         * @return
+         * The named object, or <tt>null</tt> if an object with the given name
+         * does not exist.
+         *
+         * @author gbrown
+         */
+        public Object get(String key) {
+            if (key == null) {
+                throw new IllegalArgumentException("key is null.");
+            }
+
+            Object object = null;
+            WTKXSerializer serializer = WTKXSerializer.this;
+            String[] namespacePath = key.split("\\.");
+
+            int i = 0;
+            int n = namespacePath.length - 1;
+            while (i < n && serializer != null) {
+                String namespace = namespacePath[i++];
+                serializer = serializer.includeSerializers.get(namespace);
+            }
+
+            if (serializer != null) {
+                object = serializer.getObjectByID(namespacePath[i]);
+            }
+
+            return object;
+        }
+
+        public Object put(String key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        public Object remove(String key) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean containsKey(String key) {
+            if (key == null) {
+                throw new IllegalArgumentException("key is null.");
+            }
+
+            boolean result = false;
+            WTKXSerializer serializer = WTKXSerializer.this;
+            String[] namespacePath = key.split("\\.");
+
+            int i = 0;
+            int n = namespacePath.length - 1;
+            while (i < n && serializer != null) {
+                String namespace = namespacePath[i++];
+                serializer = serializer.includeSerializers.get(namespace);
+            }
+
+            if (serializer != null) {
+                if (serializer.namedObjects.containsKey(key)) {
+                    result = true;
+                } else if (serializer.scriptEngineBindings != null) {
+                    result = serializer.scriptEngineBindings.containsKey(key);
+                }
+            }
+
+            return result;
+        }
+
+        @SuppressWarnings("unchecked")
+        public boolean isEmpty() {
+            boolean empty = namedObjects.isEmpty();
+
+            if (empty && scriptEngineBindings != null) {
+                // Check for script bindings
+                empty = scriptEngineBindings.isEmpty();
+            }
+
+            if (empty) {
+                // Check include serializers
+                for (String namespace : includeSerializers) {
+                    WTKXSerializer includeSerializer = includeSerializers.get(namespace);
+                    if (!includeSerializer.getNamedObjects().isEmpty()) {
+                        empty = false;
+                        break;
+                    }
+                }
+            }
+
+            return empty;
+        }
+    }
+
     private URL location = null;
     private Resources resources = null;
 
     private HashMap<String, Object> namedObjects = new HashMap<String, Object>();
     private HashMap<String, WTKXSerializer> includeSerializers = new HashMap<String, WTKXSerializer>();
 
+    private NamedObjectsDictionary namedObjectsDictionary = new NamedObjectsDictionary();
+
     private XMLInputFactory xmlInputFactory;
     private Object scriptEngineManager;
     private Class<?> scriptEngineManagerClass;
+    private java.util.Map<String, Object> scriptEngineBindings;
 
     public static final char URL_PREFIX = '@';
     public static final char RESOURCE_KEY_PREFIX = '%';
@@ -123,6 +228,7 @@
         this(null);
     }
 
+    @SuppressWarnings("unchecked")
     public WTKXSerializer(Resources resources) {
         this.resources = resources;
 
@@ -130,11 +236,16 @@
         xmlInputFactory.setProperty("javax.xml.stream.isCoalescing", true);
 
         try {
-        	scriptEngineManagerClass = Class.forName("javax.script.ScriptEngineManager");
-        	scriptEngineManager = scriptEngineManagerClass.newInstance();
+            scriptEngineManagerClass = Class.forName("javax.script.ScriptEngineManager");
+            scriptEngineManager = scriptEngineManagerClass.newInstance();
+            Method getBindingsMethod = scriptEngineManagerClass.getMethod
+                ("getBindings", new Class<?>[] {});
+            scriptEngineBindings = (java.util.Map<String, Object>)
+                getBindingsMethod.invoke(scriptEngineManager, new Object[] {});
         } catch(Exception exception) {
-        	scriptEngineManagerClass = null;
-        	scriptEngineManager = null;
+            scriptEngineManagerClass = null;
+            scriptEngineManager = null;
+            scriptEngineBindings = null;
         }
     }
 
@@ -364,12 +475,8 @@
                                 	Method evalMethod = scriptEngine.getClass().getMethod("eval",
                                 			new Class<?>[] {Reader.class, bindingsClass});
 
-                                	Method getBindingsMethod =
-                                		scriptEngineManagerClass.getMethod("getBindings", new Class<?>[] {});
-
-                                	Object bindings = getBindingsMethod.invoke(scriptEngineManager, new Object[] {});
                                 	Reader scriptReader = new BufferedReader(new InputStreamReader(scriptLocation.openStream()));
-                                	evalMethod.invoke(scriptEngine, new Object[] {scriptReader, bindings});
+                                	evalMethod.invoke(scriptEngine, new Object[] {scriptReader, scriptEngineBindings});
                                 } catch(Exception exception) {
                                 	throw new SerializationException(exception);
                                 }
@@ -739,28 +846,22 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T getObjectByName(String name) {
-        if (name == null) {
-            throw new IllegalArgumentException("name is null.");
-        }
-
-        Object object = null;
-        WTKXSerializer serializer = this;
-        String[] namespacePath = name.split("\\.");
-
-        int i = 0;
-        int n = namespacePath.length - 1;
-        while (i < n && serializer != null) {
-            String namespace = namespacePath[i++];
-            serializer = serializer.includeSerializers.get(namespace);
-        }
-
-        if (serializer != null) {
-        	object = serializer.getObjectByID(namespacePath[i]);
-        }
-
+        Object object = namedObjectsDictionary.get(name);
         return (T)object;
     }
 
+    /**
+     * Retrieves the named objects dictionary. The names are relative to this
+     * loader and can reference objects located in nested includes by using
+     * period-separated path strings (e.g. <tt>"foo.bar.baz"</tt>).
+     *
+     * @return
+     * The read-only named objects dictionary.
+     */
+    public Dictionary<String, Object> getNamedObjects() {
+        return namedObjectsDictionary;
+    }
+
     private Object getObjectByID(String id) {
     	Object object = null;