Package org.openquark.util.xml

Source Code of org.openquark.util.xml.XMLSerializationManager$ColorValueSerializer

/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Business Objects nor the names of its contributors
*       may be used to endorse or promote products derived from this software
*       without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/


/*
* XMLSerializationManager.java
* Created: Jul 29, 2004
* By: Kevin Sit
*/
package org.openquark.util.xml;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.openquark.util.Messages;
import org.openquark.util.attributes.Attribute;
import org.openquark.util.attributes.AttributeSet;
import org.openquark.util.time.Time;
import org.w3c.dom.Document;
import org.w3c.dom.Element;


/**
* The XML serialization manager takes care of 2 things.  First, it maintains a set of XMLElementSerializer
* objects.  These objects know how to do the actual serialization / deserialization work.  The manager
* can lookup the appropriate serializer based on the type of object being stored or the type of XML tag
* being read.
* Second, the manager maintains contextual information in the form of an attribute set.  At various points
* during loading or saving it may be necessary to temporarily hold onto some context information in order
* to successfully load or store objects.
*/
public final class XMLSerializationManager {
   
    /** Use this message bundle to dig up localized messages */
    private static final Messages messages = PackageMessages.instance;
   
    /**
     * The default tag name for an <code>AttributeSet</code>.
     */
    public static final String ATTRIBUTE_SET_TAG_NAME = "AttributeSet"; //$NON-NLS-1$
   
    /**
     * The default tag name for an <code>Attribute</code>.
     */
    public static final String ATTRIBUTE_TAG_NAME = "Attribute"; //$NON-NLS-1$
   
    /**
     * Stores the name of an attribute object (in Java) in a XML element attribute.
     */
    public static final String NAME_ATTR_NAME = "Name"; //$NON-NLS-1$
   
    /**
     * Stores the value of an attribute object (in Java) under this name.  This name
     * is usually used as a tag name only.
     */
    public static final String VALUE_ATTR_NAME = "Value"; //$NON-NLS-1$
   
    /**
     * Stores an integer value under this name.  This name can be used as a tag name
     * or an attribute name.
     */
    public static final String INTEGER_ATTR_NAME = "IntValue"; //$NON-NLS-1$
   
    /**
     * Stores a double value under this name.  This name can be used as a tag name
     * or an attribute name.
     */
    public static final String DOUBLE_ATTR_NAME = "DoubleValue"; //$NON-NLS-1$
   
    /**
     * Stores a boolean value under this name.  This name can be used as a tag name
     * or an attribute name.
     */
    public static final String BOOLEAN_ATTR_NAME = "BoolValue"//$NON-NLS-1$
   
    /**
     * Stores a string value under this name.  This name can be used as a tag name
     * or an attribute name.
     */
    public static final String STRING_ATTR_NAME = "StringValue"//$NON-NLS-1$
   
    /**
     * Stores a color value under this name.  This name can be used as a tag name
     * or an attribute name.
     */
    public static final String COLOR_ATTR_NAME = "ColourValue"//$NON-NLS-1$
   
    /**
     * Stores a time value under this name.  This name can be used as a tag name
     * or an attribute name.
     */
    public static final String TIME_ATTR_NAME = "TimeValue"; //$NON-NLS-1$
   
    /**
     * The default instance of this class, initialized with a default set of
     * element/attribute serializers.  This variable will be initialized when
     * <code>getDefaultInstance()</code> is called.
     */
    private static XMLSerializationManager defaultSerializer;
   
    /**
     * The parent serializer (optional).
     */
    private XMLSerializationManager parent;
   
    /**
     * This structure maps a tag name to a <code>XMLElementSerializer</code>.
     */
    private Map<String,XMLElementSerializer> elementSerializers = new HashMap<String,XMLElementSerializer>();
   
    /**
     * This structure maps a class to a <code>XMLElementSerializer</code>.
     *
     * TODO it is a little bit ugly to keep new hash maps: one for tag name
     *   (used mainly for loading) and one for class (used mainly for saving).
     *   But let's leave it for now.
     */
    private Map<Class<?>, XMLElementSerializer> classSerializers = new LinkedHashMap<Class<?>, XMLElementSerializer>();
   
    /**
     * This structure holds a list of attribute serializers.
     */
    private List<XMLAttributeSerializer> attributeSerializers = new ArrayList<XMLAttributeSerializer>();
   
    /**
     * Attributes of the serializer.  Callers can push extra information to
     * the serializer as attributes, so that the element serializer can make
     * use of these extra information.
     */
    private AttributeSet attributes = new AttributeSet();
   
    /**
     * This class is not intended for subclassing and it should never be
     * instantiated directly.  Use the <code>newInstance()</code> method
     * instead.
     */
    private XMLSerializationManager() {
    }
   
