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 2011/01/10 00:19:29 UTC

svn commit: r1057053 [5/12] - in /pivot/branches/3.x: ./ core/ core/src/ core/src/org/ core/src/org/apache/ core/src/org/apache/pivot/ core/src/org/apache/pivot/beans/ core/src/org/apache/pivot/bxml/ core/src/org/apache/pivot/csv/ core/src/org/apache/p...

Added: pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/Task.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/Task.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/Task.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/Task.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.pivot.util.concurrent;
+
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Abstract base class for "tasks". A task is an asynchronous operation that
+ * may optionally return a value.
+ *
+ * @param <V>
+ * The type of the value returned by the operation. May be {@link Void} to
+ * indicate that the task does not return a value.
+ */
+public abstract class Task<V> {
+    /**
+     * Task execution callback that is posted to the executor service.
+     */
+    private class ExecuteCallback implements Runnable {
+        @Override
+        public void run() {
+            V result = null;
+            Exception fault = null;
+
+            try {
+                result = execute();
+            }
+            catch(Exception exception) {
+                fault = exception;
+            }
+
+            TaskListener<V> taskListener;
+            synchronized (Task.this) {
+                Task.this.result = result;
+                Task.this.fault = fault;
+
+                abort = false;
+
+                taskListener = Task.this.taskListener;
+                Task.this.taskListener = null;
+            }
+
+            taskListener.taskExecuted(Task.this);
+        }
+    }
+
+    private static class DefaultExecutorService extends AbstractExecutorService {
+        private boolean shutdown = false;
+
+        @Override
+        public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+            return true;
+        }
+
+        @Override
+        public void shutdown() {
+            shutdownNow();
+        }
+
+        @Override
+        public java.util.List<Runnable> shutdownNow() {
+            shutdown = true;
+            return new java.util.ArrayList<Runnable>();
+        }
+
+        @Override
+        public boolean isShutdown() {
+            return shutdown;
+        }
+
+        @Override
+        public boolean isTerminated() {
+            return isShutdown();
+        }
+
+        @Override
+        public void execute(Runnable command) {
+            Thread thread = new Thread(command);
+            thread.start();
+        }
+    }
+
+    private ExecutorService executorService;
+
+    private V result = null;
+    private Exception fault = null;
+    private TaskListener<V> taskListener = null;
+
+    protected volatile long timeout = Long.MAX_VALUE;
+    protected volatile boolean abort = false;
+
+    // TODO This is a workaround for an issue with Executors.newCachedThreadPool(), which
+    // unpredictably throws IllegalThreadStateException when run in an applet.
+    public static final ExecutorService DEFAULT_EXECUTOR_SERVICE = new DefaultExecutorService();
+
+    public Task() {
+        this(DEFAULT_EXECUTOR_SERVICE);
+    }
+
+    public Task(ExecutorService executorService) {
+        if (executorService == null) {
+            throw new IllegalArgumentException("executorService is null.");
+        }
+
+        this.executorService = executorService;
+    }
+
+    /**
+     * Synchronously executes the task.
+     *
+     * @return
+     * The result of the task's execution.
+     *
+     * @throws TaskExecutionException
+     * If an error occurs while executing the task.
+     */
+    public abstract V execute() throws TaskExecutionException;
+
+    /**
+     * Asynchronously executes the task. The caller is notified of the task's
+     * completion via the listener argument. Note that the listener will be
+     * notified on the task's worker thread, not on the thread that executed
+     * the task.
+     *
+     * @param taskListener
+     * The listener to be notified when the task completes.
+     */
+    public synchronized void execute(TaskListener<V> taskListener) {
+        if (taskListener == null) {
+            throw new IllegalArgumentException("taskListener is null.");
+        }
+
+        if (this.taskListener != null) {
+            throw new IllegalThreadStateException("Task is already pending.");
+        }
+
+        this.taskListener = taskListener;
+
+        result = null;
+        fault = null;
+        abort = false;
+
+        // Create a new execute callback and post it to the executor service
+        ExecuteCallback executeCallback = new ExecuteCallback();
+        executorService.submit(executeCallback);
+    }
+
+    /**
+     * Returns the executor service used to execute this task.
+     */
+    public ExecutorService getExecutorService() {
+        return executorService;
+    }
+
+    /**
+     * Returns the result of executing the task.
+     *
+     * @return
+     * The task result, or <tt>null</tt> if the task is still executing or
+     * has failed. The result itself may also be <tt>null</tt>; callers should
+     * call {@link #isPending()} and {@link #getFault()} to distinguish
+     * between these cases.
+     */
+    public synchronized V getResult() {
+        return result;
+    }
+
+    /**
+     * Returns the fault that occurred while executing the task.
+     *
+     * @return
+     * The task fault, or <tt>null</tt> if the task is still executing or
+     * has succeeded. Callers should call {@link #isPending()} to distinguish
+     * between these cases.
+     */
+    public synchronized Exception getFault() {
+        return fault;
+    }
+
+    /**
+     * Returns the pending state of the task.
+     *
+     * @return
+     * <tt>true</tt> if the task is awaiting execution or currently executing;
+     * <tt>false</tt>, otherwise.
+     */
+    public synchronized boolean isPending() {
+        return (taskListener != null);
+    }
+
+
+    /**
+     * Returns the timeout value for this task.
+     *
+     * @see #setTimeout(long)
+     */
+    public synchronized long getTimeout() {
+        return timeout;
+    }
+
+    /**
+     * Sets the timeout value for this task. It is the responsibility of the
+     * implementing class to respect this value.
+     *
+     * @param timeout
+     * The time by which the task must complete execution. If the timeout is
+     * exceeded, a {@link TimeoutException} will be thrown.
+     */
+    public synchronized void setTimeout(long timeout) {
+        this.timeout = timeout;
+    }
+
+    /**
+     * Sets the abort flag for this task to <tt>true</tt>. It is the
+     * responsibility of the implementing class to respect this value and
+     * throw a {@link AbortException}.
+     */
+    public synchronized void abort() {
+        abort = true;
+    }
+}

Added: pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskExecutionException.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskExecutionException.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskExecutionException.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskExecutionException.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.pivot.util.concurrent;
+
+/**
+ * Thrown when an error occurs during task execution.
+ */
+public class TaskExecutionException extends Exception {
+    private static final long serialVersionUID = 0;
+
+    public TaskExecutionException() {
+        super();
+    }
+
+    public TaskExecutionException(String message) {
+        super(message);
+    }
+
+    public TaskExecutionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public TaskExecutionException(Throwable cause) {
+        super(cause);
+    }
+}

Added: pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskGroup.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskGroup.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskGroup.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskGroup.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.pivot.util.concurrent;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Abstract base class for task groups.
+ */
+public abstract class TaskGroup extends Task<Void> {
+    protected int complete = 0;
+    protected ArrayList<Task<?>> tasks = new ArrayList<Task<?>>();
+
+    public TaskGroup() {
+        this(DEFAULT_EXECUTOR_SERVICE);
+    }
+
+    public TaskGroup(ExecutorService executorService) {
+        super(executorService);
+    }
+
+    public synchronized List<Task<?>> getTasks() {
+        return isPending() ? Collections.unmodifiableList(tasks) : tasks;
+    }
+}

Added: pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskListener.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskListener.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskListener.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TaskListener.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.pivot.util.concurrent;
+
+/**
+ * Task listener interface.
+ *
+ * @param <V>
+ * The return type of the task.
+ */
+public interface TaskListener<V> {
+    /**
+     * Called when the task has been executed. The return value of
+     * {@link Task#getFault()} can be checked to determine if the
+     * execution was successful or not.
+     * <p>
+     * Note that this method will be called on the executing thread,
+     * which is not guaranteed to be the same as the thread on which
+     * {@link Task#execute(TaskListener)} was called.
+     *
+     * @param task
+     * The source of the event.
+     */
+    public void taskExecuted(Task<V> task);
+}

Added: pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TimeoutException.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TimeoutException.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TimeoutException.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/TimeoutException.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.pivot.util.concurrent;
+
+/**
+ * Thrown when an executing task has timed out.
+ */
+public class TimeoutException extends RuntimeException {
+    private static final long serialVersionUID = 0;
+
+    public TimeoutException() {
+        super();
+    }
+
+    public TimeoutException(String message) {
+        super(message);
+    }
+}

