package com.skaringa.javaxml.handler.sax;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import org.xml.sax.Attributes;
import com.skaringa.javaxml.DeserializerException;
import com.skaringa.javaxml.PropertyKeys;
import com.skaringa.javaxml.impl.PropertyHelper;
import com.skaringa.javaxml.serializers.ComponentSerializer;
import com.skaringa.javaxml.serializers.SerializerRegistry;
import com.skaringa.util.Log;
/**
* Class that handles events from a SAXInputHandler.
* It constitutes a new object according to the SAX events.
*/
public final class DocumentInputHandler {
private Stack _objHolderStack = new Stack();
private Map _objRefMap = new HashMap();
private StringBuffer _text = new StringBuffer();
private Map _propertyMap = new HashMap();
private ClassLoader _classLoader;
/**
* Get the deserialized object.
* @return The new Object.
*/
public Object getObject() {
return ((ObjectDeserializerHolder) _objHolderStack.peek()).getObj();
}
/**
* Called at the start of a document.
* Does nothing.
*/
public void startDocument() {
Log.debug("startDocument");
}
/**
* Called at the end of a document.
* Does nothing.
*/
public void endDocument() {
Log.debug("endDocument");
}
/**
* Called at the start of an element.
* It figures out the deserializer of the element
* and calls its startDeserialize method.
* @param name The element name.
* @param attrs The attributes of the element.
* @throws DeserializerException If the deserialization failes.
*/
public void startElement(String name, Attributes attrs)
throws DeserializerException {
Log.debug("startElement", name);
_text = new StringBuffer();
ObjectDeserializerHolder objHolder = new ObjectDeserializerHolder();
// check if the element is a reference
String refid = attrs.getValue("reference");
if (refid != null) {
// yes, element is a reference
objHolder.setId(refid);
objHolder.setReference(true);
}
else {
// no, element is an object
objHolder.setId(attrs.getValue("id"));
// get parent
Object parent = null;
try {
parent = getObject();
}
catch (java.util.EmptyStackException e) {
// no parent object available
}
// get deserializer
ComponentSerializer ser;
try {
ser =
SerializerRegistry.getInstance().getDeserializer(
name,
attrs,
_classLoader);
}
catch (DeserializerException ex) {
if (PropertyHelper
.parseBoolean(_propertyMap, PropertyKeys.OMIT_XSI_TYPE)) {
// if the property OMIT_XSI_TYPE_DECLARATIONS is set,
// then try to figure out the java type by another way
ser = SerializerRegistry.getInstance().findDeserializer(parent, name);
}
else {
throw ex;
}
}
objHolder.setSer(ser);
Object obj =
ser.startDeserialize(
name,
attrs,
parent,
_objHolderStack,
_classLoader);
objHolder.setObj(obj);
if (objHolder.getId() != null) {
_objRefMap.put(objHolder.getId(), obj);
}
}
_objHolderStack.push(objHolder);
}
/**
* Called if a text node is found in the XML input.
* @param ch Character array containing the text.
* @param start Start position of the text in the array.
* @param length Length of the text in the array.
*/
public void appendText(char[] ch, int start, int length) {
_text.append(ch, start, length);
}
/**
* Called at the end of an element.
* It retrieves the deserializer and object that were created in startElement
* and calls endDeserialize.
* The object created this way is then populated to the member of its parent.
* @param name The element name.
* @throws DeserializerException If the deserialization failes.
*/
public void endElement(String name) throws DeserializerException {
Log.debug("endElement", name);
ObjectDeserializerHolder objHolder =
(ObjectDeserializerHolder) _objHolderStack.pop();
Object obj;
Integer objId = objHolder.getId();
if (objHolder.isReference()) {
obj = _objRefMap.get(objId);
if (obj == null) {
throw new DeserializerException("missing referenced object: i" + objId);
}
}
else {
obj =
objHolder.getSer().endDeserialize(objHolder.getObj(), _text.toString());
objHolder.setObj(obj);
if (objId != null) {
_objRefMap.put(objId, obj);
}
}
try {
ObjectDeserializerHolder parentHolder =
(ObjectDeserializerHolder) _objHolderStack.peek();
parentHolder.getSer().setMember(parentHolder.getObj(), name, obj);
}
catch (java.util.EmptyStackException e) {
// leave the top level object at the stack
_objHolderStack.push(objHolder);
}
catch (NoSuchFieldException e) {
if (!PropertyHelper
.parseBoolean(_propertyMap, PropertyKeys.SKIP_UNKNOWN_FIELDS)) {
throw new DeserializerException("no such field: " + name);
}
}
}
/**
* Set the properties of the InputHandler
* @param propertyMap The properties.
*/
public void setProperties(Map propertyMap) {
_propertyMap = propertyMap;
}
/**
* Get the properties of the InputHandler
* @return The properties.
*/
public Map getProperties() {
return _propertyMap;
}
/**
* Set the class loader used to load classes during deserialization.
* @param loader The class loader.
*/
public void setClassLoader(ClassLoader loader) {
_classLoader = loader;
}
/**
* Get the class loader used to load classes during deserialization.
* @return The class loader.
*/
public ClassLoader getClassLoader() {
return _classLoader;
}
}