    /**
     * Sets the parent serializer.  The parent serializer will be used if an attribute
     * cannot be found in this instance.  The parent is also useful for finding
     * <code>XMLElementSerializer</code> if there is no suitable serializer registered
     * with this instance.
     * @param parent
     */
    public void setParent(XMLSerializationManager parent) {
        this.parent = parent;
    }
   
    /**
     * Sets an attribute in the serializer.  Use this carefully since this serializer
     * can be a shared instance.
     * @param name
     * @param value
     */
    public void setAttribute(String name, Object value) {
        attributes.setAttribute(new Attribute(name, value));
    }
   
    /**
     * Unsets an attribute in the serializer.  Use this carefully since this serializer
     * can be a shared instance.
     * @param name
     */
    public void unsetAttribute(String name) {
        attributes.removeAttribute(name);
    }
   
    /**
     * Returns an attribute value associated with the given name.
     * @param name
     * @return Object
     */
    public Object getAttribute(String name) {
        // Always start with this instance
        Object value = attributes.getAttributeSingleValue(name);
        if (value != null) {
            return value;
        }
        // Then, ask its parent, if there is one
        return parent == null ? null : parent.getAttribute(name);
    }
   
    /**
     * Associates a tag name with the given serializer.  This method should be
     * called before the XML serializer is first used.  Existing serializer mapped
     * to the tag name will be replaced.
     * @param tagName XML tag name
     * @param klass object value class
     * @param serializer
     */
    public void addElementSerializer(String tagName, Class<?> klass,
            XMLElementSerializer serializer) {
        elementSerializers.put(tagName, serializer);
        classSerializers.put(klass, serializer);
    }
   
    /**
     * Adds a new <code>XMLAttributeSerializer</code> implementation.
     * @param serializer
     */
    public void addAttributeSerializer(XMLAttributeSerializer serializer) {
        attributeSerializers.add(serializer);
    }
   
    /**
     * Returns a set of tag names that are supported by this serializer instance.
     * @return Set
     */
    public Set<String> getSupportedTagNames() {
        return Collections.unmodifiableSet(elementSerializers.keySet());
    }
   
    /**
     * Returns a set of classes (or types) that are supported by this serializer instance.
     * @return Set
     */
    public Set<Class<?>> getSupportedValueClasses() {
        return Collections.unmodifiableSet(classSerializers.keySet());
    }
   
    /**
     * Loads the given XML element and return a value.  This method uses the element's
     * tag name to find a suitable serializer to deserialize the XML element.
     * @param element
     * @return Object
     */
    public Object loadFromElement(Element element) {
        // The local name is only valid if the element was created with a prefix and namespace, or
        // if the element was loaded from disk.  If the element was created with createElement()
        // then the local name is null and the node name should be used (needed for the unit tests).
        String tagName = element.getLocalName();
        if (tagName == null) {
            tagName = element.getNodeName();
        }
       
        return loadFromElement(element, getValueSerializer(tagName));
    }
   
    /**
     * Deserializes the input XML element with the given serializer.
     * @param element
     * @param serializer
     * @return Object
     */
    public Object loadFromElement(Element element, XMLElementSerializer serializer) {
        if (serializer != null) {
            return serializer.loadFromElement(this, element);
        }
        return null;
    }
   
    /**
     * Loads a collection of objects from the children of the given element.
     * This method uses the internal element serializers.
     * @param element
     * @return Collection
     */
    public List<?> loadFromChildElements(Element element) {
        List<Object> result = new ArrayList<Object>();
        List<Element> children = XMLPersistenceHelper.getChildElements(element);
        for (Element childElem : children) {
            Object o = loadFromElement(childElem);
            if (o != null) {
                result.add(o);
            }
        }
        return result;
    }

    /**
     * Loads a collection of objects from the children of the given element.
     * This method uses the internal element serializers.
     * @param element
     * @param loaded the list into which to add the loaded objects
     */
    @SuppressWarnings("unchecked")
    public void loadFromChildElements(Element element, List loaded) {
        List<Element> children = XMLPersistenceHelper.getChildElements(element);
        for (Element childElem : children) {
            Object o = loadFromElement(childElem);
            if (o != null) {
                loaded.add(o);
            }
        }
    }
   
    /**
     * Loads a single value from the element, using the internal list of
     * <code>XMLAttributeSerializer</code>.
     * @param element
     * @return Object
     */
    public Object loadValueFromAttribute(Element element) {
        return loadValueFromAttribute(element, attributeSerializers);
    }
   
    /**
     * Loads a single value from the element, using the given list of <code>XMLAttributeSerializer</code>.
     * @param element
     * @param serializers
     * @return Object
     */
    public Object loadValueFromAttribute(Element element, List<XMLAttributeSerializer> serializers) {
        for (XMLAttributeSerializer serializer : serializers) {
            Object val = serializer.loadFromAttribute(element);
            if (val != null) {
                return val;
            }
        }
        return null;
    }
   