Added: pivot/branches/3.x/core/src/org/apache/pivot/xml/Element.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/xml/Element.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/xml/Element.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/xml/Element.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,762 @@
+/*
+ * Contains code originally developed for Apache Pivot under the Apache
+ * License, Version 2.0:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package org.apache.pivot.xml;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Node class representing an XML element.
+ */
+public class Element extends Node {
+    /**
+     * Class representing an XML namespace.
+     */
+    public static class Namespace {
+        private Element element = null;
+
+        private String prefix;
+        private String uri;
+
+        public Namespace(String prefix, String uri) {
+            this.prefix = prefix;
+            this.uri = uri;
+        }
+
+        /**
+         * Returns the element to which this attribute belongs.
+         *
+         * @return
+         * This attribute's element, or <tt>null</tt> if the attribute does not
+         * belong to an element.
+         */
+        public Element getElement() {
+            return element;
+        }
+
+        /**
+         * Returns the prefix associated with this namespace.
+         */
+        public String getPrefix() {
+            return prefix;
+        }
+
+        /**
+         * Returns the URI associated with this namespace.
+         */
+        public String getURI() {
+            return uri;
+        }
+    }
+
+    /**
+     * Class representing an XML attribute.
+     */
+    public static class Attribute {
+        private Element element = null;
+
+        private String namespacePrefix;
+        private String localName;
+        private String value;
+
+        public Attribute(String localName, String value) {
+            this(null, localName, value);
+        }
+
+        public Attribute(String namespacePrefix, String localName, String value) {
+            validateName(namespacePrefix, localName);
+
+            this.namespacePrefix = namespacePrefix;
+            this.localName = localName;
+
+            setValue(value);
+        }
+
+        /**
+         * Returns the element to which this attribute belongs.
+         *
+         * @return
+         * This attribute's element, or <tt>null</tt> if the attribute does not
+         * belong to an element.
+         */
+        public Element getElement() {
+            return element;
+        }
+
+        /**
+         * Returns the attribute's namespace prefix.
+         *
+         * @return
+         * The attribute's namespace prefix, or <tt>null</tt> if the attribute belongs to the
+         * default namespace.
+         */
+        public String getNamespacePrefix() {
+            return namespacePrefix;
+        }
+
+        /**
+         * Returns the attribute's local name.
+         */
+        public String getLocalName() {
+            return localName;
+        }
+
+        /**
+         * Returns the fully-qualified name of the attribute.
+         */
+        public String getName() {
+            String name;
+            if (namespacePrefix == null) {
+                name = localName;
+            } else {
+                name = namespacePrefix + ":" + localName;
+            }
+
+            return name;
+        }
+
+        /**
+         * Returns the attribute's value.
+         */
+        public String getValue() {
+            return value;
+        }
+
+        /**
+         * Sets the attribute's value.
+         *
+         * @param value
+         */
+        public void setValue(String value) {
+            if (value == null) {
+                throw new IllegalArgumentException();
+            }
+
+            this.value = value;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            boolean equals = false;
+
+            if (this == o) {
+                equals = true;
+            } else if (o instanceof Attribute) {
+                Attribute attribute = (Attribute)o;
+                if (namespacePrefix == null) {
+                    equals = (attribute.namespacePrefix == null);
+                } else {
+                    equals = (namespacePrefix.equals(attribute.namespacePrefix));
+                }
+
+                equals &= (localName.equals(attribute.localName)
+                    && value.equals(attribute.value));
+            }
+
+            return equals;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            if (namespacePrefix != null) {
+                result = 31 * result + namespacePrefix.hashCode();
+            }
+            result = prime * result + localName.hashCode();
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            String string = "";
+            if (namespacePrefix != null) {
+                string += namespacePrefix + ":";
+            }
+
+            string += localName + "=\"" + value + "\"";
+
+            return string;
+        }
+    }
+
+    private String namespacePrefix;
+    private String localName;
+
+    private String defaultNamespaceURI = null;
+    private ArrayList<Namespace> namespaces = new ArrayList<Namespace>() {
+        private static final long serialVersionUID = 0;
+
+        @Override
+        public boolean add(Namespace namespace) {
+            if (namespace.element != null) {
+                throw new IllegalArgumentException();
+            }
+
+            if (namespaceMap.containsKey(namespace.getPrefix())) {
+                throw new IllegalArgumentException();
+            }
+
+            namespace.element = Element.this;
+            namespaceMap.put(namespace.getPrefix(), namespace);
+
+            return super.add(namespace);
+        }
+
+        @Override
+        public void add(int index, Namespace namespace) {
+            if (namespace.element != null) {
+                throw new IllegalArgumentException();
+            }
+
+            if (namespaceMap.containsKey(namespace.getPrefix())) {
+                throw new IllegalArgumentException();
+            }
+
+            namespace.element = Element.this;
+            namespaceMap.put(namespace.getPrefix(), namespace);
+
+            super.add(index, namespace);
+        }
+
+        @Override
+        public Namespace remove(int index) {
+            Namespace namespace = super.remove(index);
+            namespaceMap.remove(namespace.getPrefix());
+            namespace.element = null;
+
+            return namespace;
+        }
+
+        @Override
+        public void clear() {
+            for (Namespace namespace : this) {
+                namespace.element = null;
+            }
+
+            namespaceMap.clear();
+
+            super.clear();
+        }
+
+        @Override
+        public Namespace set(int index, Namespace namespace) {
+            throw new UnsupportedOperationException();
+        }
+    };
+
+    private HashMap<String, Namespace> namespaceMap = new HashMap<String, Namespace>();
+
+    private ArrayList<Attribute> attributes = new ArrayList<Attribute>() {
+        private static final long serialVersionUID = 0;
+
+        @Override
+        public boolean add(Attribute attribute) {
+            if (attribute.element != null) {
+                throw new IllegalArgumentException();
+            }
+
+            if (attributeMap.containsKey(attribute.getName())) {
+                throw new IllegalArgumentException();
+            }
+
+            attribute.element = Element.this;
+            attributeMap.put(attribute.getName(), attribute);
+
+            return super.add(attribute);
+        }
+
+        @Override
+        public void add(int index, Attribute attribute) {
+            if (attribute.element != null) {
+                throw new IllegalArgumentException();
+            }
+
+            if (attributeMap.containsKey(attribute.getName())) {
+                throw new IllegalArgumentException();
+            }
+
+            attribute.element = Element.this;
+            attributeMap.put(attribute.getName(), attribute);
+
+            super.add(index, attribute);
+        }
+
+        @Override
+        public Attribute remove(int index) {
+            Attribute attribute = super.remove(index);
+            attributeMap.remove(attribute.getName());
+            attribute.element = null;
+
+            return attribute;
+        }
+
+        @Override
+        public void clear() {
+            for (Attribute attribute : this) {
+                attribute.element = null;
+            }
+
+            attributeMap.clear();
+
+            super.clear();
+        }
+
+        @Override
+        public Attribute set(int index, Attribute attribute) {
+            throw new UnsupportedOperationException();
+        }
+    };
+
+    private HashMap<String, Attribute> attributeMap = new HashMap<String, Attribute>();
+
+    private ArrayList<Node> nodes = new ArrayList<Node>() {
+        private static final long serialVersionUID = 0;
+
+        @Override
+        public boolean add(Node node) {
+            if (node.getParent() != null) {
+                throw new IllegalArgumentException();
+            }
+
+            node.setParent(Element.this);
+            return super.add(node);
+        }
+
+        @Override
+        public void add(int index, Node node) {
+            if (node.getParent() != null) {
+                throw new IllegalArgumentException();
+            }
+
+            node.setParent(Element.this);
+            super.add(index, node);
+        }
+
+        @Override
+        public Node remove(int index) {
+            Node node = super.remove(index);
+            node.setParent(null);
+
+            return node;
+        }
+
+        @Override
+        public void clear() {
+            for (Node node : this) {
+                node.setParent(null);
+            }
+
+            super.clear();
+        }
+
+        @Override
+        public Node set(int index, Node node) {
+            throw new UnsupportedOperationException();
+        }
+    };
+
+    public Element(String localName) {
+        this(null, localName);
+    }
+
+    public Element(String namespacePrefix, String localName) {
+        validateName(namespacePrefix, localName);
+
+        this.namespacePrefix = namespacePrefix;
+        this.localName = localName;
+    }
+
+    /**
+     * Returns the element's namespace prefix.
+     *
+     * @return
+     * The element's namespace prefix, or <tt>null</tt> if the element belongs to the
+     * default namespace.
+     */
+    public String getNamespacePrefix() {
+        return namespacePrefix;
+    }
+
+    /**
+     * Returns the element's local name.
+     */
+    public String getLocalName() {
+        return localName;
+    }
+
+    /**
+     * Returns the fully-qualified name of the element.
+     */
+    public String getName() {
+        String name;
+        if (namespacePrefix == null) {
+            name = localName;
+        } else {
+            name = namespacePrefix + ":" + localName;
+        }
+
+        return name;
+    }
+
+    /**
+     * Returns the element's default namespace URI.
+     *
+     * @return
+     * The default namespace URI declared by this element, or <tt>null</tt> if
+     * this element does not declare a default namespace.
+     */
+    public String getDefaultNamespaceURI() {
+        return defaultNamespaceURI;
+    }
+
+    /**
+     * Sets the element's default namespace URI.
+     *
+     * @param defaultNamespaceURI
+     * The default namespace URI declared by this element, or <tt>null</tt> if
+     * this element does not declare a default namespace.
+     */
+    public void setDefaultNamespaceURI(String defaultNamespaceURI) {
+        this.defaultNamespaceURI = defaultNamespaceURI;
+    }
+
+    /**
+     * Returns the element's namespace list.
+     */
+    public List<Namespace> getNamespaces() {
+        return namespaces;
+    }
+
+    /**
+     * Determines the namespace URI corresponding to the given prefix by traversing
+     * the element's ancestry.
+     *
+     * @param prefix
+     * The namespace prefix to look up, or <tt>null</tt> to determine the default
+     * namespace for this element.
+     *
+     * @return
+     * The namespace URI corresponding to the given prefix, or <tt>null</tt> if a
+     * URI could not be found.
+     */
+    public String getNamespaceURI(String prefix) {
+        String namespaceURI;
+
+        Element parent = getParent();
+        if (prefix == null) {
+            if (defaultNamespaceURI == null) {
+                namespaceURI = parent.getDefaultNamespaceURI();
+            } else {
+                namespaceURI = defaultNamespaceURI;
+            }
+        } else {
+            if (namespaceMap.containsKey(prefix)) {
+                namespaceURI = namespaceMap.get(prefix).getURI();
+            } else {
+                namespaceURI = parent.getNamespaceURI(prefix);
+            }
+        }
+
+        return namespaceURI;
+    }
+
+    /**
+     * Returns the element's attribute list.
+     */
+    public List<Attribute> getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * Returns the element's attribute dictionary.
+     */
+    public String getAttributeValue(String attributeName) {
+        Attribute attribute = attributeMap.get(attributeName);
+        return (attribute == null) ? null : attribute.getValue();
+    }
+
+    /**
+     * Returns the element's node list.
+     */
+    public List<Node> getNodes() {
+        return nodes;
+    }
+
+    /**
+     * Returns a descendant element matching a given path.
+     *
+     * @param path
+     * A path of the form:
+     * <pre>
+     * tag[n]/tag[n]/...
+     * </pre>
+     * The bracketed index values are optional and refer to the <i>n</i>th
+     * occurrence of the given tag name within its parent element. If
+     * omitted, the path refers to the first occurrence of the named
+     * element (i.e. the element at index 0).
+     *
+     * @return
+     * The matching element, or <tt>null</tt> if no such element exists.
+     */
+    public Element getElement(String path) {
+        if (path == null) {
+            throw new IllegalArgumentException("path is null.");
+        }
+
+        if (path.length() == 0) {
+            throw new IllegalArgumentException("path is empty.");
+        }
+
+        List<String> pathComponents = Arrays.asList(path.split("/"));
+        Element current = this;
+
+        for (int i = 0, n = pathComponents.size(); i < n; i++) {
+            String pathComponent = pathComponents.get(i);
+
+            String tagName;
+            int index;
+            int leadingBracketIndex = pathComponent.indexOf('[');
+            if (leadingBracketIndex == -1) {
+                tagName = pathComponent;
+                index = 0;
+            } else {
+                tagName = pathComponent.substring(0, leadingBracketIndex);
+
+                int trailingBracketIndex = pathComponent.lastIndexOf(']');
+                if (trailingBracketIndex == -1) {
+                    throw new IllegalArgumentException("Unterminated index identifier.");
+                }
+
+                index = Integer.parseInt(pathComponent.substring(leadingBracketIndex + 1,
+                    trailingBracketIndex));
+            }
+
+
+            int j = 0;
+            int k = 0;
+            for (Node node : current.getNodes()) {
+                if (node instanceof Element) {
+                    Element element = (Element)node;
+
+                    if (element.getName().equals(tagName)) {
+                        if (k == index) {
+                            break;
+                        }
+
+                        k++;
+                    }
+                }
+
+                j++;
+            }
+
+            if (j < current.getNodes().size()) {
+                current = (Element)current.getNodes().get(j);
+            } else {
+                current = null;
+                break;
+            }
+        }
+
+        return current;
+    }
+
+    /**
+     * Returns the sub-elements of of this element whose tag names match the
+     * given name.
+     *
+     * @param name
+     * The tag name to match.
+     *
+     * @return
+     * A sequence containing the matching elements. The sequence will be empty
+     * if no elements matched the given tag name.
+     */
+    public List<Element> getElements(String name) {
+        List<Element> elements = new ArrayList<Element>();
+
+        for (Node node : nodes) {
+            if (node instanceof Element) {
+                Element element = (Element)node;
+
+                if (element.getName().equals(name)) {
+                    elements.add(element);
+                }
+            }
+        }
+
+        return elements;
+    }
+
+    /**
+     * Returns the sub-elements of a descendant element whose tag names match
+     * the given name.
+     *
+     * @param path
+     * The path to the descendant, relative to this element.
+     *
+     * @param name
+     * The tag name to match.
+     *
+     * @return
+     * The matching elements, or <tt>null</tt> if no such descendant exists.
+     *
+     * @see #getElement(Element, String)
+     * @see #getElements(String)
+     */
+    public List<Element> getElements(String path, String name) {
+        Element element = getElement(path);
+        return (element == null) ? null : element.getElements(name);
+    }
+
+    /**
+     * Returns the text content of this element. An element is defined to
+     * contain text when it contains a single child that is an instance of
+     * {@link TextNode}.
+     *
+     * @return
+     * The text content of the element, or <tt>null</tt> if this element does
+     * not contain text.
+     */
+    public String getText() {
+        String text = null;
+
+        if (nodes.size() == 1) {
+            Node node = nodes.get(0);
+
+            if (node instanceof TextNode) {
+                TextNode textNode = (TextNode)node;
+                text = textNode.getText();
+            }
+        }
+
+        return text;
+    }
+
+    /**
+     * Returns the text content of a descendant element.
+     *
+     * @param path
+     * The path to the descendant, relative to this element.
+     *
+     * @return
+     * The text of the descendant, or <tt>null</tt> if no such descendant
+     * exists.
+     *
+     * @see #getElement(Element, String)
+     * @see #getText()
+     */
+    public String getText(String path) {
+        Element element = getElement(path);
+        return (element == null) ? null : element.getText();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        boolean equals = false;
+
+        if (this == o) {
+            equals = true;
+        } else if (o instanceof Element) {
+            Element element = (Element)o;
+            if (namespacePrefix == null) {
+                equals = (element.namespacePrefix == null);
+            } else {
+                equals = (namespacePrefix.equals(element.namespacePrefix));
+            }
+
+            equals &= (attributes.equals(element.attributes)
+                && nodes.equals(element.nodes));
+        }
+
+        return equals;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        if (namespacePrefix != null) {
+            result = 31 * result + namespacePrefix.hashCode();
+        }
+        result = prime * result + localName.hashCode();
+        result = prime * result + namespaces.hashCode();
+        result = prime * result + attributes.hashCode();
+        result = prime * result + nodes.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        String string = "<";
+        if (namespacePrefix != null) {
+            string += namespacePrefix + ":";
+        }
+
+        string += localName + ">";
+
+        return string;
+    }
+
+    private static void validateName(String namespacePrefix, String localName) {
+        // Validate prefix
+        if (namespacePrefix != null) {
+            if (namespacePrefix.length() == 0) {
+                throw new IllegalArgumentException("Namespace prefix is empty.");
+            }
+
+            char c = namespacePrefix.charAt(0);
+            if (!Character.isLetter(c)) {
+                throw new IllegalArgumentException("'" + c + "' is not a valid start"
+                    + " character for a namespace prefix.");
+            }
+
+            for (int i = 1, n = namespacePrefix.length(); i < n; i++) {
+                c = namespacePrefix.charAt(i);
+
+                if (!Character.isLetterOrDigit(c)
+                    && c != '-'
+                    && c != '_'
+                    && c != '.') {
+                    throw new IllegalArgumentException("'" + c + "' is not a valid character"
+                        + " for a namespace prefix.");
+                }
+            }
+        }
+
+        // Validate local name
+        if (localName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        if (localName.length() == 0) {
+            throw new IllegalArgumentException("Local name is empty.");
+        }
+
+        char c = localName.charAt(0);
+        if (!Character.isLetter(c)
+            && c != '_') {
+            throw new IllegalArgumentException("'" + c + "' is not a valid start"
+                + " character for a local name.");
+        }
+
+        for (int i = 1, n = localName.length(); i < n; i++) {
+            c = localName.charAt(i);
+
+            if (!Character.isLetterOrDigit(c)
+                && c != '-'
+                && c != '_'
+                && c != '.') {
+                throw new IllegalArgumentException("'" + c + "' is not a valid character"
+                    + " for a local name.");
+            }
+        }
+    }
+}

Added: pivot/branches/3.x/core/src/org/apache/pivot/xml/Node.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/xml/Node.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/xml/Node.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/xml/Node.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,30 @@
+/*
+ * Contains code originally developed for Apache Pivot under the Apache
+ * License, Version 2.0:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package org.apache.pivot.xml;
+
+/**
+ * Abstract base class for XML nodes.
+ */
+public abstract class Node {
+    private Element parent = null;
+
+    /**
+     * Returns the parent element of the node.
+     */
+    public Element getParent() {
+        return parent;
+    }
+
+    /**
+     * Sets the parent element of the node.
+     *
+     * @param parent
+     */
+    protected void setParent(Element parent) {
+        this.parent = parent;
+    }
+}

Added: pivot/branches/3.x/core/src/org/apache/pivot/xml/TextNode.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/xml/TextNode.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/xml/TextNode.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/xml/TextNode.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,50 @@
+/*
+ * Contains code originally developed for Apache Pivot under the Apache
+ * License, Version 2.0:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package org.apache.pivot.xml;
+
+/**
+ * Class representing an XML text node.
+ */
+public class TextNode extends Node {
+    private String text;
+
+    public TextNode(String text) {
+        if (text == null) {
+            throw new IllegalArgumentException();
+        }
+
+        this.text = text;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        boolean equals = false;
+
+        if (this == o) {
+            equals = true;
+        } else if (o instanceof TextNode) {
+            TextNode textNode = (TextNode)o;
+            equals = (text.equals(textNode.text));
+        }
+
+        return equals;
+    }
+
+    @Override
+    public int hashCode() {
+        return text.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return text;
+    }
+}

Added: pivot/branches/3.x/core/src/org/apache/pivot/xml/XMLSerializer.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/xml/XMLSerializer.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/xml/XMLSerializer.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/xml/XMLSerializer.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,326 @@
+/*
+ * Contains code originally developed for Apache Pivot under the Apache
+ * License, Version 2.0:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package org.apache.pivot.xml;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.charset.Charset;
+
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.pivot.io.SerializationException;
+import org.apache.pivot.io.Serializer;
+import org.apache.pivot.util.ListenerList;
+
+/**
+ * Reads and writes XML data.
+ */
+public class XMLSerializer implements Serializer<Element> {
+    private static class XMLSerializerListenerList
+        extends ListenerList<XMLSerializerListener>
+        implements XMLSerializerListener {
+        @Override
+        public void beginElement(XMLSerializer xmlSerializer, Element element) {
+            for (XMLSerializerListener listener : listeners()) {
+                listener.beginElement(xmlSerializer, element);
+            }
+        }
+
+        @Override
+        public void endElement(XMLSerializer xmlSerializer) {
+            for (XMLSerializerListener listener : listeners()) {
+                listener.endElement(xmlSerializer);
+            }
+        }
+
+        @Override
+        public void readTextNode(XMLSerializer xmlSerializer, TextNode textNode) {
+            for (XMLSerializerListener listener : listeners()) {
+                listener.readTextNode(xmlSerializer, textNode);
+            }
+        }
+    }
+
+    private Charset charset = null;
+
+    private XMLSerializerListenerList xmlSerializerListeners = null;
+
+    public static final String XMLNS_ATTRIBUTE_PREFIX = "xmlns";
+
+    public static final String DEFAULT_CHARSET_NAME = "UTF-8";
+    public static final String XML_EXTENSION = "xml";
+    public static final String MIME_TYPE = "text/xml";
+    public static final int BUFFER_SIZE = 2048;
+
+    public XMLSerializer() {
+        this(Charset.forName(DEFAULT_CHARSET_NAME));
+    }
+
+    public XMLSerializer(Charset charset) {
+        if (charset == null) {
+            throw new IllegalArgumentException("charset is null.");
+        }
+
+        this.charset = charset;
+    }
+
+    public Charset getCharset() {
+        return charset;
+    }
+
+    @Override
+    public Element readObject(InputStream inputStream)
+        throws IOException, SerializationException {
+        if (inputStream == null) {
+            throw new IllegalArgumentException("inputStream is null.");
+        }
+
+        Reader reader = new BufferedReader(new InputStreamReader(inputStream, charset), BUFFER_SIZE);
+        Element element = readObject(reader);
+
+        return element;
+    }
+
+    public Element readObject(Reader reader) throws SerializationException {
+        if (reader == null) {
+            throw new IllegalArgumentException("reader is null.");
+        }
+
+        // Parse the XML stream
+        XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
+        xmlInputFactory.setProperty("javax.xml.stream.isCoalescing", true);
+
+        Element document = null;
+
+        try {
+            XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(reader);
+
+            Element current = null;
+
+            while (xmlStreamReader.hasNext()) {
+                int event = xmlStreamReader.next();
+
+                switch (event) {
+                    case XMLStreamConstants.CHARACTERS: {
+                        if (!xmlStreamReader.isWhiteSpace()) {
+                            TextNode textNode = new TextNode(xmlStreamReader.getText());
+
+                            // Notify listeners
+                            if (xmlSerializerListeners != null) {
+                                xmlSerializerListeners.readTextNode(this, textNode);
+                            }
+
+                            current.getNodes().add(textNode);
+                        }
+
+                        break;
+                    }
+
+                    case XMLStreamConstants.START_ELEMENT: {
+                        // Create the element
+                        String prefix = xmlStreamReader.getPrefix();
+                        if (prefix != null
+                            && prefix.length() == 0) {
+                            prefix = null;
+                        }
+
+                        String localName = xmlStreamReader.getLocalName();
+
+                        Element element = new Element(prefix, localName);
+
+                        // Get the element's namespaces
+                        for (int i = 0, n = xmlStreamReader.getNamespaceCount(); i < n; i++) {
+                            String namespacePrefix = xmlStreamReader.getNamespacePrefix(i);
+                            String namespaceURI = xmlStreamReader.getNamespaceURI(i);
+
+                            if (namespacePrefix == null) {
+                                element.setDefaultNamespaceURI(namespaceURI);
+                            } else {
+                                element.getNamespaces().add(new Element.Namespace(namespacePrefix, namespaceURI));
+                            }
+                        }
+
+                        // Get the element's attributes
+                        for (int i = 0, n = xmlStreamReader.getAttributeCount(); i < n; i++) {
+                            String attributePrefix = xmlStreamReader.getAttributePrefix(i);
+                            if (attributePrefix != null
+                                && attributePrefix.length() == 0) {
+                                attributePrefix = null;
+                            }
+
+                            String attributeLocalName = xmlStreamReader.getAttributeLocalName(i);
+                            String attributeValue = xmlStreamReader.getAttributeValue(i);
+
+                            element.getAttributes().add(new Element.Attribute(attributePrefix,
+                                attributeLocalName, attributeValue));
+                        }
+
+                        if (current == null) {
+                            document = element;
+                        } else {
+                            current.getNodes().add(element);
+                        }
+
+                        // Notify listeners
+                        if (xmlSerializerListeners != null) {
+                            xmlSerializerListeners.beginElement(this, element);
+                        }
+
+                        current = element;
+
+                        break;
+                    }
+
+                    case XMLStreamConstants.END_ELEMENT: {
+                        // Notify listeners
+                        if (xmlSerializerListeners != null) {
+                            xmlSerializerListeners.endElement(this);
+                        }
+
+                        // Move up the stack
+                        current = current.getParent();
+
+                        break;
+                    }
+                }
+            }
+        } catch (XMLStreamException exception) {
+            throw new SerializationException(exception);
+        }
+
+        return document;
+    }
+
+    @Override
+    public void writeObject(Element element, OutputStream outputStream)
+        throws IOException, SerializationException {
+        if (outputStream == null) {
+            throw new IllegalArgumentException("outputStream is null.");
+        }
+
+        Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, charset),
+            BUFFER_SIZE);
+        writeObject(element, writer);
+        writer.flush();
+    }
+
+    public void writeObject(Element element, Writer writer) throws SerializationException {
+        if (writer == null) {
+            throw new IllegalArgumentException("writer is null.");
+        }
+
+        if (element == null) {
+            throw new IllegalArgumentException("element is null.");
+        }
+
+        XMLOutputFactory output = XMLOutputFactory.newInstance();
+
+        try {
+            XMLStreamWriter xmlStreamWriter = output.createXMLStreamWriter(writer);
+            xmlStreamWriter.writeStartDocument();
+            writeElement(element, xmlStreamWriter);
+            xmlStreamWriter.writeEndDocument();
+        } catch (XMLStreamException exception) {
+            throw new SerializationException(exception);
+        }
+    }
+
+    private void writeElement(Element element, XMLStreamWriter xmlStreamWriter)
+        throws XMLStreamException, SerializationException {
+        String namespacePrefix = element.getNamespacePrefix();
+        String localName = element.getLocalName();
+
+        if (namespacePrefix == null) {
+            if (element.getNodes().size() == 0) {
+                xmlStreamWriter.writeEmptyElement(localName);
+            } else {
+                xmlStreamWriter.writeStartElement(localName);
+            }
+        } else {
+            String namespaceURI = element.getNamespaceURI(namespacePrefix);
+
+            if (element.getNodes().size() == 0) {
+                xmlStreamWriter.writeEmptyElement(namespacePrefix, localName, namespaceURI);
+            } else {
+                xmlStreamWriter.writeStartElement(namespacePrefix, localName, namespaceURI);
+            }
+        }
+
+        // Write out the declared namespaces
+        String defaultNamespaceURI = element.getDefaultNamespaceURI();
+        if (defaultNamespaceURI != null) {
+            xmlStreamWriter.writeDefaultNamespace(defaultNamespaceURI);
+        }
+
+        for (Element.Namespace namespace : element.getNamespaces()) {
+            xmlStreamWriter.writeNamespace(namespace.getPrefix(), namespace.getURI());
+        }
+
+        // Write out the attributes
+        for (Element.Attribute attribute : element.getAttributes()) {
+            String attributeNamespacePrefix = attribute.getNamespacePrefix();
+            String attributeLocalName = attribute.getLocalName();
+            String attributeValue = attribute.getValue();
+
+            if (attributeNamespacePrefix == null) {
+                xmlStreamWriter.writeAttribute(attributeLocalName, attributeValue);
+            } else {
+                String attributeNamespaceURI = element.getNamespaceURI(attributeNamespacePrefix);
+
+                xmlStreamWriter.writeAttribute(attributeNamespacePrefix, attributeNamespaceURI,
+                    attributeLocalName, attributeValue);
+            }
+        }
+
+        // Write out the child nodes
+        for (Node node : element.getNodes()) {
+            if (node instanceof Element) {
+                writeElement((Element)node, xmlStreamWriter);
+            } else if (node instanceof TextNode) {
+                writeTextNode((TextNode)node, xmlStreamWriter);
+            } else {
+                throw new SerializationException("Unsupported node type: "
+                    + node.getClass().getName());
+            }
+        }
+
+        if (element.getNodes().size() > 0) {
+            xmlStreamWriter.writeEndElement();
+        }
+    }
+
+    private void writeTextNode(TextNode textNode, XMLStreamWriter xmlStreamWriter)
+        throws XMLStreamException {
+        xmlStreamWriter.writeCharacters(textNode.getText());
+    }
+
+    @Override
+    public String getMIMEType(Element object) {
+        return MIME_TYPE;
+    }
+
+    public ListenerList<XMLSerializerListener> getXMLSerializerListeners() {
+        if (xmlSerializerListeners == null) {
+            xmlSerializerListeners = new XMLSerializerListenerList();
+        }
+
+        return xmlSerializerListeners;
+    }
+}

