openwfe.org.util.beancoder.XmlBeanCoder Maven / Gradle / Ivy
/*
* Copyright (c) 2006, John Mettraux, OpenWFE.org
* 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 the "OpenWFE" 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.
*
* $Id: ReflectionUtils.java 2673 2006-05-26 21:08:46Z jmettraux $
*/
//
// XmlBeanCoder.java
//
// [email protected]
//
// generated with
// jtmpl 1.1.01 2004/05/19 ([email protected])
//
package openwfe.org.util.beancoder;
import java.lang.reflect.Method;
import openwfe.org.xml.XmlUtils;
import openwfe.org.misc.Base64;
/**
* The first implementation of BeanCoder; will supplant xml.XmlCoder soon.
*
* CVS Info :
*
$Author$
*
$Id$
*
* @author [email protected]
*/
public class XmlBeanCoder
extends AbstractBeanCoder
{
private final static org.apache.log4j.Logger log = org.apache.log4j.Logger
.getLogger(XmlBeanCoder.class.getName());
//
// CONSTANTS & co
private final static String E_INSTANCE
= "instance";
private final static String E_BEAN
= "bean";
private final static String E_FIELD
= "field";
private final static String E_ARRAY
= "array";
private final static String E_BYTE_ARRAY
= "byte-array";
private final static String E_PRIMITIVE
= "primitive";
private final static String E_MAP
= "map";
private final static String E_COLLECTION
= "collection";
private final static String E_NULL
= "null";
private final static String E_JDOM
= "jdom";
private final static String E_RAW_XML
= "raw-xml";
private final static String E_ENTRY
= "entry";
private final static String A_CLASS
= "class";
private final static String A_SIZE
= "size";
private final static String A_NAME
= "name";
protected final static int T_XML = 10;
//
// FIELDS
private org.jdom.Document document = null;
private org.jdom.Element currentElement = null;
//
// CONSTRUCTORS
public XmlBeanCoder ()
{
super();
}
public XmlBeanCoder (final org.jdom.Document doc)
{
super();
this.document = doc;
this.currentElement = doc.getRootElement();
}
public XmlBeanCoder (final org.jdom.Element elt)
{
super();
//this.document = doc;
this.currentElement = elt;
}
//
// METHODS
protected org.jdom.Document getResult ()
{
return this.document;
}
protected void addContent (final org.jdom.Content con)
{
this.currentElement.addContent(con);
}
protected void beginElement (final org.jdom.Element elt)
{
if (this.document == null)
{
this.document = new org.jdom.Document();
this.document.setRootElement(elt);
this.currentElement = elt;
return;
}
this.currentElement.addContent(elt);
this.currentElement = elt;
}
//
// METHODS from AbstractBeanCoder
// DECODING
/**
* Overriding decodeBean() in the parent class to make sure that
* embedded XML content doesn't get mistaken as a bean.
*/
protected Object decodeBean ()
throws BeanCoderException
{
if (currentType() == T_XML)
return decodeXmlContent();
return super.decodeBean();
}
protected org.jdom.Content decodeXmlContent ()
{
return XmlUtils.getFirstContent(this.currentElement);
}
protected int currentType ()
throws BeanCoderException
{
final String eName = this.currentElement.getName();
if (eName.equals(E_RAW_XML)) return T_XML;
if (eName.equals(E_JDOM)) return T_XML;
if (eName.equals(E_ARRAY)) return T_ARRAY;
if (eName.equals(E_BYTE_ARRAY)) return T_BYTE_ARRAY;
if (eName.equals(E_MAP)) return T_MAP;
if (eName.equals(E_COLLECTION)) return T_COLLECTION;
if (eName.equals(E_PRIMITIVE)) return T_PRIMITIVE;
if (eName.equals(E_NULL)) return T_NULL;
if (eName.equals(E_BEAN)) return T_BEAN;
if (eName.equals(E_INSTANCE)) return T_BEAN;
return T_UNKNOWN; // shouldn't occur though
}
protected String currentClassName ()
throws BeanCoderException
{
return this.currentElement.getAttributeValue(A_CLASS);
}
protected Class currentClass ()
throws BeanCoderException
{
final String className = currentClassName();
try
{
return Class.forName(className);
}
catch (final Throwable t)
{
throw new BeanCoderException
("failed to find class named '"+className+"'", t);
}
}
protected int subElementCount ()
throws BeanCoderException
{
return this.currentElement.getChildren().size();
}
protected java.util.Iterator subElementIterator ()
throws BeanCoderException
{
return new ElementIterator(this.currentElement);
}
protected String currentFieldName ()
throws BeanCoderException
{
if ( ! this.currentElement.getName().equals(E_FIELD)) return null;
return this.currentElement.getAttributeValue(A_NAME);
}
protected String currentText ()
throws BeanCoderException
{
return this.currentElement.getText();
}
protected Object decodeFieldValue ()
throws BeanCoderException
{
final org.jdom.Element e = this.currentElement;
this.currentElement =
(org.jdom.Element)this.currentElement.getChildren().get(0);
final Object result = decode();
this.currentElement = e;
return result;
}
protected byte[] decodeByteArray ()
throws BeanCoderException
{
final org.jdom.CDATA cd =
(org.jdom.CDATA)this.currentElement.getContent().get(0);
final String s = cd.getTextTrim();
try
{
return Base64.decode(s.getBytes("ascii"));
}
catch (final Throwable t)
{
throw new BeanCoderException
("failed to decode base64 into a byte array", t);
}
}
// ENCODING
/**
* Overriding encodeBean() to make sure that XML content is embedded
* into the XML tree under construction.
*/
protected void encodeBean (final Object bean)
throws BeanCoderException
{
if (bean instanceof org.jdom.Content ||
bean instanceof org.jdom.Document)
{
encodeXmlContent(bean);
return;
}
super.encodeBean(bean);
}
protected void encodeXmlContent (final Object xml)
{
org.jdom.Content con = null;
if (xml instanceof org.jdom.Content)
con = (org.jdom.Content)xml;
else
con = ((org.jdom.Document)xml).getRootElement();
final org.jdom.Element e = new org.jdom.Element(E_RAW_XML);
con = (org.jdom.Content)con.clone();
con.detach();
e.addContent(con);
addContent(e);
}
protected void encodeByteArray (final byte[] array)
throws BeanCoderException
{
final org.jdom.Element e = new org.jdom.Element(E_BYTE_ARRAY);
String s = null;
try
{
s = new String(Base64.encode(array), "ascii");
}
catch (final Throwable t)
{
throw new BeanCoderException
("failed to encode byte array", t);
}
final org.jdom.CDATA cd = new org.jdom.CDATA(s);
e.addContent(cd);
addContent(e);
}
protected void encodeEntry (final int index, final Object entry)
throws BeanCoderException
{
encode(entry);
}
protected void endElement ()
throws BeanCoderException
{
this.currentElement = this.currentElement.getParentElement();
}
protected void encodeNull ()
throws BeanCoderException
{
addContent(new org.jdom.Element(E_NULL));
}
protected void encodePrimitive (final Object bean)
throws BeanCoderException
{
final org.jdom.Element elt = new org.jdom.Element(E_PRIMITIVE);
elt.setAttribute(A_CLASS, bean.getClass().getName());
//elt.addContent(new org.jdom.Text(bean.toString()));
org.jdom.Text t = null;
try
{
t = new org.jdom.Text(bean.toString());
}
catch (final org.jdom.IllegalDataException ide)
{
if (log.isDebugEnabled())
log.debug("encodePrimitive() having to use CDATA");
t = new org.jdom.CDATA(bean.toString());
}
elt.addContent(t);
addContent(elt);
}
protected void encodeField (final String fieldName, final Object value)
throws BeanCoderException
{
final org.jdom.Element elt = new org.jdom.Element(E_FIELD);
elt.setAttribute(A_NAME, fieldName);
beginElement(elt);
encode(value);
endElement();
}
protected void beginArray (int length)
throws BeanCoderException
{
final org.jdom.Element elt = new org.jdom.Element(E_ARRAY);
elt.setAttribute(A_SIZE, ""+length);
beginElement(elt);
}
/**
* classy, isn't it ?
*/
protected void beginWithClass (final String eltName, final Object bean)
{
final org.jdom.Element elt = new org.jdom.Element(eltName);
elt.setAttribute(A_CLASS, bean.getClass().getName());
beginElement(elt);
}
protected void beginBean (final Object bean)
throws BeanCoderException
{
//beginWithClass(E_INSTANCE, bean);
beginWithClass(E_BEAN, bean);
}
protected void beginMap (final java.util.Map map)
throws BeanCoderException
{
beginWithClass(E_MAP, map);
}
protected void beginMapEntry ()
throws BeanCoderException
{
final org.jdom.Element elt = new org.jdom.Element(E_ENTRY);
beginElement(elt);
}
protected void beginCollection (final java.util.Collection col)
throws BeanCoderException
{
beginWithClass(E_COLLECTION, col);
}
//
// INNER CLASSES
/**
* This special iterator directly impacts the 'currentElement' field
* of its containing class.
*/
protected class ElementIterator
implements java.util.Iterator
{
private int position = 0;
private org.jdom.Element entryElt = null;
/**
* Builds an iterator on the child elements of the given
* entry element.
*/
public ElementIterator (final org.jdom.Element entryElt)
{
this.entryElt = entryElt;
}
public boolean hasNext ()
{
return this.position < this.entryElt.getChildren().size();
}
/**
* Simply positions the currentElement of XmlBeanCoder to the next
* child of the entryElt subject to the iteration.
* Always returns null.
*/
public Object next ()
{
XmlBeanCoder.this.currentElement =
(org.jdom.Element)this.entryElt
.getChildren().get(this.position);
this.position = this.position + 1;
return null;
//
// no need to return anything, currentElement is important
}
/**
* Empty.
*/
public void remove ()
{
}
}
//
// STATIC METHODS
public static org.jdom.Document xmlEncode (final Object bean)
throws BeanCoderException
{
final XmlBeanCoder coder = new XmlBeanCoder();
coder.encode(bean);
return coder.getResult();
}
public static Object xmlDecode (final org.jdom.Document doc)
throws BeanCoderException
{
final XmlBeanCoder coder = new XmlBeanCoder(doc);
return coder.decode();
}
public static Object xmlDecode (final org.jdom.Element elt)
throws BeanCoderException
{
final XmlBeanCoder coder = new XmlBeanCoder(elt);
return coder.decode();
}
/**
* Loading an object from a file
*/
public static Object load (final String fileName)
throws java.io.IOException, org.jdom.JDOMException, BeanCoderException
{
return xmlDecode(XmlUtils.extractXml(fileName, false));
}
/**
* Loading an object from an URL
*/
public static Object load (final java.net.URL fileUrl)
throws java.io.IOException, org.jdom.JDOMException, BeanCoderException
{
return xmlDecode(XmlUtils.extractXml(fileUrl, false));
}
/**
* Saving a bean / instance to a file
*/
public static void save (final String fileName, final Object bean)
{
java.io.FileOutputStream fos = null;
try
{
fos = new java.io.FileOutputStream(fileName);
save(fos, bean);
}
catch (final Throwable t)
{
log.error
("save() failed to open outputstream to file "+fileName, t);
}
}
/**
* Saving a bean / instance to a given output stream.
*/
public static void save (final java.io.OutputStream os, final Object bean)
throws java.io.IOException, BeanCoderException
{
try
{
final org.jdom.Document doc = xmlEncode(bean);
XmlUtils.getXMLOutputter().output(doc, os);
os.flush();
}
finally
{
try
{
os.close();
}
catch (final Throwable t)
{
log.error
("save() failed to encode as xml to given outputstream");
}
}
}
/**
* Encoding a bean to an XML string.
* If 'null' is given as encoding, the default encoding will be used.
*/
public static String encodeToString
(final Object bean, final String encoding)
throws
BeanCoderException
{
final org.jdom.Document doc = xmlEncode(bean);
return XmlUtils.toString(doc, encoding);
}
/**
* Dumps any bean into its XML string representation; will never
* throw any error (will return the error message as a string instead).
*/
public static String dumpToString
(final Object bean)
{
try
{
return encodeToString(bean, null);
}
catch (final Throwable t)
{
return ">failed to dumpToString : "+t+"<";
}
}
}