    /**
     * Stores the given value to the input element.  This method delegates the task
     * to the serializer that matches the given value's type (or class).  The
     * serializer may choose to create sub-elements under the input element.
     * @param element
     * @param value
     * @return boolean
     */
    public boolean storeToElement(Element element, Object value) {
        if (value != null) {
            XMLElementSerializer serializer = getValueSerializer(value.getClass());
            if (serializer != null) {
                return storeToElement(element, value, serializer);
            }
        }
        return false;
    }
   
    /**
     * Stores the value to the input element, using the given <code>XMLElementSerializer</code>.
     * @param element
     * @param value
     * @param serializer
     * @return boolean
     */
    public boolean storeToElement(Element element, Object value, XMLElementSerializer serializer) {
        serializer.storeToElement(this, element, value);
        return true;
    }
   
    /**
     * Stores all the given values under the given parent element.  This method
     * delegates the task to the serializer that matches the value's type (class). 
     * @param element
     * @param values
     * @return boolean
     */
    public boolean storeToElement(Element element, Collection<?> values) {
        boolean success = true;
        for (Object v : values) {
            success &= storeToElement(element, v);
        }
        return success;
    }
   
    /**
     * Stores the given value as an attribute to the specified element.
     * @param element
     * @param value
     * @return boolean
     */
    public boolean storeAsAttribute(Element element, Object value) {
        return storeAsAttribute(element, value, attributeSerializers);
    }
   
    /**
     * Stores the given value as an attribute to the specified element, using
     * the given list of attribute serializers.
     * @param element
     * @param value
     * @param serializers
     * @return boolean
     */
    public boolean storeAsAttribute(Element element, Object value, List<XMLAttributeSerializer> serializers) {
        if (value != null) {
            Class<?> cls = value.getClass();
            for (XMLAttributeSerializer serializer : serializers) {
                if (serializer.isSerializable(cls)) {
                    serializer.storeToAttribute(element, value);
                    return true;
                }
            }
        }
        return false;
    }
   
    /**
     * Returns a <code>XMLElementSerializer</code> that is mapped to the given
     * tag name.
     * @param tagName
     * @return XMLElementSerializer
     */
    private XMLElementSerializer getValueSerializer(String tagName) {
        XMLElementSerializer serializer = elementSerializers.get(tagName);
        if (serializer == null) {
            if (parent != null) {
                serializer = parent.getValueSerializer(tagName);
            }
            if (serializer == null) {
                // TODO use proper logging
                System.err.println(messages.getString("NoSerializerForTag", tagName)); //$NON-NLS-1$
            }
        }
        return serializer;
    }
   
    /**
     * Returns a <code>XMLElementSerializer</code> that is mapped to the given
     * class.  If there no serializer mapped directly to the given class,
     * then the entire map will be checked to find the first serializer
     * that is associated to the superclass(es) of the given class.
     * @param cls
     * @return XMLElementSerializer
     *
     * TODO it is possible to derive a mechanism to find the best match:
     * 1) calculate the "closeness" between the given class and the class
     *    used as the key and pick the one with the closest one
     * 2) search the list from the end
     */
    private XMLElementSerializer getValueSerializer(Class<?> cls) {
        // First search for an exact match, which should handle most of the cases
        XMLElementSerializer serializer = classSerializers.get(cls);
        if (serializer != null) {
            return serializer;
        }
       
        // can't find a match, look for the first superclass
        for (Class<?> c : classSerializers.keySet()) {
            if (c.isAssignableFrom(cls)) {
                return classSerializers.get(c);
            }
        }

        // ask the parent
        if (parent != null) {
            serializer = parent.getValueSerializer(cls);
        }
       
        // log an error if we cannot find a suitable serializer: most likely an error
        if (serializer == null) {
            // TODO use proper logging
            System.err.println(messages.getString("NoSerializerForClass", cls.getName())); //$NON-NLS-1$
        }
        return serializer;
    }
   
    /**
     * Returns the shared instance of the <code>XMLSerializer</code>.  This serializer
     * is initialized with the default set of element and attribute serializers.
     * Since this instance is shared, callers should never add any new serializers
     * to the return value.
     * @return XMLSerializer
     */
    public static XMLSerializationManager getDefaultInstance() {
        if (defaultSerializer == null) {
            defaultSerializer = newInstance();
        }
        return defaultSerializer;
    }
   