Added: pivot/branches/3.x/core/src/org/apache/pivot/xml/XMLSerializerListener.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/xml/XMLSerializerListener.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/xml/XMLSerializerListener.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/xml/XMLSerializerListener.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,52 @@
+/*
+ * Contains code originally developed for Apache Pivot under the Apache
+ * License, Version 2.0:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package org.apache.pivot.xml;
+
+/**
+ * XML serializer listener interface.
+ */
+public interface XMLSerializerListener {
+    /**
+     * XML serializer listener adapter.
+     */
+    public static class Adapter implements XMLSerializerListener {
+        @Override
+        public void beginElement(XMLSerializer xmlSerializer, Element element) {
+        }
+
+        @Override
+        public void endElement(XMLSerializer xmlSerializer) {
+        }
+
+        @Override
+        public void readTextNode(XMLSerializer xmlSerializer, TextNode textNode) {
+        }
+    }
+
+    /**
+     * Called when the serializer has begun reading an element.
+     *
+     * @param xmlSerializer
+     * @param element
+     */
+    public void beginElement(XMLSerializer xmlSerializer, Element element);
+
+    /**
+     * Called when the serializer has finished reading an element.
+     *
+     * @param xmlSerializer
+     */
+    public void endElement(XMLSerializer xmlSerializer);
+
+    /**
+     * Called when the serializer has read a text node.
+     *
+     * @param xmlSerializer
+     * @param textNode
+     */
+    public void readTextNode(XMLSerializer xmlSerializer, TextNode textNode);
+}

