Open Source Repository

Home /open-symphony/oscore-2.2.6 | Repository Home


com/opensymphony/util/XMLReaderAdapter.java
/*
 * Copyright (c) 2002-2003 by OpenSymphony
 * All rights reserved.
 */
package com.opensymphony.util;

import org.xml.sax.*;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;

import java.io.IOException;

import java.lang.reflect.Method;

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


/**
 * XMLReaderAdapter converts a java bean to its xml representation. It does
 * this by simulating a SAX XMLReader which an xslt processor can use as
 * a SAXSource.
 *
 @author <a href="mailto:[email protected]">Victor Salaman</a>
 @version $Revision: 5 $
 */
public class XMLReaderAdapter implements Locator, XMLReader {
    //~ Static fields/initializers /////////////////////////////////////////////

    private static final Object[] NULLPARAMS = new Object[0];
    private static final String EMPTYSTRING = null//new String();

    //~ Instance fields ////////////////////////////////////////////////////////

    private AttributesImpl atts = new AttributesImpl();
    private ContentHandler contentHandler = new DefaultHandler();
    private Object object;
    private String root = null;
    private String systemId;

    //~ Constructors ///////////////////////////////////////////////////////////

    public XMLReaderAdapter(Object object) {
        this(object, null);
    }

    public XMLReaderAdapter(Object object, String root) {
        this.object = object;
        this.root = root;
    }

    //~ Methods ////////////////////////////////////////////////////////////////

    public int getColumnNumber() {
        return -1;
    }

    public void setContentHandler(ContentHandler handler) {
        this.contentHandler = handler;
    }

    public ContentHandler getContentHandler() {
        return contentHandler;
    }

    public void setDTDHandler(DTDHandler handler) {
    }

    public DTDHandler getDTDHandler() {
        return null;
    }

    public void setEntityResolver(EntityResolver resolver) {
    }

    public EntityResolver getEntityResolver() {
        return null;
    }

    public void setErrorHandler(ErrorHandler handler) {
    }

    public ErrorHandler getErrorHandler() {
        return null;
    }