    /**
     * A convenient method for returning a new instance of the XML serializer
     * with a default set of <code>XMLElementSerializer</code>.
     * @return XMLSerializer
     */
    public static XMLSerializationManager newInstance() {
        XMLSerializationManager serializer = newEmptyInstance();
       
        // Registers all built-in element serializers
        serializer.addElementSerializer(ATTRIBUTE_SET_TAG_NAME, AttributeSet.class,
                AttributeSetValueSerializer.SINGLETON);
        serializer.addElementSerializer(ATTRIBUTE_TAG_NAME, Attribute.class,
                AttributeValueSerializer.SINGLETON);
        serializer.addElementSerializer(INTEGER_ATTR_NAME, Integer.class,
                IntegerValueSerializer.SINGLETON);
        serializer.addElementSerializer(DOUBLE_ATTR_NAME, Double.class,
                DoubleValueSerializer.SINGLETON);
        serializer.addElementSerializer(BOOLEAN_ATTR_NAME, Boolean.class,
                BooleanValueSerializer.SINGLETON);
        serializer.addElementSerializer(STRING_ATTR_NAME, String.class,
                StringValueSerializer.SINGLETON);
        serializer.addElementSerializer(COLOR_ATTR_NAME, Color.class,
                ColorValueSerializer.SINGLETON);
        serializer.addElementSerializer(TIME_ATTR_NAME, Time.class,
                TimeValueSerializer.SINGLETON);
       
        // Registers all built-in attribute serializers
        serializer.addAttributeSerializer(IntegerValueSerializer.SINGLETON);
        serializer.addAttributeSerializer(DoubleValueSerializer.SINGLETON);
        serializer.addAttributeSerializer(BooleanValueSerializer.SINGLETON);
        serializer.addAttributeSerializer(StringValueSerializer.SINGLETON);
        serializer.addAttributeSerializer(ColorValueSerializer.SINGLETON);
        serializer.addAttributeSerializer(TimeValueSerializer.SINGLETON);

        return serializer;
    }
   
    /**
     * A convenient method for returning a new instance of the XML serializer
     * without any built-in <code>XMLElementSerializer</code>.
     * @return XMLSerializer
     */
    public static XMLSerializationManager newEmptyInstance() {
        return new XMLSerializationManager();
    }
   
    /**
     * A convenient method for returning a shared instance of the <code>XMLElementSerializer</code>
     * that can serialize/deserialize an <code>AttributeSet</code>.
     * @return XMLElementSerializer
     */
    public static XMLElementSerializer getAttributeSetSerializer() {
        return AttributeSetValueSerializer.SINGLETON;
    }
   
    /**
     * A convenient method for returning a shared instance of the <code>XMLElementSerializer</code>
     * that can serialize/deserialize an <code>Attribute</code>.
     * @return XMLElementSerializer
     */
    public static XMLElementSerializer getAttributeSerializer() {
        return AttributeValueSerializer.SINGLETON;
    }

    /**
     * An implementation of the <code>XMLElementSerializer</code> interface for
     * serializing and deserializing an <code>AttributeSet</code> instance.
     */
    public static class AttributeSetValueSerializer implements XMLElementSerializer, Cloneable {
       
        /**
         * A shared instance of this serializer.
         */
        public static final AttributeSetValueSerializer SINGLETON = new AttributeSetValueSerializer();
       
        /**
         * The tag to give elements created
         */
        public String tagName;
       
        /**
         *
         */
        public AttributeSetValueSerializer() {
            this(null);
        }
       
        /**
         * Stores the attributes in this set under this tag name.  If the name is <code>null</code>,
         * the attributes will be stored as a flat list, without an enclosing tag.
         * @param tagName
         */
        public AttributeSetValueSerializer(String tagName) {
            this.tagName = tagName;
        }
       
        /**
         * @see org.openquark.util.xml.XMLElementSerializer#loadFromElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element)
         */
        public Object loadFromElement(XMLSerializationManager manager, Element element) {
            AttributeSet attributes = createNewAttributeSet();
            List<Element> children = XMLPersistenceHelper.getChildElements(element);
            for (Element childElem : children) {
                Object data = manager.loadFromElement(childElem);
                if (data instanceof Attribute) {
                    attributes.setAttribute((Attribute) data);
                }
            }
            return attributes;
        }
       
        /**
         * @see org.openquark.util.xml.XMLElementSerializer#storeToElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToElement(XMLSerializationManager manager, Element element, Object value) {
            // Create the enclosing tag if necessary
            if (tagName != null) {
                Document document = element.getOwnerDocument ();
                Element attributeSetElement = document.createElement(tagName);
                element.appendChild(attributeSetElement);
                element = attributeSetElement;
            }
           
            // Sort the attributes alphabetically so that they will be saved in a consistent
            // order each time
            AttributeSet attributes = (AttributeSet)value;
            List<Attribute> sortedAttrs = attributes.getAttributesAsList();
            Collections.sort(sortedAttrs, Attribute.getNameComparator());
            for (Attribute attribute : sortedAttrs) {
                manager.storeToElement(element, attribute);
            }
        }
       
        /**
         * Returns a copy of this instance.
         * @return AttributeSetValueSerializer
         */
        public AttributeSetValueSerializer copyInstance() {
            try {
                return (AttributeSetValueSerializer) clone();
            } catch (CloneNotSupportedException cnse) {
                // should not happen
                return new AttributeSetValueSerializer(tagName);
            }
        }
       
