/*
* 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());
}
}
}