    public void setFeature(String featureId, boolean onthrows SAXNotRecognizedException, SAXNotSupportedException {
    }

    public boolean getFeature(String featureIdthrows SAXNotRecognizedException {
        return false;
    }

    public int getLineNumber() {
        return -1;
    }

    public void setObject(Object object) {
        this.object = object;
    }

    public void setProperty(String propertyId, Object propertythrows SAXNotRecognizedException, SAXNotSupportedException {
    }

    public Object getProperty(String namethrows SAXNotRecognizedException {
        throw new SAXNotRecognizedException(name);
    }

    public String getPublicId() {
        return null;
    }

    public void setRoot(String root) {
        this.root = root;
    }

    public String getSystemId() {
        return systemId;
    }

    public void parse(InputSource sourcethrows IOException, SAXException {
        parse();
    }

    public void parse(String sthrows IOException, SAXException {
        parse();
    }

    public void parse() throws IOException, SAXException {
        if (object == null) {
            throw new SAXException("no object to reflected defined");
        }

        if (contentHandler == null) {
            throw new SAXException("no content handler defined");
        }

        contentHandler.setDocumentLocator(this);
        contentHandler.startDocument();
        walk(object, (root == null"data" : root, false);
        contentHandler.endDocument();
    }

    private String getTagName(String tagName) {
        boolean lastWasLower = false;
        int bufIndex = 0;
        int oIndex = tagName.length();
        StringBuffer buff = new StringBuffer(tagName);

        for (int i = 0; i < oIndex; i++) {
            char c = tagName.charAt(i);

            if (i > 0) {
                if (lastWasLower && Character.isUpperCase(c)) {
                    buff.setCharAt(bufIndex, Character.toLowerCase(c));
                    buff.insert(bufIndex, '-');
                    bufIndex++;
                }
            else {
                buff.setCharAt(0, Character.toLowerCase(c));
                lastWasLower = true;
            }

            bufIndex++;
        }

        return buff.toString();
    }

    private void walk(Object object, String name, boolean useKeythrows SAXException {
        boolean accessorsFound;

        if (!useKey) {
            contentHandler.startElement(EMPTYSTRING, name, EMPTYSTRING, atts);
        else {
            AttributesImpl atts = new AttributesImpl();
            atts.addAttribute(EMPTYSTRING, EMPTYSTRING, "key""key", name);
            contentHandler.startElement(EMPTYSTRING, "item", EMPTYSTRING, atts);
        }

        try {
            if (object != null) {
                Class c = object.getClass();

                if (c.isAssignableFrom(String.class)) {
                    String value = (Stringobject;
                    contentHandler.characters(value.toCharArray()0, value.length());
                else {
                    PropertyDescriptor[] props = Introspector.getBeanInfo(c, Object.class).getPropertyDescriptors();
                    accessorsFound = false;

                    for (int i = 0; i < props.length; i++) {
                        Method m = props[i].getReadMethod();
                        String s = m.getName();

                        if ((s.startsWith("get"&& (s.length() 3)) || (s.startsWith("is"&& (s.length() 2))) {
                            String attributeName = getTagName(s.substring(s.startsWith("is"3));
                            Class rt = m.getReturnType();

                            if (attributeName.equals("class")) {
                                continue;
                            }

                            if (m.getParameterTypes().length == 0) {
                                Object value = m.invoke(object, NULLPARAMS);

                                if (value == null) {
                                    continue;
                                }

                                accessorsFound = true;

                                if (Collection.class.isAssignableFrom(value.getClass())) {
                                    Collection cole = (Collectionvalue;
                                    contentHandler.startElement(EMPTYSTRING, attributeName, EMPTYSTRING, atts);

                                    for (Iterator colIter = cole.iterator();
                                            colIter.hasNext();) {
                                        Object obj = (ObjectcolIter.next();
                                        walk(obj, "item"false);
                                    }

                                    contentHandler.endElement(EMPTYSTRING, attributeName, EMPTYSTRING);

                                    continue;
                                else if (Enumeration.class.isAssignableFrom(value.getClass())) {
                                    Enumeration e = (Enumerationvalue;
                                    contentHandler.startElement(EMPTYSTRING, attributeName, EMPTYSTRING, atts);

                                    while (e.hasMoreElements()) {
                                        Object obj = (Objecte.nextElement();
                                        walk(obj, "item"false);
                                    }

                                    contentHandler.endElement(EMPTYSTRING, attributeName, EMPTYSTRING);

                                    continue;
                                else if (Vector.class.isAssignableFrom(value.getClass())) {
                                    Vector vec = (Vectorvalue;
                                    contentHandler.startElement(EMPTYSTRING, attributeName, EMPTYSTRING, atts);

                                    for (int ix = 0; ix < vec.size(); ix++) {
                                        Object obj = (Objectvec.elementAt(ix);
                                        walk(obj, "item"false);
                                    }

                                    contentHandler.endElement(EMPTYSTRING, attributeName, EMPTYSTRING);

                                    continue;
                                }

                                if (Map.class.isAssignableFrom(value.getClass())) {
                                    contentHandler.startElement(EMPTYSTRING, attributeName, EMPTYSTRING, atts);

                                    Map map = (Mapvalue;

                                    for (Iterator iter = map.entrySet().iterator();
                                            iter.hasNext();) {
                                        Map.Entry entry = (Map.Entryiter.next();
                                        walk(entry.getValue()(Stringentry.getKey()true);
                                    }

                                    contentHandler.endElement(EMPTYSTRING, attributeName, EMPTYSTRING);

                                    continue;
                                else {
                                    walk(value, attributeName, false);
                                }
                            }
                        }
                    }

                    if (!accessorsFound) {
                        contentHandler.characters(object.toString().toCharArray()0, object.toString().length());
                    }
                }
            }
        catch (Exception e) {
            throw new SAXException(e);
        }

        if (!useKey) {
            contentHandler.endElement(EMPTYSTRING, name, EMPTYSTRING);
        else {
            contentHandler.endElement(EMPTYSTRING, "item", EMPTYSTRING);
        }
    }
}