        /**
         * Creates a new <code>AttributeSet</code> instance.
         * <p>
         * Subclasses can override this method.
         * @return AttributeSet
         */
        protected AttributeSet createNewAttributeSet() {
            return new AttributeSet();
        }
    }
   
    /**
     * An implementation of the <code>XMLElementSerializer</code> interface for
     * serializing and deserializing an <code>Attribute</code> instance.
     */
    public static class AttributeValueSerializer implements XMLElementSerializer, Cloneable {
       
        /**
         * A shared instance of this serializer.
         */
        public static final AttributeValueSerializer SINGLETON = new AttributeValueSerializer();
       
        /**
         * Use this tag name for the name of the XML tag.
         */
        public final String tagName;
       
        /**
         * Default constructor, tag set to ATTRIBUTE_TAG_NAME
         */
        public AttributeValueSerializer() {
            this(ATTRIBUTE_TAG_NAME);
        }
       
        /**
         * Construtor with a specfic tag.
         * @param tagName
         */
        public AttributeValueSerializer(String tagName) {
            this.tagName = tagName;
        }
       
        /**
         * @see org.openquark.util.xml.XMLElementSerializer#loadFromElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element)
         */
        public Object loadFromElement(XMLSerializationManager manager, Element element) {
            // Load the attribute name.
            // First try to load this from the Name attribute.
            String attributeName = element.getAttribute(NAME_ATTR_NAME);

            // If there is no Name attribute, then attempt to load the name from a child element.
            if (attributeName == null || attributeName.length() == 0) {
                Element nameElement = XMLPersistenceHelper.getChildElement(element, NAME_ATTR_NAME);
                if (nameElement != null)
                    attributeName = XMLPersistenceHelper.getChildText(nameElement);
            }

            // Make sure that an attribute name was specified.
            if (attributeName == null || attributeName.length() == 0)
                return null;

            // Check whether a value is stored as an attribute.
            Object attrValue = manager.loadValueFromAttribute(element);
            if (attrValue != null) {
                return createAttribute(attributeName, attrValue);
            }
           
            // Load the attribute values from the Value child element.
            Element valueNode = XMLPersistenceHelper.getChildElement(element, VALUE_ATTR_NAME);
            if (valueNode == null) {
                return null;
            }

            // If there is a "Value" node, loads the child element as a collection
            // of values
            Collection<?> values = manager.loadFromChildElements(valueNode);
            if (values.isEmpty()) {
                return null;
            } else {
                return createAttribute(attributeName, values);
            }
        }
       
        /**
         * @see org.openquark.util.xml.XMLElementSerializer#storeToElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToElement(XMLSerializationManager manager, Element element, Object value) {
            // Don't store the attribute if it has no values.
            Attribute attribute = (Attribute) value;
            List<?> values = attribute.getValues();
            if (values.isEmpty()) {
                return;
            }
           
            Document document = element.getOwnerDocument ();
            Element attrElement = document.createElement(tagName);
            element.appendChild(attrElement);

            // Store the name member as an attribute.
            attrElement.setAttribute(NAME_ATTR_NAME, attribute.getName());

            // Store the value member.
            if (values.size() == 1) {
                // attempts to store the single value as an attribute, if it does not work, attempt
                // to store it as an element
                if (manager.storeAsAttribute(attrElement, attribute.getSingleValue())) {
                    return;
                }
            }

            // If the value cannot be stored as an attribute or there are multiple values,
            // then store these under a Value child element.
            Element valueElement = document.createElement(VALUE_ATTR_NAME);
            attrElement.appendChild(valueElement);
            for (Object valueObject : values) {
                if (valueObject instanceof AttributeSet) {
                    // We need special handling for attribute set.  Instead of
                    // storing the attributes as a plain list, create an attribute set
                    // element and use it to wrap around the attributes.  This is necessary
                    // because when we deserialize the values, we want to deserialize it
                    // as an AttributeSet instead of a Collection of Attribute's
                    XMLElementSerializer s = manager.getValueSerializer(valueObject.getClass());
                    if (s instanceof AttributeSetValueSerializer) {
                        AttributeSetValueSerializer valueSerializer = (AttributeSetValueSerializer) s;
                        if (valueSerializer.tagName == null) {
                            valueSerializer = valueSerializer.copyInstance();
                            valueSerializer.tagName = ATTRIBUTE_SET_TAG_NAME;
                        }
                        manager.storeToElement(valueElement, valueObject, valueSerializer);
                    }
                } else {
                    manager.storeToElement(valueElement, valueObject);
                }
            }
        }
       
        /**
         * Returns a new attribute with the given name-value pair.
         * @param name
         * @param value
         * @return Attribute
         */
        protected Attribute createAttribute(String name, Object value) {
            return new Attribute(name, value);
        }
       