Added: pivot/branches/3.x/core/test/org/apache/pivot/beans/test/BeanAdapterTest.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/test/org/apache/pivot/beans/test/BeanAdapterTest.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/test/org/apache/pivot/beans/test/BeanAdapterTest.java (added)
+++ pivot/branches/3.x/core/test/org/apache/pivot/beans/test/BeanAdapterTest.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,33 @@
+package org.apache.pivot.beans.test;
+
+import org.apache.pivot.beans.BeanAdapter;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class BeanAdapterTest {
+    @Test
+    public void basicTest() {
+        SampleBean sampleBean = new SampleBean();
+        BeanAdapter beanAdapter = new BeanAdapter(sampleBean);
+
+        assertEquals(sampleBean.getA(), beanAdapter.get("a"));
+        assertEquals(sampleBean.getB(), beanAdapter.get("b"));
+        assertTrue(beanAdapter.isReadOnly("b"));
+
+        for (String property : beanAdapter.keySet()) {
+            assertFalse(beanAdapter.isReadOnly(property));
+        }
+
+        // Test explicit setter
+        beanAdapter.put("a", "100");
+        assertEquals(beanAdapter.get("a"), -100);
+
+        // Test type coercion
+        beanAdapter.put("a", 10.9);
+        assertEquals(beanAdapter.get("a"), 10);
+
+        beanAdapter.put("testEnum", "abcDef");
+        beanAdapter.put("testEnum", "ABC_DEF");
+    }
+}

