All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javolution.xml.internal.XMLContextImpl Maven / Gradle / Ivy

/*
 * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
 * Copyright (C) 2012 - Javolution (http://javolution.org/)
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software is
 * freely granted, provided that this notice is preserved.
 */
package javolution.xml.internal;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import javolution.context.LogContext;
import javolution.text.CharArray;
import javolution.text.TextBuilder;
import javolution.text.TextContext;
import javolution.text.TextFormat;
import javolution.util.FastMap;
import javolution.xml.DefaultXMLFormat;
import javolution.xml.XMLContext;
import javolution.xml.XMLFormat;
import javolution.xml.stream.XMLStreamException;

/**
 * Holds the default implementation of XMLContext.
 * 
 * @author  Jean-Marie Dautelle
 * @version 6.0, July 21, 2013
 */
@SuppressWarnings("rawtypes")
public final class XMLContextImpl extends XMLContext {

    // Holds class->format mapping. 
    private final FastMap, XMLFormat> classToFormat = new FastMap, XMLFormat>()
            .shared();

    // Holds parent (null if root).
    private final XMLContextImpl parent;

    /** Default constructor for root */
    public XMLContextImpl() {
        parent = null;
    }

    /** Inner constructor */
    public XMLContextImpl(XMLContextImpl parent) {
        this.parent = parent;
    }

    @Override
    protected XMLContext inner() {
        return new XMLContextImpl(this);
    }

    @SuppressWarnings("unchecked")
    @Override
    protected  XMLFormat searchFormat(Class type) {
        XMLFormat format = (XMLFormat) classToFormat.get(type);
        if (format != null) return format;
        if (parent != null) { // Searches parent.
            format = parent.searchFormat(type);
            classToFormat.put(type, format);
            return format;
        }
        // Root context (search inheritable annotations).
        DefaultXMLFormat annotation = type
                .getAnnotation(DefaultXMLFormat.class);
        if (annotation != null) { // Found it.
            try {
                format = (XMLFormat) annotation.value().newInstance();
                classToFormat.put(type, format);
                return format;
            } catch (Throwable error) {
                LogContext.warning(error);
            }
        }
        if (Collection.class.isAssignableFrom(type)) {
            classToFormat.put(type, COLLECTION_XML);
            return (XMLFormat) COLLECTION_XML;
        } else if (Map.class.isAssignableFrom(type)) {
            classToFormat.put(type, MAP_XML);
            return (XMLFormat) MAP_XML;
        } else {
            classToFormat.put(type, OBJECT_XML);
            return (XMLFormat) OBJECT_XML;
        }
    }

    @Override
    public  void setFormat(Class type, XMLFormat format) {
        classToFormat.put(type, format);
    }

    /////////////////////////
    // PREDEFINED FORMATS  //
    /////////////////////////

    /**
     * THe default Object XML representation consists of the text representation 
     * of the object as a "value" attribute.
     */
    private static final XMLFormat OBJECT_XML = new XMLFormat() {

        @Override
        public boolean isReferenceable() {
            return false; // Always by value.
        }

        @Override
        public Object newInstance(Class cls, XMLFormat.InputElement xml)
                throws XMLStreamException {
            TextFormat format = TextContext.getFormat(cls);
            CharArray value = xml.getAttribute("value");
            if (value == null) throw new XMLStreamException(
                    "Missing value attribute to parse " + cls + " instances.");
            return format.parse(value);
        }

        @Override
        public void read(XMLFormat.InputElement xml, Object obj)
                throws XMLStreamException {
            // Do nothing.
        }

        @Override
        public void write(Object obj, XMLFormat.OutputElement xml)
                throws XMLStreamException {
            TextBuilder tmp = new TextBuilder();
            TextFormat tf = TextContext.getFormat(obj.getClass());
            tf.format(obj, tmp);
            xml.setAttribute("value", tmp);
        }

    };

    /**
     * The default XML representation for {@link java.util.Collection}
     * consists of nested XML elements one for each element of the collection. 
     * The elements' order is defined by the collection iterator order. 
     * Collections are deserialized using their default constructor.
     */
    private static final XMLFormat COLLECTION_XML = new XMLFormat() {

        @SuppressWarnings("unchecked")
        @Override
        public void read(XMLFormat.InputElement xml, Collection collection)
                throws XMLStreamException {
            while (xml.hasNext()) {
                collection.add(xml.getNext());
            }
        }

        @Override
        public void write(Collection collection, XMLFormat.OutputElement xml)
                throws XMLStreamException {
            for (Iterator i = collection.iterator(); i.hasNext();) {
                xml.add(i.next());
            }
        }
    };

    /**
     * The default XML representation for {@link java.util.Map} consists of 
     * key/value pair as nested XML elements. For example:[code]
     * 
     *     
     *     
     *     
     *     
     *     
     *     
     * [/code]
     *
     * The elements' order is defined by the map's entries iterator order.
     * Maps are deserialized using their default constructor.
     */
    private static final XMLFormat MAP_XML = new XMLFormat() {

        @SuppressWarnings("unchecked")
        @Override
        public void read(XMLFormat.InputElement xml, Map map)
                throws XMLStreamException {
            while (xml.hasNext()) {
                Object key = xml.get("Key");
                Object value = xml.get("Value");
                map.put(key, value);
            }
        }

        @Override
        public void write(Map map, XMLFormat.OutputElement xml)
                throws XMLStreamException {
            for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
                Map.Entry entry = (Map.Entry) it.next();
                xml.add(entry.getKey(), "Key");
                xml.add(entry.getValue(), "Value");
            }
        }
    };
}