        /**
         * Returns a new attribute with the given name, and the associated value collection.
         * @param name
         * @param values
         * @return Attribute
         */
        protected Attribute createAttribute(String name, Collection<?> values) {
            return new Attribute(name, values);
        }
       
        /**
         * Returns a copy of this serializer instance.
         * @return AttributeValueSerializer
         */
        public AttributeValueSerializer copyInstance() {
            try {
                return (AttributeValueSerializer) clone();
            } catch (CloneNotSupportedException cnse) {
                return new AttributeValueSerializer(tagName);
            }
        }
       
    }
   
    /**
     * An implementation of the <code>XMLElementSerializer</code> interface for
     * serializing and deserializing a <code>Number</code> object.
     */
    public static abstract class NumberValueSerializer
            implements XMLElementSerializer, XMLAttributeSerializer {
       
        /**
         * @see org.openquark.util.xml.XMLElementSerializer#loadFromElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element)
         */
        public Object loadFromElement(XMLSerializationManager manager, Element element) {
            return parse(XMLPersistenceHelper.getChildText(element));
        }

        /**
         * @see org.openquark.util.xml.XMLElementSerializer#storeToElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToElement(XMLSerializationManager manager, Element element,
                Object value) {
            Document document = element.getOwnerDocument();

            // Store the integer value.
            Element numberElement = document.createElement(getName());
            numberElement.appendChild(document.createTextNode(format((Number) value)));
            element.appendChild(numberElement);
        }

        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#loadFromAttribute(org.w3c.dom.Element)
         */
        public Object loadFromAttribute(Element element) {
            String str = element.getAttribute(getName());
            if (str != null && str.length() != 0) {
                return parse(str);
            }
            return null;
        }
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#storeToAttribute(org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToAttribute(Element element, Object value) {
            element.setAttribute(getName(), format((Number) value));
        }
       
        /**
         * Subclasses must override this method to provide the tag/attribute name.
         * @return String
         */
        protected abstract String getName();
       
        /**
         * Subclasses must override this to provide an implementation for converting
         * a string to a number.
         * @param string
         * @return Number
         */
        protected abstract Number parse(String string);
       