Added: pivot/branches/3.x/core/test/org/apache/pivot/beans/test/SampleBean.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/test/org/apache/pivot/beans/test/SampleBean.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/test/org/apache/pivot/beans/test/SampleBean.java (added)
+++ pivot/branches/3.x/core/test/org/apache/pivot/beans/test/SampleBean.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,35 @@
+package org.apache.pivot.beans.test;
+
+public class SampleBean {
+    public enum TestEnum {
+        ABC_DEF
+    }
+
+    private int a = 20;
+    private String b = "ABCD";
+    private TestEnum testEnum = null;
+
+    public int getA() {
+        return a;
+    }
+
+    public void setA(int a) {
+        this.a = a;
+    }
+
+    public void setA(String a) {
+        setA(-Integer.parseInt(a));
+    }
+
+    public String getB() {
+        return b;
+    }
+
+    public TestEnum getTestEnum() {
+        return testEnum;
+    }
+
+    public void setTestEnum(TestEnum testEnum) {
+        this.testEnum = testEnum;
+    }
+}

Added: pivot/branches/3.x/core/test/org/apache/pivot/csv/test/CSVSerializerTest.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/test/org/apache/pivot/csv/test/CSVSerializerTest.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/test/org/apache/pivot/csv/test/CSVSerializerTest.java (added)
+++ pivot/branches/3.x/core/test/org/apache/pivot/csv/test/CSVSerializerTest.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,248 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.pivot.csv.test;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.pivot.csv.CSVSerializer;
+import org.apache.pivot.csv.CSVSerializerListener;
+import org.apache.pivot.io.SerializationException;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class CSVSerializerTest {
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testBasicReadObject() throws IOException, SerializationException {
+        // Test multiple line break formats
+        StringBuilder buf = new StringBuilder();
+        buf.append("a1,b1,c1\r\n");
+        buf.append("a2,b2,c2\n");
+        buf.append("a3,b3,c3\r");
+        buf.append("a4,b4,c4");
+
+        StringReader reader = new StringReader(buf.toString());
+
+        CSVSerializer serializer = new CSVSerializer();
+        serializer.setKeys("A", "B", "C");
+        serializer.getCSVSerializerListeners().add(new CSVSerializerListener() {
+            public void beginList(CSVSerializer csvSerializer, List<?> list) {
+                System.out.println("Begin list: " + list);
+            }
+
+            public void endList(CSVSerializer csvSerializer) {
+                System.out.println("End list");
+            }
+
+            public void readItem(CSVSerializer csvSerializer, Object item) {
+                System.out.println("Read item: " + item);
+            }
+        });
+
+        List<?> result = serializer.readObject(reader);
+
+        Map<String, Object> row;
+
+        // Test the first row
+        row = (Map<String, Object>)result.get(0);
+        assertEquals(row.get("A"), "a1");
+        assertEquals(row.get("B"), "b1");
+        assertEquals(row.get("C"), "c1");
+
+        // Test the second row
+        row = (Map<String, Object>)result.get(1);
+        assertEquals(row.get("A"), "a2");
+        assertEquals(row.get("B"), "b2");
+        assertEquals(row.get("C"), "c2");
+
+        // Test the third row
+        row = (Map<String, Object>)result.get(2);
+        assertEquals(row.get("A"), "a3");
+        assertEquals(row.get("B"), "b3");
+        assertEquals(row.get("C"), "c3");
+
+        // Test the fourth row
+        row = (Map<String, Object>)result.get(3);
+        assertEquals(row.get("A"), "a4");
+        assertEquals(row.get("B"), "b4");
+        assertEquals(row.get("C"), "c4");
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testQuotedCommaReadObject() throws IOException, SerializationException {
+        StringBuilder buf = new StringBuilder();
+        buf.append("a,\",b,\",c\r\n");
+
+        StringReader reader = new StringReader(buf.toString());
+
+        CSVSerializer serializer = new CSVSerializer();
+        serializer.setKeys("A", "B", "C");
+
+        List<?> result = serializer.readObject(reader);
+
+        Map<String, Object> row = (Map<String, Object>)result.get(0);
+        assertEquals("a", row.get("A"));
+        assertEquals(",b,", row.get("B"));
+        assertEquals("c", row.get("C"));
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testQuotedQuoteReadObject() throws IOException, SerializationException {
+        StringBuilder buf = new StringBuilder();
+        buf.append("a,\"\"\"b\"\"\",c\r\n");
+
+        StringReader reader = new StringReader(buf.toString());
+
+        CSVSerializer serializer = new CSVSerializer();
+        serializer.setKeys("A", "B", "C");
+
+        List<?> result = serializer.readObject(reader);
+
+        Map<String, Object> row = (Map<String, Object>)result.get(0);
+        assertEquals("a", row.get("A"));
+        assertEquals("\"b\"", row.get("B"));
+        assertEquals("c", row.get("C"));
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testQuotedNewlineReadObject() throws IOException, SerializationException {
+        StringBuilder buf = new StringBuilder();
+        buf.append("a,\"b\nb  \",c\r\n");
+
+        StringReader reader = new StringReader(buf.toString());
+
+        CSVSerializer serializer = new CSVSerializer();
+        serializer.setKeys("A", "B", "C");
+
+        List<?> result = serializer.readObject(reader);
+
+        Map<String, Object> row = (Map<String, Object>)result.get(0);
+        assertEquals("a", row.get("A"));
+        assertEquals("b\nb", row.get("B"));
+        assertEquals("c", row.get("C"));
+    }
+
+    @Test
+    public void testBasicWriteObject() throws IOException {
+        List<Object> items = new ArrayList<Object>();
+
+        HashMap<String, Object> item1 = new HashMap<String, Object>();
+        item1.put("A", "a1");
+        item1.put("B", "b1");
+        item1.put("C", "c1");
+        items.add(item1);
+
+        HashMap<String, Object> item2 = new HashMap<String, Object>();
+        item2.put("A", "a2");
+        item2.put("B", "b2");
+        item2.put("C", "c2");
+        items.add(item2);
+
+        StringWriter writer = new StringWriter();
+
+        CSVSerializer serializer = new CSVSerializer();
+        serializer.setKeys("A", "B", "C");
+
+        serializer.writeObject(items, writer);
+
+        assertEquals("a1,b1,c1\r\na2,b2,c2\r\n", writer.toString());
+    }
+
+    @Test
+    public void testQuotedCommaWriteObject() throws IOException {
+        List<Object> items = new ArrayList<Object>();
+        HashMap<String, Object> item = new HashMap<String, Object>();
+        item.put("A", "a");
+        item.put("B", ",b,");
+        item.put("C", "c");
+        items.add(item);
+
+        StringWriter writer = new StringWriter();
+
+        CSVSerializer serializer = new CSVSerializer();
+        serializer.setKeys("A", "B", "C");
+
+        serializer.writeObject(items, writer);
+
+        assertEquals("a,\",b,\",c\r\n", writer.toString());
+    }
+
+    @Test
+    public void testQuotedQuoteWriteObject() throws IOException {
+        List<Object> items = new ArrayList<Object>();
+        HashMap<String, Object> item = new HashMap<String, Object>();
+        item.put("A", "a");
+        item.put("B", "\"b\"");
+        item.put("C", "c");
+        items.add(item);
+
+        StringWriter writer = new StringWriter();
+
+        CSVSerializer serializer = new CSVSerializer();
+        serializer.setKeys("A", "B", "C");
+
+        serializer.writeObject(items, writer);
+
+        assertEquals("a,\"\"\"b\"\"\",c\r\n", writer.toString());
+    }
+
+    @Test
+    public void testQuotedNewlineWriteObject() throws IOException {
+        List<Object> items = new ArrayList<Object>();
+        HashMap<String, Object> item = new HashMap<String, Object>();
+        item.put("A", "a");
+        item.put("B", "\nb\n");
+        item.put("C", "c");
+        items.add(item);
+
+        StringWriter writer = new StringWriter();
+
+        CSVSerializer serializer = new CSVSerializer();
+        serializer.setKeys("A", "B", "C");
+
+        serializer.writeObject(items, writer);
+
+        assertEquals("a,\"\nb\n\",c\r\n", writer.toString());
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testInlineKeys() throws IOException, SerializationException {
+        StringBuilder buf = new StringBuilder();
+        buf.append("A \t, B ,C \n");
+        buf.append("a1,b1,c1\n");
+
+        StringReader reader = new StringReader(buf.toString());
+
+        CSVSerializer serializer = new CSVSerializer();
+        List<?> result = serializer.readObject(reader);
+        Map<String, Object> row = (Map<String, Object>)result.get(0);
+        assertEquals(row.get("A"), "a1");
+        assertEquals(row.get("B"), "b1");
+        assertEquals(row.get("C"), "c1");
+    }
+}

Added: pivot/branches/3.x/core/test/org/apache/pivot/io/test/BinarySerializerTest.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/test/org/apache/pivot/io/test/BinarySerializerTest.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/test/org/apache/pivot/io/test/BinarySerializerTest.java (added)
+++ pivot/branches/3.x/core/test/org/apache/pivot/io/test/BinarySerializerTest.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.pivot.io.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import org.apache.pivot.io.BinarySerializer;
+import org.apache.pivot.io.Serializer;
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.fail;
+
+public class BinarySerializerTest {
+    @Test
+    public void testBinarySerializer() {
+        Serializer<Object> serializer = new BinarySerializer();
+
+        Object[] outputData = {
+            "Hello World",
+            123.456,
+            true
+        };
+        Object[] inputData;
+
+        try {
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            try {
+                serializer.writeObject(outputData, outputStream);
+            } finally {
+                outputStream.close();
+            }
+
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
+            try {
+                inputData = (Object[])serializer.readObject(inputStream);
+            } finally {
+                inputStream.close();
+            }
+
+            assertArrayEquals(outputData, inputData);
+        } catch(Exception exception) {
+            fail(exception.getMessage());
+        }
+    }
+}

Added: pivot/branches/3.x/core/test/org/apache/pivot/io/test/ByteArraySerializerTest.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/test/org/apache/pivot/io/test/ByteArraySerializerTest.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/test/org/apache/pivot/io/test/ByteArraySerializerTest.java (added)
+++ pivot/branches/3.x/core/test/org/apache/pivot/io/test/ByteArraySerializerTest.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.pivot.io.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.apache.pivot.io.ByteArraySerializer;
+import org.apache.pivot.io.SerializationException;
+import org.apache.pivot.io.Serializer;
+import org.junit.Test;
+
+public class ByteArraySerializerTest {
+    public static final String testString = "// \n" + "// Hello from "
+            + ByteArraySerializerTest.class.getName() + "\n" + "// \n";
+    public static final byte[] testBytes = testString.getBytes();
+
+    public void log(String msg) {
+        System.out.println(msg);
+    }
+
+    @Test
+    public void readValues() throws IOException, SerializationException {
+        log("readValues()");
+
+        Serializer<byte[]> serializer = new ByteArraySerializer();
+
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(testBytes);
+        byte[] result = serializer.readObject(inputStream);
+        assertNotNull(result);
+
+        // dump content, but useful only for text resources ...
+        String dump = new String(result);
+        int dumpLength = dump.getBytes().length;
+        log("Result: " + dumpLength + " bytes \n" + dump);
+
+        assertTrue(dumpLength > 0);
+    }
+
+    @Test
+    public void writeValues() throws IOException, SerializationException {
+        log("writeValues()");
+
+        Serializer<byte[]> serializer = new ByteArraySerializer();
+
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        serializer.writeObject(testBytes, outputStream);
+
+        outputStream.flush();
+        outputStream.close();
+
+        byte[] result = outputStream.toByteArray();
+        assertNotNull(result);
+
+        // dump content, but useful only for text resources ...
+        String dump = new String(result);
+        int dumpLength = dump.getBytes().length;
+        log("Result: " + dumpLength + " bytes \n" + dump);
+
+        assertTrue(dumpLength > 0);
+    }
+
+}

Added: pivot/branches/3.x/core/test/org/apache/pivot/io/test/StringSerializerTest.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/test/org/apache/pivot/io/test/StringSerializerTest.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/test/org/apache/pivot/io/test/StringSerializerTest.java (added)
+++ pivot/branches/3.x/core/test/org/apache/pivot/io/test/StringSerializerTest.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.pivot.io.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.apache.pivot.io.SerializationException;
+import org.apache.pivot.io.Serializer;
+import org.apache.pivot.io.StringSerializer;
+import org.junit.Test;
+
+public class StringSerializerTest {
+    public static final String testString = "// \n" + "// Hello from "
+            + StringSerializerTest.class.getName() + "\n" + "// \n";
+    public static final byte[] testBytes = testString.getBytes();
+
+    public void log(String msg) {
+        System.out.println(msg);
+    }
+
+    @Test
+    public void readValues() throws IOException, SerializationException {
+        log("readValues()");
+
+        Serializer<String> serializer = new StringSerializer();
+
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(testBytes);
+        String result = serializer.readObject(inputStream);
+        assertNotNull(result);
+        assertEquals(result, testString);
+
+        // dump content, but useful only for text resources ...
+        String dump = new String(result);
+        int dumpLength = dump.getBytes().length;
+        log("Result: " + dumpLength + " bytes \n" + dump);
+
+        assertTrue(dumpLength > 0);
+    }
+
+    @Test
+    public void writeValues() throws IOException, SerializationException {
+        log("writeValues()");
+
+        Serializer<String> serializer = new StringSerializer();
+
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        serializer.writeObject(testString, outputStream);
+
+        outputStream.flush();
+        outputStream.close();
+
+        String result = outputStream.toString();
+        assertNotNull(result);
+        assertEquals(result, testString);
+
+        // dump content, but useful only for text resources ...
+        String dump = new String(result);
+        int dumpLength = dump.getBytes().length;
+        log("Result: " + dumpLength + " bytes \n" + dump);
+
+        assertTrue(dumpLength > 0);
+    }
+
+}

Added: pivot/branches/3.x/core/test/org/apache/pivot/json/test/BindTest.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/test/org/apache/pivot/json/test/BindTest.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/test/org/apache/pivot/json/test/BindTest.java (added)
+++ pivot/branches/3.x/core/test/org/apache/pivot/json/test/BindTest.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.pivot.json.test;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.pivot.beans.BeanAdapter;
+import org.apache.pivot.io.SerializationException;
+import org.apache.pivot.json.JSONSerializer;
+import org.apache.pivot.util.TypeLiteral;
+import org.junit.Test;
+
+public class BindTest {
+    /**
+     * Tests returning an untyped list.
+     *
+     * @throws IOException
+     * @throws SerializationException
+     */
+    @Test
+    public void testUntypedList() throws IOException, SerializationException {
+        JSONSerializer listSerializer = new JSONSerializer(ArrayList.class);
+        List<?> list = (List<?>)listSerializer.readObject(new StringReader("[1, 2, 3, 4, 5]"));
+        assertEquals(list.get(0), 1);
+    }
+
+    /**
+     * Tests returning a typed list using {@code org.apache.pivot.util.TypeLiteral}.
+     *
+     * @throws IOException
+     * @throws SerializationException
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testTypedList() throws IOException, SerializationException {
+        JSONSerializer listSerializer = new JSONSerializer();
+        List<Object> list =
+            (List<Object>)listSerializer.readObject(getClass().getResourceAsStream("list.json"));
+
+        JSONSerializer typedListSerializer =
+            new JSONSerializer((new TypeLiteral<ArrayList<SampleBean2>>() {}).getType());
+        ArrayList<SampleBean2> typedList =
+            (ArrayList<SampleBean2>)typedListSerializer.readObject(getClass().getResourceAsStream("list.json"));
+
+        Object item0 = typedList.get(0);
+        assertTrue(item0 instanceof SampleBean2);
+        assertEquals(typedList.get(0).getA(), BeanAdapter.get(list, "[0].a"));
+    }
+
+    /**
+     * Tests returning a subclass of a generic {@code org.apache.pivot.collections.List}.
+     *
+     * @throws IOException
+     * @throws SerializationException
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testListSubclass() throws IOException, SerializationException {
+        JSONSerializer listSerializer = new JSONSerializer();
+        List<Object> list =
+            (List<Object>)listSerializer.readObject(getClass().getResourceAsStream("list.json"));
+
+        JSONSerializer typedListSerializer = new JSONSerializer(SampleBean2ListSubclass.class);
+        SampleBean2List typedList =
+            (SampleBean2List)typedListSerializer.readObject(getClass().getResourceAsStream("list.json"));
+
+        Object item0 = typedList.get(0);
+        assertTrue(item0 instanceof SampleBean2);
+        assertEquals(typedList.get(0).getA(), BeanAdapter.get(list, "[0].a"));
+    }
+
+    /**
+     * Tests returning an untyped map.
+     *
+     * @throws IOException
+     * @throws SerializationException
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testUntypedMap() throws IOException, SerializationException {
+        JSONSerializer mapSerializer = new JSONSerializer(HashMap.class);
+        HashMap<String, ?> map = (HashMap<String, ?>)mapSerializer.readObject(new StringReader("{a:1, b:2, c:'3'}"));
+        assertEquals(map.get("a"), 1);
+    }
+
+    /**
+     * Tests returning a typed map using {@code org.apache.pivot.util.TypeLiteral}.
+     *
+     * @throws IOException
+     * @throws SerializationException
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testTypedMap() throws IOException, SerializationException {
+        JSONSerializer typedMapSerializer =
+            new JSONSerializer((new TypeLiteral<HashMap<String, SampleBean2>>() {}).getType());
+
+        HashMap<String, SampleBean2> map =
+            (HashMap<String, SampleBean2>)typedMapSerializer.readObject(new StringReader("{foo: {a:1, b:2, c:'3'}}"));
+
+        assertTrue(BeanAdapter.get(map, "foo") instanceof SampleBean2);
+        assertEquals(BeanAdapter.get(map, "foo.c"), "3");
+    }
+
+    /**
+     * Tests returning a subclass of a generic {@code org.apache.pivot.collections.Map}.
+     *
+     * @throws IOException
+     * @throws SerializationException
+     */
+    @Test
+    public void testMapSubclass() throws IOException, SerializationException {
+        JSONSerializer typedMapSerializer = new JSONSerializer(SampleBean2MapSubclass.class);
+
+        SampleBean2Map map =
+            (SampleBean2Map)typedMapSerializer.readObject(new StringReader("{foo: {a:1, b:2, c:'3'}}"));
+
+        assertTrue(BeanAdapter.get(map, "foo") instanceof SampleBean2);
+        assertEquals(BeanAdapter.get(map, "foo.c"), "3");
+    }
+
+    /**
+     * Tests returning a Java bean value.
+     *
+     * @throws IOException
+     * @throws SerializationException
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testBean() throws IOException, SerializationException {
+        JSONSerializer mapSerializer = new JSONSerializer();
+        Map<String, Object> map =
+            (Map<String, Object>)mapSerializer.readObject(getClass().getResourceAsStream("map.json"));
+
+        JSONSerializer beanSerializer = new JSONSerializer(SampleBean1.class);
+        SampleBean1 typedMap =
+            (SampleBean1)beanSerializer.readObject(getClass().getResourceAsStream("map.json"));
+
+        assertEquals(typedMap.getA(), BeanAdapter.get(map, "a"));
+        assertEquals(typedMap.getB(), BeanAdapter.get(map, "b"));
+        assertEquals(typedMap.getC(), BeanAdapter.get(map, "c"));
+        assertEquals(typedMap.getD(), BeanAdapter.get(map, "d"));
+        assertEquals(typedMap.getE(), BeanAdapter.get(map, "e"));
+        assertEquals(typedMap.getI().getA(), BeanAdapter.get(map, "i.a"));
+
+        Object k0 = typedMap.getK().get(0);
+        assertTrue(k0 instanceof SampleBean2);
+        assertEquals(typedMap.getK().get(0).getA(), BeanAdapter.get(map, "k[0].a"));
+    }
+}

Added: pivot/branches/3.x/core/test/org/apache/pivot/json/test/JSONSerializerTest.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/test/org/apache/pivot/json/test/JSONSerializerTest.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/test/org/apache/pivot/json/test/JSONSerializerTest.java (added)
+++ pivot/branches/3.x/core/test/org/apache/pivot/json/test/JSONSerializerTest.java Sun Jan  9 23:19:19 2011
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.pivot.json.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.pivot.beans.BeanAdapter;
+import org.apache.pivot.io.SerializationException;
+import org.apache.pivot.json.JSONSerializer;
+import org.apache.pivot.json.JSONSerializerListener;
+import org.junit.Test;
+
+public class JSONSerializerTest {
+    @Test
+    public void testCarriageReturns() {
+        List<?> emptyList;
+        try {
+            emptyList = JSONSerializer.parseList("[\n]");
+        } catch(SerializationException exception) {
+            throw new RuntimeException(exception);
+        }
+
+        assertEquals(0, emptyList.size());
+    }
+
+    @Test
+    public void testE() throws SerializationException {
+        assertEquals(5000000, JSONSerializer.parseDouble("5.0E6"), 0);
+        assertEquals(0.000005, JSONSerializer.parseDouble("5.0E-6"), 0);
+    }
+
+    @Test(expected=SerializationException.class)
+    public void testFloatNaN() throws SerializationException {
+        JSONSerializer.toString(Float.NaN);
+    }
+
+    @Test(expected=SerializationException.class)
+    public void testFloatNegativeInfinity() throws SerializationException {
+        JSONSerializer.toString(Float.NEGATIVE_INFINITY);
+    }
+
+    @Test(expected=SerializationException.class)
+    public void testFloatPositiveInfinity() throws SerializationException {
+        JSONSerializer.toString(Float.POSITIVE_INFINITY);
+    }
+
+    @Test(expected=SerializationException.class)
+    public void testDoubleNaN() throws SerializationException {
+        JSONSerializer.toString(Double.NaN);
+    }
+
+    @Test(expected=SerializationException.class)
+    public void testDoubleNegativeInfinity() throws SerializationException {
+        JSONSerializer.toString(Double.NEGATIVE_INFINITY);
+    }
+
+    @Test(expected=SerializationException.class)
+    public void testDoublePositiveInfinityN() throws SerializationException {
+        JSONSerializer.toString(Double.POSITIVE_INFINITY);
+    }
+
+    @Test
+    public void testEquals() throws IOException, SerializationException {
+        JSONSerializer jsonSerializer = new JSONSerializer();
+        JSONSerializerListener jsonSerializerListener = new JSONSerializerListener() {
+            @Override
+            public void beginMap(JSONSerializer jsonSerializer, Map<String, ?> value) {
+                System.out.println("Begin dictionary: " + value);
+            }
+
+            @Override
+            public void endMap(JSONSerializer jsonSerializer) {
+                System.out.println("End dictionary");
+            }
+
+            @Override
+            public void readKey(JSONSerializer jsonSerializer, String key) {
+                System.out.println("Read key: " + key);
+            }
+
+            @Override
+            public void beginList(JSONSerializer jsonSerializer, List<?> value) {
+                System.out.println("Begin sequence: " + value);
+            }
+
+            @Override
+            public void endList(JSONSerializer jsonSerializer) {
+                System.out.println("End sequence");
+            }
+
+            @Override
+            public void readString(JSONSerializer jsonSerializer, String value) {
+                System.out.println("Read string: " + value);
+            }
+
+            @Override
+            public void readNumber(JSONSerializer jsonSerializer, Number value) {
+                System.out.println("Read number: " + value);
+            }
+
+            @Override
+            public void readBoolean(JSONSerializer jsonSerializer, Boolean value) {
+                System.out.println("Read boolean: " + value);
+            }
+
+            @Override
+            public void readNull(JSONSerializer jsonSerializer) {
+                System.out.println("Read null");
+            }
+        };
+
+        jsonSerializer.getJSONSerializerListeners().add(jsonSerializerListener);
+        Object o1 = jsonSerializer.readObject(getClass().getResourceAsStream("map.json"));
+
+        jsonSerializer.getJSONSerializerListeners().remove(jsonSerializerListener);
+        Object o2 = jsonSerializer.readObject(getClass().getResourceAsStream("map.json"));
+
+        assertTrue(o1.equals(o2));
+
+        List<?> d = BeanAdapter.get(o1, "d");
+        d.remove(0);
+
+        assertFalse(o1.equals(o2));
+    }
+}