// You can redistribute this software and/or modify it under the terms of
// the Ozone Core License version 1 published by ozone-db.org.
//
// The original code and portions created by SMB are
// Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
//
// $Id: XML2ObjectContentHandler.java,v 1.1 2001/12/18 10:31:31 per_nyfelt Exp $
package org.ozoneDB.core.xml;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import org.xml.sax.*;
import org.apache.xerces.parsers.SAXParser;
import org.ozoneDB.OzoneProxy;
import org.ozoneDB.core.ObjectID;
/**
* This class handles the XML and transform it into an Object.
*
* @version $Revision: 1.1 $
* @author <a href="http://www.softwarebuero.de">SMB</a>
*/
public class XML2ObjectContentHandler implements ContentHandler, Consts {
public static final boolean debug = false;
//
// member
//
/**
*/
protected Locator locator;
/**
* Cache for the ref-elements.
*/
protected static Hashtable objCache = new Hashtable();
/**
* All objs, members, values etc. are saved in these stack.
*/
protected Stack stack;
/**
* CH (ContentHandler) is for handling a special part of the XML
* in a special ContentHandler. (e.g. HashtableContentHandler)
*/
protected XML2ObjectContentHandler CH = null;
/**
*/
protected XML2ObjectDelegate delegate;
//
// construcor
//
/**
*/
public XML2ObjectContentHandler() {
CH = this;
}
/**
*/
public XML2ObjectContentHandler(XML2ObjectDelegate delegate) {
this();
this.delegate = delegate;
}
//
// methods
//
/**
* The method setDocumentLocator sets the locator.
*
* @param locator
*/
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
/**
* ... start Document
*/
public void startDocument() {
if (debug) {
System.out.println("Start parsing ..");
}
}
/**
* ... end Document
*/
public void endDocument() {
if (debug) {
System.out.println("End parsing ..");
}
}
/**
* The method startElement handels all startElements.
* It refers to the methods, which process the individual startElement
* in detail.
*
* @param namespaceURI
* @param localName
* @param rawName (the tagname)
* @param atts (the attributes of the tag)
*/
public void startElement (String namespaceURI, String localName,
String rawName, Attributes atts) {
if (rawName.equals(TAG_OBJ)) {
CH.objStartElement(atts);
} else if (rawName.equals(TAG_MEMBER)) {
CH.memberStartElement(atts);
} else if (rawName.equals(TAG_VALUE)) {
CH.valueStartElement(atts);
} else if (rawName.equals(TAG_VALUEOBJ)) {
CH.valueObjStartElement(atts);
} else if (rawName.equals(TAG_VALUEARRAY)) {
CH.valueArrayStartElement(atts);
} else if (rawName.equals(TAG_SUPERCLASS)) {
CH.superclassStartElement(atts);
}
}
/**
* The method endElement handles all endElements.
* It refers to the methods, which process the individual endElement
* in detail.
*
* @param namespaceURI
* @param localName
* @param rawName (the tagname)
*/
public void endElement (String namespaceURI, String localName,
String rawName) {
if (CH.stack.size() <= 1 && rawName.equals(TAG_VALUEOBJ)) {
Hashtable hash = (Hashtable)CH.stack.pop();
CH = this;
stack.push(hash);
}
if (rawName.equals(TAG_OBJ)) {
CH.objEndElement();
} else if (rawName.equals(TAG_MEMBER)) {
CH.memberEndElement();
} else if (rawName.equals(TAG_VALUE)) {
CH.valueEndElement();
} else if (rawName.equals(TAG_VALUEOBJ)) {
CH.valueObjEndElement();
} else if (rawName.equals(TAG_VALUEARRAY)) {
CH.valueArrayEndElement();
} else if (rawName.equals(TAG_SUPERCLASS)) {
CH.superclassEndElement();
}
}
/**
* The method characters handles the text-elements.
*
* @param ch (char-array)
* @param start (start of the array)
* @param end (end of the array)
*/
public void characters (char[] ch, int start, int end) {
CH.values(ch, start, end);
}
/**
*/
public void processingInstruction(String target, String data) {
if (debug) {
System.out.println("Target: " + target + " Data: " + data);
}
}
/**
*/
public void startPrefixMapping (String prefix, String uri) {
if (debug) {
System.out.println("Prefix: " + prefix + " Uri: " + uri);
}
}
/**
*/
public void endPrefixMapping (String prefix) {
if (debug) {
System.out.println("EndPrefix: " + prefix);
}
}
/**
*/
public void ignorableWhitespace (char[] ch, int start, int end) {
if (debug) {
String s = new String(ch,start,end);
System.out.println("Ignor chars: "+s);
}
}
/**
*/
public void skippedEntity (String name) {
if (debug) {
System.out.println("Skip entity "+name);
}
}
//
// handle elements
//
/**
* The method objStartElement refers to handleObjStartElement.
* @param atts (the attributes)
*/
protected void objStartElement(Attributes atts) {
handleObjStartElement(atts);
}
/**
* The method memberStartElement refers to handleMemberStartElement.
* @param atts (the attributes)
*/
protected void memberStartElement(Attributes atts) {
handleMemberStartElement(atts);
}
/**
* The method valueStartElement refers to handleValueStartElement.
* @param atts (the attributes)
*/
protected void valueStartElement(Attributes atts) {
handleValueStartElement(atts);
}
/**
* The method valueObjStartElement refers to handleValueObjStartElement.
* @param atts (the attributes)
*/
protected void valueObjStartElement(Attributes atts) {
handleValueObjStartElement(atts);
}
/**
* The method valueArrayStartElement refers to handleValueArrayStartElement.
* @param atts (the attributes)
*/
protected void valueArrayStartElement(Attributes atts) {
handleValueArrayStartElement(atts);
}
/**
* The method superclassStartElement refers to handleSuperclassStartElement.
* @param atts (the attributes)
*/
protected void superclassStartElement(Attributes atts) {
handleSuperclassStartElement(atts);
}
/**
* The method values refers to handleValues.
*
* @param ch (char-array)
* @param start (start of the array)
* @param end (end of the array)
*/
protected void values(char[] ch, int start, int end) {
handleValues(ch, start, end);
}
/**
* The method objEndElement refers to handleObjEndElement.
*/
protected void objEndElement() {
handleObjEndElement();
}
/**
* The method memberEndElement refers to handleMemberEndElement.
*/
protected void memberEndElement() {
handleMemberEndElement ();
}
/**
* The method valueEndElement refers to handleValueEndElement.
*/
protected void valueEndElement() {
handleValueEndElement();
}
/**
* The method valueObjEndElement refers to handleValueObjEndElement.
*/
protected void valueObjEndElement() {
handleValueObjEndElement();
}
/**
* The method valueArrayEndElement refers to handleValueArrayEndElement.
*/
protected void valueArrayEndElement() {
handleValueArrayEndElement();
}
/**
* The method superclassEndElement refers to handleSuperclassEndElement.
*/
protected void superclassEndElement() {
handleSuperclassEndElement();
}
/**
* The method handleObjStartElement creates a new object
* and put it in the stack.
*
* @param atts (the attributes)
*/
protected void handleObjStartElement(Attributes atts) {
ObjElement oe;
try {
stack = new Stack();
oe = new ObjElement(atts);
stack.push(oe);
objCache.put(oe.getId(), oe.getObject());
} catch (ClassNotFoundException cnfe) {
System.err.println("handleObjStartElement: " + cnfe);
} catch (InstantiationException ie) {
System.err.println("handleObjStartElement: " + ie);
} catch (IllegalAccessException iae) {
System.err.println("handleObjStartElement: " + iae);
}
}
/**
* The method handleObjEndElement gets the finished Object from the stack.
*/
protected void handleObjEndElement() {
ObjElement oe = (ObjElement)stack.pop();
delegate.handleObject(oe);
}
/**
* This methode handles an OzoneProxy member.
*
* @param memberName (name of the member)
* @param proxy (the OzoneProxy object)
*/
protected void handleOzoneProxyMember(Attributes atts) {
String proxyType = atts.getValue(ATTR_PROXY_TYPE);
String href = atts.getValue(ATTR_XLINK_HREF_RAW);
ObjectID objID = new ObjectID((new Long(href)).longValue());
try {
Class proxyClass = Thread.currentThread().getContextClassLoader().loadClass(proxyType);
OzoneProxy proxy = (OzoneProxy)proxyClass.newInstance();
Field remoteID = proxyClass.getField( REMOTE_ID );
remoteID.set(proxy, objID);
ValueObjElement voe = new ValueObjElement(proxy);
stack.push(voe);
} catch (ClassNotFoundException cnfe) {
System.err.println("handleOzoneProxyMember: " + cnfe);
} catch (InstantiationException ie) {
System.err.println("handleOzoneProxyMember: " + ie);
} catch (IllegalAccessException iae) {
System.err.println("handleOzoneProxyMember: " + iae);
} catch (NoSuchFieldException nsfe) {
System.err.println("handleOzoneProxyMember: " + nsfe);
}
}
/**
* The method handleMemberStartElement creates a MemberElement
* and put it the stack.
*
* @param atts (the attributes)
*/
protected void handleMemberStartElement(Attributes atts) {
MemberElement me = new MemberElement(atts);
stack.push(me);
if (atts.getValue(ATTR_PROXY_TYPE) != null) //member is an OzoneProxy
handleOzoneProxyMember(atts);
}
/**
* The method handleMemberEndElement gets the finished MemberElement and the value
* from the stack and put it in the object.
*/
protected void handleMemberEndElement() {
Object value = null;
if (stack.peek() instanceof ValueObjElement)
value = ((ValueObjElement)stack.pop()).getObject();
else if (stack.peek() instanceof MemberElement)
value = null;
else
value = stack.pop();
if (stack.peek() instanceof MemberElement) {
MemberElement me = (MemberElement)stack.pop();
Object obj = stack.peek();
Class objClass = obj.getClass();
if (stack.peek() instanceof ObjElement) {
obj = ((ObjElement)stack.peek()).getObject();
objClass = obj.getClass();
} else if (stack.peek() instanceof ValueObjElement) {
obj = ((ValueObjElement)stack.peek()).getObject();
objClass = obj.getClass();
} else if (stack.peek() instanceof SuperclassElement) {
obj = ((SuperclassElement)stack.peek()).getObject();
objClass = ((SuperclassElement)stack.peek()).getSuperclass();
}
try {
Field fd = objClass.getDeclaredField(me.getName());
fd.setAccessible(true);
fd.set(obj, value);
} catch (NoSuchFieldException nsfe) { // wrong Class
System.err.println("handleMemberEndElement: " + nsfe);
} catch (IllegalAccessException iae) { //no access for this member
System.err.println("handleMemberEndElement: " + iae);
}
}
}
/**
* The method handleValueStartElement creates a ValueElement
* and put it the stack.
*
* @param atts (the attributes)
*/
protected void handleValueStartElement(Attributes atts) {
String ref = atts.getValue(ATTR_REF);
if (ref != null) {
Object refObj = objCache.get(ref);
stack.push(new RefElement(refObj));
return;
}
ValueElement ve = new ValueElement(atts);
stack.push(ve);
}
/**
* The method handleValues gets the ValueElement from the stack.
* All values in the ValueElement are saved as String.
*
* @param ch (char-array)
* @param start (start of the array)
* @param end (end of the array)
*/
public void handleValues (char[] ch, int start, int end) {
if (stack == null || stack.empty())
return;
if ((stack.peek() instanceof ValueElement)) {
String value = new String(ch,start,end);
ValueElement ve = (ValueElement)stack.pop();
if (ve.getStrValue() != null) // if ValueElement.value has already a value,
value = ve.getStrValue() + value; // then append (new)value to (old)value
ve.setStrValue(value);
stack.push(ve);
}
}
/**
* The method handleValueEndElement gets the ValueElement from the stack.
* It casts the value (as String) in the special type and put the real
* value in the stack back.
*/
protected void handleValueEndElement() {
Object value;
if (stack.peek() instanceof RefElement) {
value = ((RefElement)(stack.pop())).getRefObj();
} else {
ValueElement ve = (ValueElement) stack.pop();
if (ve.getStrValue() == null) value = null;
else {
value = castValue (ve.getType(), ve.getStrValue());
objCache.put(ve.getId(), value);
}
}
stack.push(value);
}
/**
* The method castValues casts the valueString into the real type.
*
* @param type (the type)
* @param valueString (start of the array)
*/
protected Object castValue(String type, String valueStr) {
if ((type.equals("java.lang.Boolean")) ||
(type.equals("boolean"))) {
Boolean value = new Boolean(valueStr);
return value;
}
if ((type.equals("java.lang.Byte")) ||
(type.equals("byte"))) {
Byte value = new Byte(valueStr);
return value;
}
if ((type.equals("java.lang.Character")) ||
(type.equals("char"))) {
Character value = new Character(valueStr.charAt(0));
return value;
}
if ((type.equals("java.lang.Short")) ||
(type.equals("short"))) {
Short value = new Short(valueStr);
return value;
}
if ((type.equals("java.lang.Integer")) ||
(type.equals("int"))) {
Integer value = new Integer(valueStr);
return value;
}
if ((type.equals("java.lang.Long")) ||
(type.equals("long"))) {
Long value = new Long(valueStr);
return value;
}
if ((type.equals("java.lang.Float")) ||
(type.equals("float"))) {
Float value = new Float(valueStr);
return value;
}
if ((type.equals("java.lang.Double")) ||
(type.equals("double"))) {
Double value = new Double(valueStr);
return value;
}
if (type.equals("java.lang.String")) {
String value = new String(valueStr);
return value;
}
return null;
}
/**
* The method handleValueObjStartElement creates a ValueObjElement
* and put it in the stack.
* If the valueObj is from type java.util.Hashtable:
* -> new ContentHandler which creates a Hashtable
* (It is because of can not creating innerClasses!!)
*
* @param atts (the attributes)
*/
protected void handleValueObjStartElement(Attributes atts) {
String ref = atts.getValue("ref");
if (ref != null) {
Object refObj = objCache.get(ref);
stack.push(refObj);
return;
}
try {
ValueObjElement voe = new ValueObjElement(atts);
if (voe.getType().equals("java.util.Hashtable")) {
System.out.println("new HashContentHandler");
CH = new HashtableContentHandler(locator, (Hashtable)voe.getObject());
} else {
stack.push(voe);
objCache.put(voe.getId(), voe.getObject());
}
} catch (ClassNotFoundException cnfe) {
System.err.println("handleValueObjStartElement: " + cnfe);
} catch (InstantiationException ie) {
System.err.println("handleValueObjStartElement: " + ie);
} catch (IllegalAccessException iae) {
System.err.println("handleValueObjStartElement: " + iae);
}
}
/**
*/
protected void handleValueObjEndElement() {
}
/**
* The method handleValueArrayStartElement creates a ValueArrayElement
* and put it in the stack.
*
* @param atts (the attributes)
*/
protected void handleValueArrayStartElement(Attributes atts) {
String ref = atts.getValue("ref");
if (ref != null) {
Object refObj = objCache.get(ref);
stack.push(new RefElement(refObj));
return;
}
ValueArrayElement vae = new ValueArrayElement(atts);
stack.push(vae);
}
/**
* The method handleValueArrayEndElement joins the values to an array.
*/
protected void handleValueArrayEndElement() {
Object array;
if (stack.peek() instanceof RefElement) {
array = ((RefElement)(stack.pop())).getRefObj();
stack.push(array);
return;
}
try {
Vector vaValues = new Vector();
while (!(stack.peek() instanceof ValueArrayElement)) {
vaValues.addElement(stack.pop());
}
ValueArrayElement vae = (ValueArrayElement) stack.pop();
Class vaClass = Class.forName(vae.getType()).getComponentType();
array = Array.newInstance(vaClass, vaValues.size());
int k = vaValues.size()-1; // k-- otherwise -> wrong sequence
for (int j = 0; j < vaValues.size(); j++, k--) {
Array.set(array, j, vaValues.elementAt(k));
}
objCache.put(vae.getId(), array);
stack.push(array);
} catch (ClassNotFoundException cnfe) {
System.err.println("handleValueArrayStartElement: " + cnfe);
}
}
/**
* The method handleSuperclassStartElement creates a SuperclassElement
* and put into the stack.
*
* @param atts (the attributes)
*/
protected void handleSuperclassStartElement(Attributes atts) {
try {
Object obj = stack.peek();
if (stack.peek() instanceof ObjElement) {
obj = ((ObjElement)stack.peek()).getObject();
} else if (stack.peek() instanceof ValueObjElement) {
obj = ((ValueObjElement)stack.peek()).getObject();
} else if (stack.peek() instanceof SuperclassElement) {
obj = ((SuperclassElement)stack.peek()).getObject();
}
SuperclassElement sce = new SuperclassElement(obj, atts);
stack.push(sce);
} catch (ClassNotFoundException cnfe) {
System.err.println("handleSuperclassStartElement: " + cnfe);
}
}
/**
* The method handleSuperclassEndElement pop the superclass in the stack.
*/
protected void handleSuperclassEndElement() {
stack.pop();
}
// ------------ TEST -------------
// -- System.out.println(STACK) --
// -------------------------------
protected void showStack(Stack s) {
try {
System.out.println("------------------------------ (start)");
for (int i=s.size()-1; i>=0; i--) {
System.out.print(" " + i+". " + s.elementAt(i));
System.out.println();
}
System.out.println("------------------------------ (end)");
} catch (Exception e) {
System.err.println("showStack: " + e);
}
}
}