        /**
         * Subclasses must override this to provide an implementation for formatting
         * a number to a string.  By default, this method invokes <code>toString()</code>
         * on the number.
         * @param number
         * @return String
         */
        protected String format(Number number) {
            return number.toString();
        }
       
    }

    /**
     * An implementation of the <code>XMLElementSerializer</code> interface and
     * the <code>XMLAttributeSerializer</code> interface for serializing and
     * deserializing an <code>Integer</code>.
     */
    public static class IntegerValueSerializer extends NumberValueSerializer {
       
        /**
         * A shared instance of this serializer.
         */
        public static final IntegerValueSerializer SINGLETON = new IntegerValueSerializer();
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#isSerializable(java.lang.Class)
         */
        public boolean isSerializable(Class<?> c) {
            return Integer.class.isAssignableFrom(c);
        }
       
        /**
         * @see org.openquark.util.xml.XMLSerializationManager.NumberValueSerializer#getName()
         */
        protected String getName() {
            return INTEGER_ATTR_NAME;
        }
       
        /**
         * @see org.openquark.util.xml.XMLSerializationManager.NumberValueSerializer#parse(java.lang.String)
         */
        protected Number parse(String string) {
            return Integer.valueOf(string);
        }
    }
   
    /**
     * An implementation of the <code>XMLElementSerializer</code> interface and
     * the <code>XMLAttributeSerializer</code> interface for serializing and
     * deserializing a <code>Double</code>.
     */
    public static class DoubleValueSerializer extends NumberValueSerializer {
       
        /**
         * A shared instance of this serializer.
         */
        public static final DoubleValueSerializer SINGLETON = new DoubleValueSerializer();
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#isSerializable(java.lang.Class)
         */
        public boolean isSerializable(Class<?> c) {
            return Double.class.isAssignableFrom(c);
        }

        /**
         * @see org.openquark.util.xml.XMLSerializationManager.NumberValueSerializer#getName()
         */
        protected String getName() {
            return DOUBLE_ATTR_NAME;
        }
       
        /**
         * @see org.openquark.util.xml.XMLSerializationManager.NumberValueSerializer#parse(java.lang.String)
         */
        protected Number parse(String string) {
            return Double.valueOf(string);
        }
    }
   
    /**
     * An implementation of the <code>XMLElementSerializer</code> interface and
     * the <code>XMLAttributeSerializer</code> interface for serializing and
     * deserializing a <code>Boolean</code>.
     */
    public static class BooleanValueSerializer implements XMLElementSerializer, XMLAttributeSerializer {
       
        private static final String FALSE = "false"; //$NON-NLS-1$
        private static final String TRUE = "true"; //$NON-NLS-1$
       
        /**
         * A shared instance of this serializer.
         */
        public static final BooleanValueSerializer SINGLETON = new BooleanValueSerializer();
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#isSerializable(java.lang.Class)
         */
        public boolean isSerializable(Class<?> c) {
            return Boolean.class.isAssignableFrom(c);
        }
       
        /**
         * @see org.openquark.util.xml.XMLElementSerializer#loadFromElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element)
         */
        public Object loadFromElement(XMLSerializationManager manager, Element element) {
            String boolText = XMLPersistenceHelper.getChildText(element);
            return Boolean.valueOf(boolText.equalsIgnoreCase(TRUE));
        }

        /**
         * @see org.openquark.util.xml.XMLElementSerializer#storeToElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToElement(XMLSerializationManager manager, Element element,
                Object value) {
            Document document = element.getOwnerDocument();

            // Store the boolean value.
            Element boolElement = document.createElement(BOOLEAN_ATTR_NAME);
            String booleanString = ((Boolean) value).booleanValue() ? TRUE : FALSE; 
            boolElement.appendChild(document.createTextNode(booleanString));
            element.appendChild (boolElement);
        }

        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#loadFromAttribute(org.w3c.dom.Element)
         */
        public Object loadFromAttribute(Element element) {
            String str = element.getAttribute(BOOLEAN_ATTR_NAME);
            if (str != null && str.length() != 0) {
                return Boolean.valueOf(str.equalsIgnoreCase (TRUE));
            }
            return null;
        }

        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#storeToAttribute(org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToAttribute(Element element, Object value) {
            Boolean boolVal = (Boolean) value;
            element.setAttribute(BOOLEAN_ATTR_NAME, boolVal.booleanValue() ? TRUE : FALSE);
        }
    }
   
    /**
     * An implementation of the <code>XMLElementSerializer</code> interface and
     * the <code>XMLAttributeSerializer</code> interface for serializing and
     * deserializing a <code>String</code>.
     */
    public static class StringValueSerializer implements XMLElementSerializer, XMLAttributeSerializer {
       
        /**
         * A shared instance of this serializer.
         */
        public static final StringValueSerializer SINGLETON = new StringValueSerializer();
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#isSerializable(java.lang.Class)
         */
        public boolean isSerializable(Class<?> c) {
            return String.class.isAssignableFrom(c);
        }
       
        /**
         * @see org.openquark.util.xml.XMLElementSerializer#loadFromElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element)
         */
        public Object loadFromElement(XMLSerializationManager manager, Element element) {
            return XMLPersistenceHelper.getChildText(element);
        }

        /**
         * @see org.openquark.util.xml.XMLElementSerializer#storeToElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToElement(XMLSerializationManager manager, Element element, Object value) {
            Document document = element.getOwnerDocument();

            // Store the string value.
            Element stringElement = document.createElement(STRING_ATTR_NAME);
            stringElement.appendChild(document.createTextNode((String) value));
            element.appendChild(stringElement);
        }
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#loadFromAttribute(org.w3c.dom.Element)
         */
        public Object loadFromAttribute(Element element) {
            if (element.hasAttribute(STRING_ATTR_NAME)) {
                return element.getAttribute(STRING_ATTR_NAME);
            }
            return null;
        }
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#storeToAttribute(org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToAttribute(Element element, Object value) {
            element.setAttribute(STRING_ATTR_NAME, value.toString ());
        }
    }

    /**
     * An implementation of the <code>XMLElementSerializer</code> interface and
     * the <code>XMLAttributeSerializer</code> interface for serializing and
     * deserializing a <code>Color</code> object.
     */
    public static class ColorValueSerializer implements XMLElementSerializer, XMLAttributeSerializer {

        private static final String RED = "r"; //$NON-NLS-1$
        private static final String GREEN = "g"; //$NON-NLS-1$
        private static final String BLUE = "b"; //$NON-NLS-1$
       
        /**
         * A shared instance of this serializer.
         */
        public static final ColorValueSerializer SINGLETON = new ColorValueSerializer();
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#isSerializable(java.lang.Class)
         */
        public boolean isSerializable(Class<?> c) {
            return Color.class.isAssignableFrom(c);
        }
       
        /**
         * @see org.openquark.util.xml.XMLElementSerializer#loadFromElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element)
         */
        public Object loadFromElement(XMLSerializationManager manager, Element element) {
            Element childElem;

            childElem = XMLPersistenceHelper.getChildElement(element, RED);
            String rText = (childElem == null) ? null : XMLPersistenceHelper.getChildText(childElem);

            childElem = XMLPersistenceHelper.getChildElement(element, GREEN);
            String gText = (childElem == null) ? null : XMLPersistenceHelper.getChildText(childElem);

            childElem = XMLPersistenceHelper.getChildElement(element, BLUE);
            String bText = (childElem == null) ? null : XMLPersistenceHelper.getChildText(childElem);

            int r = (rText == null) ? 0 : Integer.parseInt(rText);
            int g = (gText == null) ? 0 : Integer.parseInt(gText);
            int b = (bText == null) ? 0 : Integer.parseInt(bText);

            return new Color (r, g, b);
        }

        /**
         * @see org.openquark.util.xml.XMLElementSerializer#storeToElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToElement(XMLSerializationManager manager, Element element,
                Object value) {
            Document document = element.getOwnerDocument ();

            Color c = (Color) value;
            Element colourElement = document.createElement ("Colour"); //$NON-NLS-1$
            colourElement.setAttribute(RED, Integer.toString(c.getRed ()));
            colourElement.setAttribute(GREEN, Integer.toString(c.getGreen ()));
            colourElement.setAttribute(BLUE, Integer.toString(c.getBlue ()));

            element.appendChild(colourElement);
        }
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#loadFromAttribute(org.w3c.dom.Element)
         */
        public Object loadFromAttribute(Element element) {
            String valueText = element.getAttribute(COLOR_ATTR_NAME);
            if (valueText != null && valueText.length() != 0) {
                // The 3 colour components (rgb) should be separated by spaces.
                String [] rgbValues = valueText.split (" "); //$NON-NLS-1$

                if (rgbValues != null && rgbValues.length >= 3) {
                    int r = Integer.parseInt (rgbValues[0]);
                    int g = Integer.parseInt (rgbValues[1]);
                    int b = Integer.parseInt (rgbValues[2]);
                    return new Color (r, g, b);
                }
            }
            return null;
        }
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#storeToAttribute(org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToAttribute(Element element, Object value) {
            Color c = (Color) value;
            String colString = Integer.toString (c.getRed ()) + " " //$NON-NLS-1$
                               Integer.toString (c.getGreen ()) + " " //$NON-NLS-1$
                               Integer.toString (c.getBlue ());
            element.setAttribute(COLOR_ATTR_NAME, colString);
        }
    }
   
    /**
     * An implementation of the <code>XMLElementSerializer</code> interface and
     * the <code>XMLAttributeSerializer</code> interface for serializing and
     * deserializing a <code>Time</code> object.
     */
    public static class TimeValueSerializer implements XMLElementSerializer, XMLAttributeSerializer {

        /**
         * A shared instance of this serializer.
         */
        public static final TimeValueSerializer SINGLETON = new TimeValueSerializer();
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#isSerializable(java.lang.Class)
         */
        public boolean isSerializable(Class<?> c) {
            return Time.class.isAssignableFrom(c);
        }
       
        /**
         * @see org.openquark.util.xml.XMLElementSerializer#loadFromElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element)
         */
        public Object loadFromElement(XMLSerializationManager manager, Element element) {
            String valueText = XMLPersistenceHelper.getChildText(element);
            return Time.fromSerializedForm(valueText);
        }
       
        /**
         * @see org.openquark.util.xml.XMLElementSerializer#storeToElement(org.openquark.util.xml.XMLSerializationManager, org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToElement(XMLSerializationManager manager, Element element,
                Object value) {
            Document document = element.getOwnerDocument();

            // Store the time value.
            Time time = (Time) value;
            Element timeElement = document.createElement(TIME_ATTR_NAME);
            timeElement.appendChild(document.createTextNode(time.toSerializedForm()));
            element.appendChild(timeElement);
        }
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#loadFromAttribute(org.w3c.dom.Element)
         */
        public Object loadFromAttribute(Element element) {
            String valueText = element.getAttribute(TIME_ATTR_NAME);
            if (valueText != null && valueText.length() != 0) {
                return Time.fromSerializedForm(valueText);
            }
            return null;
        }
       
        /**
         * @see org.openquark.util.xml.XMLAttributeSerializer#storeToAttribute(org.w3c.dom.Element, java.lang.Object)
         */
        public void storeToAttribute(Element element, Object value) {
            Time time = (Time) value;
            element.setAttribute(TIME_ATTR_NAME, time.toSerializedForm());
        }
    }
   
}
TOP

Related Classes of org.openquark.util.xml.XMLSerializationManager$ColorValueSerializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.