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/03/26 00:12:17 UTC

svn commit: r758461 [47/47] - in /incubator/pivot/branches: ./ 1.1/ 1.1/charts-test/ 1.1/charts-test/src/ 1.1/charts-test/src/pivot/ 1.1/charts-test/src/pivot/charts/ 1.1/charts-test/src/pivot/charts/test/ 1.1/charts/ 1.1/charts/lib/ 1.1/charts/src/ 1....

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtkx/WTKXSerializer.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtkx/WTKXSerializer.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtkx/WTKXSerializer.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtkx/WTKXSerializer.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,903 @@
+/*
+ * Copyright (c) 2009 VMware, Inc.
+ *
+ * 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 pivot.wtkx;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamException;
+
+import pivot.beans.BeanDictionary;
+import pivot.beans.PropertyNotFoundException;
+import pivot.collections.ArrayList;
+import pivot.collections.Dictionary;
+import pivot.collections.HashMap;
+import pivot.collections.List;
+import pivot.collections.Sequence;
+import pivot.serialization.Serializer;
+import pivot.serialization.SerializationException;
+import pivot.util.ListenerList;
+import pivot.util.Resources;
+
+/**
+ * Loads an object hierarchy from an XML document.
+ *
+ * @author gbrown
+ */
+public class WTKXSerializer implements Serializer<Object> {
+    private static class Element  {
+        public enum Type {
+            INSTANCE,
+            INCLUDE,
+            SCRIPT,
+            READ_ONLY_PROPERTY,
+            WRITABLE_PROPERTY
+        }
+
+        public final Element parent;
+        public final String tagName;
+        public final Type type;
+        public final List<Attribute> attributes;
+
+        public Object value;
+
+        public Element(Element parent, String tagName, Type type, List<Attribute> attributes, Object value) {
+            this.parent = parent;
+            this.tagName = tagName;
+            this.type = type;
+            this.attributes = attributes;
+            this.value = value;
+        }
+    }
+
+    private static class Attribute {
+        public final String namespaceURI;
+        public final String prefix;
+        public final String localName;
+        public final String value;
+
+        public Attribute(String namespaceURI, String prefix, String localName, String value) {
+            this.namespaceURI = namespaceURI;
+            this.prefix = prefix;
+            this.localName = localName;
+            this.value = value;
+        }
+    }
+
+    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 XMLInputFactory xmlInputFactory;
+    private Object scriptEngineManager;
+    private Class<?> scriptEngineManagerClass;
+
+    public static final char URL_PREFIX = '@';
+    public static final char RESOURCE_KEY_PREFIX = '%';
+    public static final char OBJECT_REFERENCE_PREFIX = '$';
+
+    public static final String WTKX_PREFIX = "wtkx";
+    public static final String ID_ATTRIBUTE = "id";
+
+    public static final String INCLUDE_TAG = "include";
+    public static final String INCLUDE_SRC_ATTRIBUTE = "src";
+    public static final String INCLUDE_NAMESPACE_ATTRIBUTE = "namespace";
+    public static final String INCLUDE_RESOURCES_ATTRIBUTE = "resources";
+
+    public static final String SCRIPT_TAG = "script";
+    public static final String SCRIPT_SRC_ATTRIBUTE = "src";
+
+    public static final String MIME_TYPE = "application/wtkx";
+
+    public WTKXSerializer() {
+        this(null);
+    }
+
+    public WTKXSerializer(Resources resources) {
+        this.resources = resources;
+
+        xmlInputFactory = XMLInputFactory.newInstance();
+        xmlInputFactory.setProperty("javax.xml.stream.isCoalescing", true);
+
+        try {
+        	scriptEngineManagerClass = Class.forName("javax.script.ScriptEngineManager");
+        	scriptEngineManager = scriptEngineManagerClass.newInstance();
+        } catch(Exception exception) {
+        	scriptEngineManagerClass = null;
+        	scriptEngineManager = null;
+        }
+    }
+
+    public Resources getResources() {
+        return resources;
+    }
+
+    public Object readObject(String resourceName) throws IOException,
+        SerializationException {
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+        URL location = classLoader.getResource(resourceName);
+
+        if (location == null) {
+            throw new SerializationException("Could not find resource named \""
+                + resourceName + "\".");
+        }
+
+        return readObject(location);
+    }
+
+    public Object readObject(URL location) throws IOException, SerializationException {
+        this.location = location;
+        return readObject(new BufferedInputStream(location.openStream()));
+    }
+
+    @SuppressWarnings("unchecked")
+    public Object readObject(InputStream inputStream) throws IOException,
+        SerializationException {
+        Object object = null;
+
+        // Clear any previous named objects and include serializers
+        namedObjects.clear();
+        includeSerializers.clear();
+
+        // Parse the XML stream
+        Element element = null;
+        try {
+            XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(inputStream);
+
+            while (reader.hasNext()) {
+                int event = reader.next();
+
+                switch (event) {
+                    case XMLStreamConstants.CHARACTERS: {
+                        if (!reader.isWhiteSpace()) {
+                            String text = reader.getText();
+
+                            if (text.length() > 0) {
+                                switch (element.type) {
+                                    case INSTANCE: {
+                                        if (element.value instanceof Sequence) {
+                                            Sequence<Object> sequence = (Sequence<Object>)element.value;
+
+                                            try {
+                                                Method addMethod = sequence.getClass().getMethod("add",
+                                                    new Class<?>[] {String.class});
+                                                addMethod.invoke(sequence, new Object[] {text});
+                                            } catch(NoSuchMethodException exception) {
+                                                throw new SerializationException("Text content cannot be added to "
+                                                    + sequence.getClass().getName() + ".", exception);
+                                            } catch(InvocationTargetException exception) {
+                                                throw new SerializationException(exception);
+                                            } catch(IllegalAccessException exception) {
+                                                throw new SerializationException(exception);
+                                            }
+                                        }
+
+                                        break;
+                                    }
+
+                                    case WRITABLE_PROPERTY: {
+                                        element.value = text;
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+
+                        break;
+                    }
+
+                    case XMLStreamConstants.START_ELEMENT: {
+                        String namespaceURI = reader.getNamespaceURI();
+                        String prefix = reader.getPrefix();
+                        String localName = reader.getLocalName();
+
+                        String id = null;
+
+                        if (prefix != null
+                            && prefix.equals(WTKX_PREFIX)) {
+                            if (element == null) {
+                                throw new SerializationException(prefix + ":" + localName
+                                    + " is not a valid root element.");
+                            }
+
+                            if (localName.equals(INCLUDE_TAG)) {
+                                // The element represents an include
+                                String src = null;
+                                String namespace = null;
+
+                                Resources includeResources = resources;
+
+                                ArrayList<Attribute> attributes = new ArrayList<Attribute>();
+
+                                for (int i = 0, n = reader.getAttributeCount(); i < n; i++) {
+                                    String attributeNamespaceURI = reader.getAttributeNamespace(i);
+                                    if (attributeNamespaceURI == null) {
+                                        attributeNamespaceURI = reader.getNamespaceURI("");
+                                    }
+
+                                    String attributePrefix = reader.getAttributePrefix(i);
+                                    String attributeLocalName = reader.getAttributeLocalName(i);
+                                    String attributeValue = reader.getAttributeValue(i);
+
+                                    if (attributePrefix != null
+                                        && attributePrefix.equals(WTKX_PREFIX)) {
+                                        if (attributeLocalName.equals(ID_ATTRIBUTE)) {
+                                            id = attributeValue;
+                                        }
+                                    } else {
+                                        if (attributeLocalName.equals(INCLUDE_SRC_ATTRIBUTE)) {
+                                            src = attributeValue;
+                                        } else if (attributeLocalName.equals(INCLUDE_NAMESPACE_ATTRIBUTE)) {
+                                            namespace = attributeValue;
+                                        } else if (attributeLocalName.equals(INCLUDE_RESOURCES_ATTRIBUTE)) {
+                                            includeResources = new Resources(attributeValue);
+                                        } else {
+                                            attributes.add(new Attribute(attributeNamespaceURI,
+                                                attributePrefix, attributeLocalName, attributeValue));
+                                        }
+                                    }
+                                }
+
+                                if (src == null) {
+                                    throw new SerializationException(INCLUDE_SRC_ATTRIBUTE
+                                        + " attribute is required for " + WTKX_PREFIX + ":" + INCLUDE_TAG
+                                        + " tag.");
+                                }
+
+                                // Process the include
+                                WTKXSerializer serializer = new WTKXSerializer(includeResources);
+                                if (namespace != null) {
+                                    includeSerializers.put(namespace, serializer);
+                                }
+
+                                Object value;
+                                if (src.charAt(0) == '/') {
+                                    value = serializer.readObject(src.substring(1));
+                                } else {
+                                    value = serializer.readObject(new URL(location, src));
+                                }
+
+                                element = new Element(element, localName, Element.Type.INCLUDE, attributes, value);
+                            } else if (localName.equals(SCRIPT_TAG)) {
+                            	if (scriptEngineManagerClass == null) {
+                            		throw new SerializationException("Scripting is not supported on this platform.");
+                            	}
+
+                                // The element represents a script
+                                String src = null;
+
+                                for (int i = 0, n = reader.getAttributeCount(); i < n; i++) {
+                                    String attributeLocalName = reader.getAttributeLocalName(i);
+                                    String attributeValue = reader.getAttributeValue(i);
+
+                                    if (attributeLocalName.equals(SCRIPT_SRC_ATTRIBUTE)) {
+                                        src = attributeValue;
+                                    } else {
+                                    	throw new SerializationException(attributeLocalName + " is not a valid "
+                                			+ " attribute for the " + WTKX_PREFIX + ":" + SCRIPT_TAG + ".");
+                                    }
+                                }
+
+                                if (src == null) {
+                                    throw new SerializationException(INCLUDE_SRC_ATTRIBUTE
+                                        + " attribute is required for " + 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);
+
+                            	Object scriptEngine = null;
+                            	try {
+                                	Method getEngineByExtensionMethod =
+                                		scriptEngineManagerClass.getMethod("getEngineByExtension", new Class<?>[] {String.class});
+
+                                    scriptEngine = getEngineByExtensionMethod.invoke(scriptEngineManager, new Object[] {extension});
+                            	} catch(Exception exception) {
+                            		throw new RuntimeException(exception);
+                            	}
+
+                            	if (scriptEngine == null) {
+                                	throw new SerializationException("Unable to find scripting engine for "
+                            			+ " extension " + extension + ".");
+                                }
+
+                                try {
+                                    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+                                	URL scriptLocation;
+
+                                	if (src.charAt(0) == '/') {
+                                		scriptLocation = classLoader.getResource(src);
+                                    } else {
+                                    	scriptLocation = new URL(location, src);
+                                    }
+
+                                	Class<?> bindingsClass = Class.forName("javax.script.Bindings");
+                                	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});
+                                } catch(Exception exception) {
+                                	throw new SerializationException(exception);
+                                }
+
+                                element = new Element(element, localName, Element.Type.SCRIPT, null, null);
+                            } else {
+                                throw new SerializationException(prefix + ":" + localName
+                                    + " is not a valid tag.");
+                            }
+                        } else {
+                            ArrayList<Attribute> attributes = new ArrayList<Attribute>();
+
+                            for (int i = 0, n = reader.getAttributeCount(); i < n; i++) {
+                                String attributeNamespaceURI = reader.getAttributeNamespace(i);
+                                if (attributeNamespaceURI == null) {
+                                    attributeNamespaceURI = reader.getNamespaceURI("");
+                                }
+
+                                String attributePrefix = reader.getAttributePrefix(i);
+                                String attributeLocalName = reader.getAttributeLocalName(i);
+                                String attributeValue = reader.getAttributeValue(i);
+
+                                if (attributePrefix != null
+                                    && attributePrefix.equals(WTKX_PREFIX)) {
+                                    if (attributeLocalName.equals(ID_ATTRIBUTE)) {
+                                        id = attributeValue;
+                                    }
+                                } else {
+                                    attributes.add(new Attribute(attributeNamespaceURI,
+                                        attributePrefix, attributeLocalName, attributeValue));
+                                }
+                            }
+
+                            if (Character.isUpperCase(localName.charAt(0))) {
+                                // The element represents a typed object
+                                if (namespaceURI == null) {
+                                    throw new SerializationException("No XML namespace specified for "
+                                        + localName + " tag.");
+                                }
+
+                                String className = namespaceURI + "." + localName.replace('.', '$');
+
+                                try {
+                                    Class<?> type = Class.forName(className);
+                                    element = new Element(element, localName, Element.Type.INSTANCE, attributes, type.newInstance());
+                                } catch(Exception exception) {
+                                    throw new SerializationException(exception);
+                                }
+                            } else {
+                                // This element represents a property
+                                if (element == null) {
+                                    throw new SerializationException("Root node must represent a typed object.");
+                                }
+
+                                BeanDictionary propertyDictionary = new BeanDictionary(element.value);
+
+                                if (propertyDictionary.isReadOnly(localName)) {
+                                    Object value = propertyDictionary.get(localName);
+                                    assert (value != null) : "Read-only properties cannot be null.";
+                                    element = new Element(element, localName, Element.Type.READ_ONLY_PROPERTY, attributes, value);
+                                } else {
+                                    if (attributes.getLength() > 0) {
+                                        throw new SerializationException("Writable property elements cannot have attributes.");
+                                    }
+
+                                    element = new Element(element, localName, Element.Type.WRITABLE_PROPERTY, null, null);
+                                }
+                            }
+                        }
+
+                        switch (element.type) {
+                            case INCLUDE:
+                            case INSTANCE: {
+                                // If the element's parent is a sequence or a listener list, add
+                                // the element value to it
+                                if (element.parent != null) {
+                                    if (element.parent.value instanceof Sequence) {
+                                        Sequence<Object> sequence = (Sequence<Object>)element.parent.value;
+                                        sequence.add(element.value);
+                                    } else {
+                                        if (element.parent.value instanceof ListenerList) {
+                                            ListenerList<Object> listenerList = (ListenerList<Object>)element.parent.value;
+                                            listenerList.add(element.value);
+                                        }
+                                    }
+                                }
+
+                                // If an ID was specified, add the value to the named object map
+                                if (id != null) {
+                                    namedObjects.put(id, element.value);
+
+                                    if (scriptEngineManager != null) {
+                                    	try {
+	                                    	Method putMethod = scriptEngineManagerClass.getMethod("put",
+                                    			new Class<?>[] {String.class, Object.class});
+	                                    	putMethod.invoke(scriptEngineManager, new Object[] {id, namedObjects.get(id)});
+                                    	} catch(Exception exception) {
+                                    		throw new RuntimeException(exception);
+                                    	}
+                                	}
+                                }
+
+                                break;
+                            }
+                        }
+
+                        break;
+                    }
+
+                    case XMLStreamConstants.END_ELEMENT: {
+                        String localName = reader.getLocalName();
+
+                        switch (element.type) {
+                            case WRITABLE_PROPERTY: {
+                                BeanDictionary propertyDictionary = new BeanDictionary(element.parent.value);
+                                propertyDictionary.put(localName, element.value);
+                                break;
+                            }
+
+                            case SCRIPT: {
+                            	break;
+                            }
+
+                            default: {
+                                if (element.value instanceof Dictionary) {
+                                    // The element is an untyped object
+                                    Dictionary<String, Object> dictionary = (Dictionary<String, Object>)element.value;
+
+                                    for (Attribute attribute : element.attributes) {
+                                        if (Character.isUpperCase(attribute.localName.charAt(0))) {
+                                            throw new SerializationException("Static setters are only supported for typed instances.");
+                                        }
+
+                                        // Resolve and apply the attribute
+                                        dictionary.put(attribute.localName, resolve(attribute.value, null));
+                                    }
+                                } else {
+                                    // The element represents a typed object; apply the attributes
+                                    BeanDictionary valueDictionary = new BeanDictionary(element.value);
+
+                                    for (Attribute attribute : element.attributes) {
+                                        if (Character.isUpperCase(attribute.localName.charAt(0))) {
+                                            // The property represents an attached value
+                                            setStaticProperty(attribute, element.value);
+                                        } else {
+                                            Class<?> type = valueDictionary.getType(attribute.localName);
+
+                                            if (type != null
+                                                && ListenerList.class.isAssignableFrom(type)) {
+                                                // The property represents a listener list
+                                                ListenerList<Object> listenerList = (ListenerList<Object>)valueDictionary.get(attribute.localName);
+
+                                                // The attribute value is a comma-separated list of listener IDs
+                                                String[] listenerIDs = attribute.value.split(",");
+
+                                                for (int i = 0, n = listenerIDs.length; i < n; i++) {
+                                                    String listenerID = listenerIDs[i].trim();
+
+                                                    if (listenerID.length() > 0) {
+                                                        listenerID = listenerID.substring(1);
+
+                                                        if (listenerID.length() > 0) {
+                                                            listenerList.add(getObjectByID(listenerID));
+                                                        }
+                                                    }
+                                                }
+                                            } else {
+                                                valueDictionary.put(attribute.localName,
+                                                    resolve(attribute.value, valueDictionary.getType(attribute.localName)));
+                                            }
+                                        }
+                                    }
+                                }
+
+                                // If the parent element is a writable property, set this as its value; it
+                                // will be applied later in the parent's closing tag
+                                if (element.parent != null
+                                    && element.parent.type == Element.Type.WRITABLE_PROPERTY) {
+                                    element.parent.value = element.value;
+                                }
+                            }
+                        }
+
+                        // If this is the top of the stack, return this element's value;
+                        // otherwise, move up the stack
+                        if (element.parent == null) {
+                            object = element.value;
+                        } else {
+                            element = element.parent;
+                        }
+
+                        break;
+                    }
+                }
+            }
+
+            reader.close();
+        } catch(XMLStreamException exception) {
+            throw new SerializationException(exception);
+        }
+
+        // Clear the location so the previous value won't be re-used in a
+        // subsequent call to this method
+        location = null;
+
+        return object;
+    }
+
+    public void writeObject(Object object, OutputStream outputStream) throws IOException,
+        SerializationException {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getMIMEType(Object object) {
+        return MIME_TYPE;
+    }
+
+    /**
+     * Retrieves a included serializer by its namespace.
+     *
+     * @param name
+     * The name of the serializer, relative to this loader. The values's name
+     * is the concatentation of its parent namespaces and its namespace,
+     * separated by periods (e.g. "foo.bar.baz").
+     *
+     * @return The named serializer, or <tt>null</tt> if a serializer with the
+     * given name does not exist.
+     */
+    public WTKXSerializer getSerializerByName(String name) {
+        if (name == null) {
+            throw new IllegalArgumentException("name is null.");
+        }
+
+        WTKXSerializer serializer = this;
+        String[] namespacePath = name.split("\\.");
+
+        int i = 0;
+        int n = namespacePath.length;
+        while (i < n && serializer != null) {
+            String namespace = namespacePath[i++];
+            serializer = serializer.includeSerializers.get(namespace);
+        }
+
+        return serializer;
+    }
+
+    /**
+     * 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.
+     */
+    public Object 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]);
+        }
+
+        return object;
+    }
+
+    private Object getObjectByID(String id) {
+    	Object object = null;
+
+    	if (namedObjects.containsKey(id)) {
+    		object = namedObjects.get(id);
+    	} else {
+    		if (scriptEngineManager != null) {
+            	try {
+                	Method getMethod = scriptEngineManagerClass.getMethod("get", new Class<?>[] {String.class});
+                	object = getMethod.invoke(scriptEngineManager, new Object[] {id});
+            	} catch(Exception exception) {
+            		throw new RuntimeException(exception);
+            	}
+    		}
+    	}
+
+    	return object;
+    }
+
+    /**
+     * Resolves an attribute value. If the property type is a primitive or
+     * primitive wrapper, converts the string value to the primitive type.
+     * Otherwise, resolves the value as either a URL, resource value, or
+     * object reference, depending on the value's prefix. If the value can't
+     * or doesn't need to be resolved, the original attribute value is
+     * returned.
+     *
+     * @param attributeValue
+     * The attribute value to resolve.
+     *
+     * @param propertyType
+     * The property type, or <tt>null</tt> if the type is not known.
+     *
+     * @return
+     * The resolved value.
+     */
+    private Object resolve(String attributeValue, Class<?> propertyType)
+        throws MalformedURLException {
+        Object resolvedValue = null;
+
+        if (propertyType == Boolean.class
+            || propertyType == Boolean.TYPE) {
+            try {
+                resolvedValue = Boolean.parseBoolean(attributeValue);
+            } catch(NumberFormatException exception) {
+                resolvedValue = attributeValue;
+            }
+        } else if (propertyType == Character.class
+            || propertyType == Character.TYPE) {
+            if (attributeValue.length() > 0) {
+                resolvedValue = attributeValue.charAt(0);
+            }
+        } else if (propertyType == Byte.class
+            || propertyType == Byte.TYPE) {
+            try {
+                resolvedValue = Byte.parseByte(attributeValue);
+            } catch(NumberFormatException exception) {
+                resolvedValue = attributeValue;
+            }
+        } else if (propertyType == Short.class
+            || propertyType == Short.TYPE) {
+            try {
+                resolvedValue = Short.parseShort(attributeValue);
+            } catch(NumberFormatException exception) {
+                resolvedValue = attributeValue;
+            }
+        } else if (propertyType == Integer.class
+            || propertyType == Integer.TYPE) {
+            try {
+                resolvedValue = Integer.parseInt(attributeValue);
+            } catch(NumberFormatException exception) {
+                resolvedValue = attributeValue;
+            }
+        } else if (propertyType == Long.class
+            || propertyType == Long.TYPE) {
+            try {
+                resolvedValue = Long.parseLong(attributeValue);
+            } catch(NumberFormatException exception) {
+                resolvedValue = attributeValue;
+            }
+        } else if (propertyType == Float.class
+            || propertyType == Float.TYPE) {
+            try {
+                resolvedValue = Float.parseFloat(attributeValue);
+            } catch(NumberFormatException exception) {
+                resolvedValue = attributeValue;
+            }
+        } else if (propertyType == Double.class
+            || propertyType == Double.TYPE) {
+            try {
+                resolvedValue = Double.parseDouble(attributeValue);
+            } catch(NumberFormatException exception) {
+                resolvedValue = attributeValue;
+            }
+        } else {
+            if (attributeValue.charAt(0) == URL_PREFIX) {
+                if (attributeValue.length() > 1) {
+                    if (attributeValue.charAt(1) == URL_PREFIX) {
+                        resolvedValue = attributeValue.substring(1);
+                    } else {
+                        if (location == null) {
+                            throw new IllegalStateException("Base location is undefined.");
+                        }
+
+                        resolvedValue = new URL(location, attributeValue.substring(1));
+                    }
+                }
+            } else if (attributeValue.charAt(0) == RESOURCE_KEY_PREFIX) {
+                if (attributeValue.length() > 1) {
+                    if (attributeValue.charAt(1) == RESOURCE_KEY_PREFIX) {
+                        resolvedValue = attributeValue.substring(1);
+                    } else {
+                        if (resources == null) {
+                            throw new IllegalStateException("Resource dictionary is undefined.");
+                        }
+
+                        resolvedValue = resources.get(attributeValue.substring(1));
+                    }
+                }
+            } else if (attributeValue.charAt(0) == OBJECT_REFERENCE_PREFIX) {
+                if (attributeValue.length() > 1) {
+                    if (attributeValue.charAt(1) == OBJECT_REFERENCE_PREFIX) {
+                        resolvedValue = attributeValue.substring(1);
+                    } else {
+                        resolvedValue = getObjectByID(attributeValue.substring(1));
+                    }
+                }
+            } else {
+                resolvedValue = attributeValue;
+            }
+        }
+
+        return resolvedValue;
+    }
+
+    /**
+     * Invokes a static property setter.
+     *
+     * @param attribute
+     * The attribute whose corresponding static setter is to be invoked.
+     *
+     * @param object
+     * The object on which to invoke the static setter.
+     */
+    private void setStaticProperty(Attribute attribute, Object object)
+        throws SerializationException, MalformedURLException {
+        String propertyName =
+            attribute.localName.substring(attribute.localName.lastIndexOf(".") + 1);
+        propertyName = Character.toUpperCase(propertyName.charAt(0)) +
+            propertyName.substring(1);
+
+        String propertyClassName = attribute.namespaceURI + "."
+            + attribute.localName.substring(0, attribute.localName.length()
+                - (propertyName.length() + 1));
+
+        Class<?> propertyClass = null;
+        try {
+            propertyClass = Class.forName(propertyClassName);
+        } catch(ClassNotFoundException exception) {
+            throw new SerializationException(exception);
+        }
+
+        Class<?> objectType = object.getClass();
+
+        // Determine the property type from the getter method
+        Method getterMethod = getStaticGetterMethod(propertyClass, propertyName, objectType);
+        if (getterMethod == null) {
+            throw new PropertyNotFoundException("Static property \"" + attribute
+                + "\" does not exist.");
+        }
+
+        // Resolve the attribute value
+        Class<?> propertyType = getterMethod.getReturnType();
+        Object propertyValue = resolve(attribute.value, propertyType);
+        Class<?> propertyValueType = (propertyValue == null) ?
+            getterMethod.getReturnType() : propertyValue.getClass();
+
+        Method setterMethod = getStaticSetterMethod(propertyClass, propertyName,
+            objectType, propertyValueType);
+
+        if (setterMethod == null) {
+            throw new SerializationException("Unable to determine type for "
+                + " static property \"" + attribute + "\".");
+        }
+
+        // Invoke the setter
+        try {
+            setterMethod.invoke(null, new Object[] {object, propertyValue});
+        } catch(Exception exception) {
+            throw new SerializationException(exception);
+        }
+    }
+
+    private Method getStaticGetterMethod(Class<?> propertyClass, String propertyName,
+        Class<?> objectType) {
+        Method method = null;
+
+        if (objectType != null) {
+            try {
+                method = propertyClass.getMethod(BeanDictionary.GET_PREFIX
+                    + propertyName, new Class<?>[] {objectType});
+            } catch(NoSuchMethodException exception) {
+                // No-op
+            }
+
+            if (method == null) {
+                try {
+                    method = propertyClass.getMethod(BeanDictionary.IS_PREFIX
+                        + propertyName, new Class<?>[] {objectType});
+                } catch(NoSuchMethodException exception) {
+                    // No-op
+                }
+            }
+
+            if (method == null) {
+                method = getStaticGetterMethod(propertyClass, propertyName,
+                    objectType.getSuperclass());
+            }
+        }
+
+        return method;
+    }
+
+    private Method getStaticSetterMethod(Class<?> propertyClass, String propertyName,
+        Class<?> objectType, Class<?> propertyValueType) {
+        Method method = null;
+
+        if (objectType != null) {
+            final String methodName = BeanDictionary.SET_PREFIX + propertyName;
+
+            try {
+                method = propertyClass.getMethod(methodName,
+                    new Class<?>[] {objectType, propertyValueType});
+            } catch(NoSuchMethodException exception) {
+                // No-op
+            }
+
+            if (method == null) {
+                // If value type is a primitive wrapper, look for a method
+                // signature with the corresponding primitive type
+                try {
+                    Field primitiveTypeField = propertyValueType.getField("TYPE");
+                    Class<?> primitivePropertyValueType = (Class<?>)primitiveTypeField.get(null);
+
+                    try {
+                        method = propertyClass.getMethod(methodName,
+                            new Class<?>[] {objectType, primitivePropertyValueType});
+                    } catch(NoSuchMethodException exception) {
+                        // No-op
+                    }
+                } catch(NoSuchFieldException exception) {
+                    // No-op; not a wrapper type
+                } catch(IllegalAccessException exception) {
+                    // No-op; not a wrapper type
+                }
+            }
+
+            if (method == null) {
+                method = getStaticSetterMethod(propertyClass, propertyName,
+                    objectType.getSuperclass(), propertyValueType);
+            }
+        }
+
+        return method;
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtkx/package.html
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtkx/package.html?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtkx/package.html (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtkx/package.html Wed Mar 25 23:08:38 2009
@@ -0,0 +1,6 @@
+<html>
+<head></head>
+<body>
+<p>Provides support for loading WTK components and other classes from XML.</p>
+</body>
+</html>