0001: /**
0002: * Objective Database Abstraction Layer (ODAL)
0003: * Copyright (c) 2004, The ODAL Development Group
0004: * All rights reserved.
0005: * For definition of the ODAL Development Group please refer to LICENCE.txt file
0006: *
0007: * Distributable under LGPL license.
0008: * See terms of license at gnu.org.
0009: */package com.completex.objective.components.persistency.io.xml.impl;
0010:
0011: import com.completex.objective.components.persistency.ColumnType;
0012: import com.completex.objective.components.persistency.Link;
0013: import com.completex.objective.components.persistency.MetaColumn;
0014: import com.completex.objective.components.persistency.PersistentObject;
0015: import com.completex.objective.components.persistency.Record;
0016: import com.completex.objective.components.persistency.State;
0017: import com.completex.objective.components.persistency.io.PoObjectInput;
0018: import com.completex.objective.components.persistency.type.CollectionTraceable;
0019: import com.completex.objective.components.persistency.type.CollectionTracer;
0020: import com.completex.objective.components.persistency.type.TracingCollection;
0021: import com.completex.objective.components.persistency.type.ValueStreamHelper;
0022: import com.completex.objective.components.persistency.xml.XmlRuntimeException;
0023: import com.completex.objective.util.TypeUtil;
0024: import com.completex.objective.util.XmlDomHelper;
0025: import org.w3c.dom.Document;
0026: import org.w3c.dom.Element;
0027: import org.w3c.dom.Node;
0028: import org.xml.sax.SAXException;
0029: import sun.misc.BASE64Decoder;
0030:
0031: import javax.xml.parsers.DocumentBuilder;
0032: import java.io.ByteArrayInputStream;
0033: import java.io.IOException;
0034: import java.io.InputStream;
0035: import java.io.ObjectInputStream;
0036: import java.util.ArrayList;
0037: import java.util.Collection;
0038: import java.util.LinkedHashMap;
0039:
0040: /**
0041: * Implementation of PoObjectInput interface. The stream is not thread safe.
0042: *
0043: * @author Gennady Krizhevsky
0044: */
0045: public class XmlPersistentObjectInputStream extends XmlDomStream
0046: implements PoObjectInput {
0047: public static final int EMPTY_INDEX = -1;
0048:
0049: private InputStream inputStream;
0050:
0051: protected CurrentContexts contexts = new CurrentContexts();
0052:
0053: public XmlPersistentObjectInputStream(InputStream inputStream)
0054: throws IOException {
0055: this .inputStream = inputStream;
0056: setup();
0057: }
0058:
0059: protected void setupRootElement() {
0060: rootElement = document.getDocumentElement();
0061: version = xmlDomHelper.getAttributeByName(rootElement,
0062: ATTR_VERSION, false);
0063: }
0064:
0065: protected Document createDocument(DocumentBuilder builder)
0066: throws IOException, SAXException {
0067: return builder.parse(inputStream);
0068: }
0069:
0070: protected Element resolveParentElement() {
0071: return initialized && currentElement != null ? ((Element) currentElement
0072: .getParentNode())
0073: : rootElement;
0074: }
0075:
0076: /**
0077: * Read and return an object.
0078: *
0079: * @return the object read from the stream
0080: * @exception java.lang.ClassNotFoundException If the class of a serialized
0081: * object cannot be found.
0082: * @exception IOException If any of the usual Input/Output
0083: * related exceptions occur.
0084: */
0085: public Object readObject() throws ClassNotFoundException,
0086: IOException {
0087: CurrentContext context = extractContext();
0088: Element childNode = context.getCurrentElement();
0089: return readObject(context, childNode, isReadDescendant());
0090: }
0091:
0092: protected Object readObject(CurrentContext context,
0093: Element childNode, boolean descendant) {
0094: Object readObject = null;
0095: if (childNode != null) {
0096: contexts.increaseLevel();
0097: try {
0098: String childName = childNode.getNodeName();
0099: if (TAG_PO.equals(childName)) {
0100: readObject = readPersistentObject(childNode);
0101: } else if (TAG_COLLECTION.equals(childName)) {
0102: readObject = readCollection(childNode);
0103: } else if (TAG_EXT_TYPE.equals(childName)) {
0104: readObject = readExtType(childNode);
0105: } else if (TAG_NULL.equals(childName)) {
0106: // Do nothing
0107: } else {
0108: System.err
0109: .println("ERROR: XmlPersistentObjectInputStream::readObject: Unknown tag: "
0110: + childName);
0111: }
0112: moveDescendantElementIfNeeded(descendant, context);
0113: } finally {
0114: contexts.decreaseLevel();
0115: }
0116: }
0117: return readObject;
0118: }
0119:
0120: private void moveDescendantElementIfNeeded(boolean descendant,
0121: CurrentContext context) {
0122: if (contexts.isFirstLevel() || descendant) {
0123: context.moveDescendantElement();
0124: }
0125: }
0126:
0127: protected Object readExtType(Element childNode) {
0128: println("readExtType : " + childNode);
0129: ExtTypeTransformer transformer = new ExtTypeTransformer(
0130: childNode);
0131: return resolveRefValue(transformer);
0132: }
0133:
0134: protected Node getFirstChildByTagName(Element parentNode,
0135: String tagPo, boolean assertExists) {
0136: return xmlDomHelper.getFirstElementByName(parentNode, tagPo,
0137: assertExists);
0138: }
0139:
0140: protected void init() {
0141: ensureOpen();
0142: if (!initialized && TAG_ODAL.equals(rootName)) {
0143: preserveOriginalValues = xmlDomHelper
0144: .getAttributeByNameAsBoolean(rootElement,
0145: TAG_PRESERVE_ORIGINAL_VALUES, false);
0146: initialized = true;
0147: }
0148: }
0149:
0150: protected PersistentObject readPersistentObject(Element poNode) {
0151: DefaultValueTransformer defaultValueTransformer = new DefaultValueTransformer(
0152: poNode);
0153: PersistentObject persistentObject = (PersistentObject) resolveRefValue(defaultValueTransformer);
0154:
0155: if (!defaultValueTransformer.isReference()) {
0156: readRecord(poNode, persistentObject);
0157: persistentObject.toBeanFields();
0158:
0159: try {
0160: beginReadDescendant(poNode);
0161: persistentObject.readExternalDescendant(this );
0162: } catch (Exception e) {
0163: throw new XmlRuntimeException(
0164: "Cannot read External Descendant "
0165: + e.toString());
0166: }
0167: readCompoundChildren(poNode, persistentObject);
0168: readComplexChildren(poNode, persistentObject);
0169: }
0170:
0171: return persistentObject;
0172: }
0173:
0174: protected boolean isReadDescendant() {
0175: return contexts.size() > 1;
0176: }
0177:
0178: protected void beginReadDescendant(Element parentNode) {
0179: Element descendantNode = xmlDomHelper.getElementByName(
0180: parentNode, TAG_DESCENDANT, false);
0181: if (descendantNode != null) {
0182: addContext(descendantNode);
0183: }
0184: }
0185:
0186: private void addContext(Element descendantNode) {
0187: contexts.addContext(xmlDomHelper, descendantNode);
0188: }
0189:
0190: protected void readRecord(Node poNode,
0191: PersistentObject persistentObject) {
0192: persistentObject.record2().setPreserveOriginalValues(
0193: preserveOriginalValues);
0194: Node recordNode = extractRecordNode(poNode);
0195: initializeRecord(recordNode, persistentObject);
0196: Node[] fieldNodes = xmlDomHelper.getElementsByName(recordNode,
0197: TAG_FIELD, false);
0198: for (int i = 0; i < fieldNodes.length; i++) {
0199: Node fieldNode = fieldNodes[i];
0200: int idx = xmlDomHelper.getAttributeByNameAsInt(fieldNode,
0201: ATTR_IDX, true);
0202: boolean dirty = xmlDomHelper.getAttributeByNameAsBoolean(
0203: fieldNode, ATTR_DIRTY, false);
0204: Node[] valueNodes = getValueNodes(fieldNode);
0205: boolean hasOrigValue = valueNodes.length > 1;
0206:
0207: String[] valueStrings = extractValueStrings(
0208: persistentObject, hasOrigValue, valueNodes);
0209:
0210: Object[] values = new Object[2];
0211: values[0] = resolveRefValue(new PoValueTransformer(
0212: persistentObject, idx, valueStrings[0],
0213: valueNodes[0], false));
0214: Node origValueNode = resolveOrigValueNode(hasOrigValue,
0215: valueNodes, persistentObject);
0216: if (origValueNode != null) {
0217: values[1] = resolveRefValue(new PoValueTransformer(
0218: persistentObject, idx, valueStrings[1],
0219: origValueNode, true));
0220: }
0221: persistentObject.record2().getEntry(idx).setUnmarkedValue(
0222: values[0], values[1]);
0223: persistentObject.record2().getEntry(idx).setDirty(dirty);
0224: }
0225: }
0226:
0227: private Node resolveOrigValueNode(boolean hasOrigValue,
0228: Node[] valueNodes, PersistentObject persistentObject) {
0229: Node origNode = null;
0230: if (hasOrigValue) {
0231: origNode = valueNodes[1];
0232: } else if (persistentObject.record2().isInitialized()) {
0233: origNode = valueNodes[0];
0234: }
0235: return origNode;
0236: }
0237:
0238: protected void readComplexChildren(Node poNode,
0239: PersistentObject persistentObject) {
0240: if (persistentObject.complex()) {
0241: Element cpxParentNode = xmlDomHelper.getFirstElementByName(
0242: poNode, TAG_COMPLEX_CHILDREN, false);
0243: if (cpxParentNode != null) {
0244: Element[] linkNodes = xmlDomHelper.getElementsByName(
0245: cpxParentNode, TAG_LINK, false);
0246: readLinks(linkNodes, persistentObject);
0247: }
0248: }
0249:
0250: }
0251:
0252: protected void readLinks(Element[] linkNodes,
0253: PersistentObject persistentObject) {
0254: if (linkNodes.length > 0) {
0255: LinkedHashMap children = new LinkedHashMap();
0256: for (int i = 0; i < linkNodes.length; i++) {
0257: readChildLink(linkNodes, i, children);
0258: }
0259: Record
0260: .setupUnmarshalledChildren(persistentObject,
0261: children);
0262: Link rootLink = persistentObject.record().toLink();
0263: rootLink.setChildren(children);
0264: }
0265: }
0266:
0267: protected void readChildLink(Element[] linkNodes, int i,
0268: LinkedHashMap children) {
0269: Link link = new Link();
0270: Element linkNode = linkNodes[i];
0271: String name = linkNode.getAttribute(ATTR_NAME);
0272: String pathString = linkNode.getAttribute(ATTR_NAME);
0273: boolean endOfChain = xmlDomHelper.getAttributeByNameAsBoolean(
0274: linkNode, ATTR_END_OF_CHAIN, false);
0275: link.setName(name);
0276: link.setPath(pathString);
0277: link.setEndOfChain(endOfChain);
0278: children.put(name, link);
0279: readChildLinkResult(linkNode, link);
0280: }
0281:
0282: protected void readChildLinkResult(Element linkNode, Link link) {
0283: Element[] linkElementsNode = xmlDomHelper.getElements(linkNode);
0284: for (int i = 0; i < linkElementsNode.length; i++) {
0285: Element linkElement = linkElementsNode[i];
0286: Object value = readObject(contexts.getContext(),
0287: linkElement, false);
0288: link.setResult(value);
0289: }
0290: }
0291:
0292: protected Collection readCollection(Element collectionNode) {
0293: CollectionValueTransformer transformer = new CollectionValueTransformer(
0294: collectionNode);
0295: Collection collection = (Collection) resolveRefValue(transformer);
0296: if (collection instanceof TracingCollection) {
0297: TracingCollection tracingCollection = (TracingCollection) collection;
0298: String attrSaveTraced = xmlDomHelper.getAttributeByName(
0299: collectionNode, ATTR_SAVE_TRACED, false);
0300: boolean saveTraced = XmlDomHelper.S2b(attrSaveTraced);
0301: tracingCollection.setSaveTraced(saveTraced);
0302: }
0303: if (collection instanceof CollectionTraceable) {
0304: CollectionTraceable traceable = (CollectionTraceable) collection;
0305: readCollectionElements(collectionNode, collection);
0306: readCollectionTracer(collectionNode, traceable);
0307: } else {
0308: readCollectionElements(collectionNode, collection);
0309: }
0310: return collection;
0311: }
0312:
0313: protected CollectionTracer readCollectionTracer(
0314: Element collectionNode, CollectionTraceable traceable) {
0315: CollectionTracer tracer = null;
0316: Element tracerNode = xmlDomHelper.getElementByName(
0317: collectionNode, TAG_TRACER, false);
0318: if (tracerNode != null) {
0319: tracer = traceable.getCollectionTracer();
0320: String attrTrace = xmlDomHelper.getAttributeByName(
0321: tracerNode, ATTR_TRACE, false);
0322: boolean trace = XmlDomHelper.S2b(attrTrace);
0323: tracer.setTrace(trace);
0324: tracerNode.setAttribute(ATTR_TRACE, XmlDomHelper.b2S(tracer
0325: .isTrace()));
0326: Element[] modifiedEntryElements = xmlDomHelper
0327: .getElementsByName(tracerNode, TAG_MODIFIED_ENTRY,
0328: false);
0329: if (modifiedEntryElements.length > 0) {
0330: tracer.setTrace();
0331: for (int i = 0; i < modifiedEntryElements.length; i++) {
0332: Element modifiedEntryElement = modifiedEntryElements[i];
0333: if (modifiedEntryElement != null) {
0334: String opName = xmlDomHelper
0335: .getAttributeByName(
0336: modifiedEntryElement, ATTR_OP,
0337: true);
0338: Element poNode = xmlDomHelper.getElementByName(
0339: modifiedEntryElement, TAG_PO, true);
0340: PersistentObject persistent = readPersistentObject(poNode);
0341: tracer.addModifiedEntry(persistent,
0342: CollectionTracer.Operation
0343: .type2operation(opName));
0344: }
0345: }
0346: }
0347: }
0348: return tracer;
0349: }
0350:
0351: protected void readCollectionElements(Element linkElement,
0352: Collection collection) {
0353: Element collectionElementsParentNode = xmlDomHelper
0354: .getElementByName(linkElement, TAG_ELEMENTS, false);
0355: if (collectionElementsParentNode != null) {
0356: Element[] collectionElements = xmlDomHelper
0357: .getElements(collectionElementsParentNode);
0358: for (int j = 0; j < collectionElements.length; j++) {
0359: Element collectionElement = collectionElements[j];
0360: if (collectionElement != null) {
0361: Object obj = readObject(contexts.getContext(),
0362: collectionElement, false);
0363: collection.add(obj);
0364: }
0365: }
0366: }
0367: }
0368:
0369: protected void readCompoundChildren(Node poNode,
0370: PersistentObject persistentObject) {
0371: Node compoundChildren = xmlDomHelper.getElementByName(poNode,
0372: TAG_COMPOUND_CHILDREN, false);
0373:
0374: if (compoundChildren != null) {
0375: Element[] children = xmlDomHelper.getElementsByName(
0376: compoundChildren, TAG_PO, false);
0377: for (int i = 0; i < children.length; i++) {
0378: PersistentObject entry = readPersistentObject(children[i]);
0379: persistentObject.compoundEntry(i + 1, entry);
0380: }
0381: }
0382: }
0383:
0384: private String[] extractValueStrings(
0385: PersistentObject persistentObject, boolean hasOrigValue,
0386: Node[] valueNodes) {
0387: String[] valueStrings = new String[2];
0388: valueStrings[0] = xmlDomHelper.getNodeText(valueNodes[0]);
0389: if (hasOrigValue) {
0390: valueStrings[1] = xmlDomHelper.getNodeText(valueNodes[1]);
0391: } else if (persistentObject.record().isInitialized()) {
0392: //
0393: // If record is initialized and it does not have original values
0394: // then it means that original values are the same as the values:
0395: //
0396: valueStrings[1] = valueStrings[0];
0397: } else {
0398: // Nothing?
0399: }
0400: return valueStrings;
0401: }
0402:
0403: private void initializeRecord(Node recordNode,
0404: PersistentObject persistentObject) {
0405: State recordState = extractRecordState(preserveOriginalValues,
0406: recordNode);
0407: persistentObject.record().setPreserveOriginalValues(
0408: preserveOriginalValues);
0409: if (recordState != null) {
0410: persistentObject.record().setState(recordState);
0411: }
0412: }
0413:
0414: private State extractRecordState(boolean preserveOrigValues,
0415: Node recordNode) {
0416: State recordState = null;
0417: if (preserveOrigValues) {
0418: String recordStateString = xmlDomHelper.getAttributeByName(
0419: recordNode, ATTR_STATE, false);
0420: if (recordStateString != null) {
0421: recordState = State.name2state(recordStateString);
0422: }
0423: }
0424: return recordState;
0425: }
0426:
0427: protected Object string2value(String className, String valueString,
0428: boolean binary) throws IOException, ClassNotFoundException {
0429: return ValueStreamHelper.string2value(className, valueString,
0430: binary);
0431: }
0432:
0433: protected Object string2unknownBinary(String valueString)
0434: throws IOException, ClassNotFoundException {
0435: BASE64Decoder decoder = new BASE64Decoder();
0436: byte[] bytes = decoder.decodeBuffer(valueString);
0437: ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
0438: ObjectInputStream in = new ObjectInputStream(bin);
0439: return in.readObject();
0440: }
0441:
0442: protected Object string2value(PersistentObject persistentObject,
0443: int idx, String valueString, Node valueNode,
0444: boolean origValue) {
0445: MetaColumn column = persistentObject.record().getColumn(idx);
0446: ColumnType type = column.getType();
0447: String bin = xmlDomHelper.getAttributeByName(valueNode,
0448: ATTR_BINARY, false);
0449: boolean binary = bin != null;
0450: return ValueStreamHelper.string2value(binary, valueString,
0451: origValue, type, column.getColumnName());
0452: }
0453:
0454: protected Object resolveRefValue(ValueTransformer valueTransformer) {
0455: Node valueNode = valueTransformer.getValueNode();
0456: String idString = xmlDomHelper.getAttributeByName(valueNode,
0457: ATTR_ID, false);
0458: String refidString = xmlDomHelper.getAttributeByName(valueNode,
0459: ATTR_REFID, false);
0460: String className = extractClassName(valueNode);
0461: valueTransformer.setClassName(className);
0462:
0463: Object value;
0464: boolean isReference = false;
0465: if (idString != null) {
0466: value = valueTransformer.transform();
0467: addToReferences(value, idString);
0468: } else if (refidString != null) {
0469: isReference = true;
0470: // Find ref
0471: value = references.get(refidString);
0472: if (value == null) {
0473: System.err
0474: .println("ERROR: XmlPersistentObjectInputStream::resolveRefValue: Cannot find reference by refid "
0475: + refidString);
0476: }
0477: } else {
0478: // id is null and refid is nuull - this is primitive
0479: value = valueTransformer.transform();
0480:
0481: }
0482:
0483: valueTransformer.setReference(isReference);
0484: return value;
0485: }
0486:
0487: protected void addToReferences(Object value, String idString) {
0488: if (value != null) {
0489: references.put(idString, value);
0490: }
0491: }
0492:
0493: private Node extractRecordNode(Node poNode) {
0494: return xmlDomHelper.getElementByName(poNode, TAG_RECORD, true);
0495: }
0496:
0497: protected Node[] getValueNodes(Node parentNode) {
0498: Node[] valueNodes = xmlDomHelper.getNodesByType(parentNode,
0499: Node.ELEMENT_NODE);
0500: if (valueNodes.length > 2) {
0501: throw new XmlRuntimeException("Too many value elements ("
0502: + valueNodes.length + ")" + " found");
0503: } else if (valueNodes.length == 0) {
0504: throw new XmlRuntimeException("No value elements found");
0505: }
0506: return valueNodes;
0507: }
0508:
0509: protected Node[] getNodesByName(Node parentNode, String tagName,
0510: int type, boolean assertExists) {
0511: return xmlDomHelper.getNodesByName(parentNode, tagName, type,
0512: assertExists);
0513: }
0514:
0515: private String extractClassName(Node poNode) {
0516: return getAttributeByName(poNode, ATTR_CLASS, false);
0517: }
0518:
0519: protected String getAttributeByName(Node node, String tagName,
0520: boolean assertExist) {
0521: return xmlDomHelper.getAttributeByName(node, tagName,
0522: assertExist);
0523: }
0524:
0525: /**
0526: * Not used
0527: */
0528: public int available() throws IOException {
0529: return 0;
0530: }
0531:
0532: /**
0533: * The method does not comply with the interface specification.
0534: * It reads the next object as byte
0535: *
0536: * @return the byte read.
0537: * @exception IOException If an I/O error has occurred or if the object is not byte
0538: */
0539: public int read() throws IOException {
0540: return readByte();
0541: }
0542:
0543: public void close() throws IOException {
0544: super .close();
0545: inputStream.close();
0546: contexts.clear();
0547: }
0548:
0549: /**
0550: * Not used
0551: */
0552: public long skip(long n) throws IOException {
0553: return 0;
0554: }
0555:
0556: /**
0557: * Unsupported
0558: */
0559: public int read(byte b[]) throws IOException {
0560: throw new UnsupportedOperationException("read(byte b[])");
0561: }
0562:
0563: /**
0564: * Unsupported
0565: */
0566: public int read(byte b[], int off, int len) throws IOException {
0567: throw new UnsupportedOperationException(
0568: "read(byte b[], int off, int len)");
0569: }
0570:
0571: /**
0572: * The method does not comply with the interface specification.
0573: * It reads the next object as byte
0574: *
0575: * @return the byte read.
0576: * @exception IOException If an I/O error has occurred or if the object is not byte
0577: */
0578: public byte readByte() throws IOException {
0579: CurrentContext context = extractContext();
0580: Object object = readObject(context,
0581: context.getCurrentElement(), isReadDescendant());
0582: return TypeUtil.Number2byte(((Number) object));
0583: }
0584:
0585: /**
0586: * The method does not comply with the interface specification.
0587: * It reads the next object as char
0588: *
0589: * @return the byte read.
0590: * @exception IOException If an I/O error has occurred or if the object is not char
0591: */
0592: public char readChar() throws IOException {
0593: String str = readUTF();
0594: char[] chars = str.toCharArray();
0595: return chars.length > 0 ? chars[0] : ((char) -1);
0596: }
0597:
0598: /**
0599: * The method does not comply with the interface specification.
0600: * It reads the next object as double
0601: *
0602: * @return the byte read.
0603: * @exception IOException If an I/O error has occurred or if the object is not double
0604: */
0605: public double readDouble() throws IOException {
0606: CurrentContext context = extractContext();
0607: Object object = readObject(context,
0608: context.getCurrentElement(), isReadDescendant());
0609: return TypeUtil.Number2double(((Number) object));
0610: }
0611:
0612: /**
0613: * The method does not comply with the interface specification.
0614: * It reads the next object as float
0615: *
0616: * @return the byte read.
0617: * @exception IOException If an I/O error has occurred or if the object is not float
0618: */
0619: public float readFloat() throws IOException {
0620: CurrentContext context = extractContext();
0621: Object object = readObject(context,
0622: context.getCurrentElement(), isReadDescendant());
0623: return TypeUtil.Number2float(((Number) object));
0624: }
0625:
0626: /**
0627: * The method does not comply with the interface specification.
0628: * It reads the next object as int.
0629: *
0630: * @return the byte read.
0631: * @exception IOException If an I/O error has occurred or if the object is not int.
0632: */
0633: public int readInt() throws IOException {
0634: CurrentContext context = extractContext();
0635: Object object = readObject(context,
0636: context.getCurrentElement(), isReadDescendant());
0637: return TypeUtil.Number2int(((Number) object));
0638: }
0639:
0640: /**
0641: * The method does not comply with the interface specification.
0642: * It reads the next object as byte.
0643: *
0644: * @return the byte read.
0645: * @exception IOException If an I/O error has occurred or if the object is not byte.
0646: */
0647: public int readUnsignedByte() throws IOException {
0648: return readByte();
0649: }
0650:
0651: /**
0652: * The method does not comply with the interface specification.
0653: * It reads the next object as short.
0654: *
0655: * @return the byte read.
0656: * @exception IOException If an I/O error has occurred or if the object is not short.
0657: */
0658: public int readUnsignedShort() throws IOException {
0659: return readShort();
0660: }
0661:
0662: /**
0663: * The method does not comply with the interface specification.
0664: * It reads the next object as long.
0665: *
0666: * @return the byte read.
0667: * @exception IOException If an I/O error has occurred or if the object is not long.
0668: */
0669: public long readLong() throws IOException {
0670: CurrentContext context = extractContext();
0671: Object object = readObject(context,
0672: context.getCurrentElement(), isReadDescendant());
0673: return TypeUtil.Number2long(((Long) object));
0674: }
0675:
0676: /**
0677: * The method does not comply with the interface specification.
0678: * It reads the next object as short.
0679: *
0680: * @return the byte read.
0681: * @exception IOException If an I/O error has occurred or if the object is not short.
0682: */
0683: public short readShort() throws IOException {
0684: CurrentContext context = extractContext();
0685: Object object = readObject(context,
0686: context.getCurrentElement(), isReadDescendant());
0687: return TypeUtil.Number2short(((Number) object));
0688: }
0689:
0690: /**
0691: * The method does not comply with the interface specification.
0692: * It reads the next object as boolean.
0693: *
0694: * @return the byte read.
0695: * @exception IOException If an I/O error has occurred or if the object is not boolean.
0696: */
0697: public boolean readBoolean() throws IOException {
0698: CurrentContext context = extractContext();
0699: Object object = readObject(context,
0700: context.getCurrentElement(), isReadDescendant());
0701: return TypeUtil.Boolean2boolean(((Boolean) object));
0702: }
0703:
0704: /**
0705: * Not used
0706: */
0707: public int skipBytes(int n) throws IOException {
0708: return 0;
0709: }
0710:
0711: /**
0712: * Unsupported
0713: */
0714: public void readFully(byte b[]) throws IOException {
0715: throw new UnsupportedOperationException("readFully(byte b[])");
0716: }
0717:
0718: /**
0719: * Unsupported
0720: */
0721: public void readFully(byte b[], int off, int len)
0722: throws IOException {
0723: throw new UnsupportedOperationException(
0724: "readFully(byte b[], int off, int len)");
0725: }
0726:
0727: /**
0728: * Unsupported
0729: */
0730: public String readLine() throws IOException {
0731: throw new UnsupportedOperationException("readLine()");
0732: }
0733:
0734: /**
0735: * @see java.io.DataInput#readUTF()
0736: */
0737: public String readUTF() throws IOException {
0738: CurrentContext context = extractContext();
0739: return (String) readObject(context,
0740: context.getCurrentElement(), isReadDescendant());
0741: }
0742:
0743: protected CurrentContext extractContext() {
0744: Element parentElement = resolveParentElement();
0745: init();
0746: return contexts.getContext(xmlDomHelper, parentElement);
0747: }
0748:
0749: //
0750: //
0751: // Util classes:
0752: //
0753: //
0754: static interface ValueTransformer {
0755: Object transform();
0756:
0757: Node getValueNode();
0758:
0759: boolean isReference();
0760:
0761: void setReference(boolean reference);
0762:
0763: String getClassName();
0764:
0765: void setClassName(String className);
0766: }
0767:
0768: /**
0769: * Default value transformer
0770: */
0771: class DefaultValueTransformer implements ValueTransformer {
0772: Node valueNode;
0773: String className;
0774:
0775: Object value;
0776: boolean reference;
0777:
0778: public DefaultValueTransformer(Node valueNode, String className) {
0779: this .valueNode = valueNode;
0780: this .className = className;
0781: }
0782:
0783: public DefaultValueTransformer(Node valueNode) {
0784: this .valueNode = valueNode;
0785: }
0786:
0787: public Object transform() {
0788: if (value == null) {
0789: value = instantiateObject(className);
0790: }
0791: return value;
0792: }
0793:
0794: protected Object instantiateObject(String className) {
0795: if (className == null) {
0796: throw new XmlRuntimeException(
0797: "Cannot instantiate object with className == null");
0798: }
0799: Object value;
0800: try {
0801: value = Class.forName(className).newInstance();
0802: } catch (Exception e) {
0803: throw new XmlRuntimeException("Cannot instantiate "
0804: + className, e);
0805: }
0806: return value;
0807: }
0808:
0809: public String getClassName() {
0810: return className;
0811: }
0812:
0813: public void setClassName(String className) {
0814: this .className = className;
0815: }
0816:
0817: public Object getValue() {
0818: return value;
0819: }
0820:
0821: public Node getValueNode() {
0822: return valueNode;
0823: }
0824:
0825: public boolean isReference() {
0826: return reference;
0827: }
0828:
0829: public void setReference(boolean reference) {
0830: this .reference = reference;
0831: }
0832: }
0833:
0834: /**
0835: * Persistent Object transformer
0836: */
0837: class PoValueTransformer implements ValueTransformer {
0838: PersistentObject persistentObject;
0839: int idx;
0840: String valueString;
0841: Node valueNode;
0842: boolean origValue;
0843:
0844: boolean reference;
0845:
0846: public PoValueTransformer(PersistentObject persistentObject,
0847: int idx, String valueString, Node valueNode,
0848: boolean origValue) {
0849: this .persistentObject = persistentObject;
0850: this .idx = idx;
0851: this .valueString = valueString;
0852: this .valueNode = valueNode;
0853: this .origValue = origValue;
0854: }
0855:
0856: public Object transform() {
0857: return string2value(persistentObject, idx, valueString,
0858: valueNode, origValue);
0859: }
0860:
0861: public Node getValueNode() {
0862: return valueNode;
0863: }
0864:
0865: public boolean isReference() {
0866: return reference;
0867: }
0868:
0869: public void setReference(boolean reference) {
0870: this .reference = reference;
0871: }
0872:
0873: public String getClassName() {
0874: return null;
0875: }
0876:
0877: public void setClassName(String className) {
0878: }
0879:
0880: }
0881:
0882: /**
0883: * Collection transformer
0884: */
0885: class CollectionValueTransformer extends DefaultValueTransformer {
0886: public CollectionValueTransformer(Element valueNode) {
0887: super (valueNode);
0888: }
0889: }
0890:
0891: /**
0892: * Unknown Binary transformer
0893: */
0894: class ExtTypeTransformer extends DefaultValueTransformer {
0895:
0896: public ExtTypeTransformer(Node valueNode) {
0897: super (valueNode);
0898: }
0899:
0900: protected Object instantiateObject(String className) {
0901: Object value = null;
0902: Node nullNode = xmlDomHelper.getFirstElementByName(
0903: valueNode, TAG_NULL, false);
0904: if (nullNode == null) {
0905: Node firstTextNode = xmlDomHelper.getFirstNodeByType(
0906: valueNode, Node.TEXT_NODE);
0907: try {
0908: if (firstTextNode != null) {
0909: String bin = xmlDomHelper.getAttributeByName(
0910: valueNode, ATTR_BINARY, false);
0911: String valueString = firstTextNode
0912: .getNodeValue();
0913: value = string2value(className, valueString,
0914: bin != null);
0915: }
0916: } catch (Exception e) {
0917: throw new XmlRuntimeException("Cannot instantiate "
0918: + className, e);
0919: }
0920: }
0921: return value;
0922: }
0923: }
0924:
0925: /**
0926: *
0927: */
0928: protected static class CurrentContexts {
0929: private int level = 0;
0930: ArrayList contexts = new ArrayList();
0931:
0932: public void add(CurrentContext context) {
0933: contexts.add(context);
0934: }
0935:
0936: public void remove(CurrentContext context) {
0937: contexts.remove(context);
0938: }
0939:
0940: public CurrentContext getContext(XmlDomHelper xmlDomHelper,
0941: Element parentNode) {
0942: CurrentContext context;
0943: if (contexts.isEmpty()) {
0944: context = addContext(xmlDomHelper, parentNode);
0945: } else {
0946: context = getContext();
0947: }
0948: return context;
0949: }
0950:
0951: public CurrentContext addContext(XmlDomHelper xmlDomHelper,
0952: Element parentNode) {
0953: return new CurrentContext(this , xmlDomHelper, parentNode);
0954: }
0955:
0956: public CurrentContext getContext() {
0957: return (CurrentContext) contexts.get(contexts.size() - 1);
0958: }
0959:
0960: public void clear() {
0961: contexts.clear();
0962: }
0963:
0964: public boolean isReadDescendant() {
0965: return !contexts.isEmpty()
0966: && getContext().isReadDescendant();
0967: }
0968:
0969: public int size() {
0970: return contexts.size();
0971: }
0972:
0973: public int increaseLevel() {
0974: ++level;
0975: // System.err.println("increaseLevel: " + level);
0976: return level;
0977: }
0978:
0979: public int decreaseLevel() {
0980: --level;
0981: // System.err.println("decreaseLevel: " + level);
0982: return level;
0983: }
0984:
0985: public int getLevel() {
0986: return level;
0987: }
0988:
0989: public boolean isFirstLevel() {
0990: return level == 1;
0991: }
0992: }
0993:
0994: /**
0995: * Current Node structure:
0996: */
0997: protected static class CurrentContext {
0998: public static final int EMPTY_INDEX = -1;
0999:
1000: private CurrentContexts contexts;
1001: private XmlDomHelper xmlDomHelper;
1002: private Element currentElement;
1003: private Element[] currentDescendantNodes;
1004: private int currentDescendantIndex = EMPTY_INDEX;
1005:
1006: public CurrentContext(CurrentContexts contexts,
1007: XmlDomHelper xmlDomHelper, Element parentNode) {
1008: this .contexts = contexts;
1009: this .xmlDomHelper = xmlDomHelper;
1010: beginReadDescendant(parentNode);
1011: }
1012:
1013: public Element getCurrentElement() {
1014: return currentElement;
1015: }
1016:
1017: public void setCurrentElement(Element currentElement) {
1018: this .currentElement = currentElement;
1019: }
1020:
1021: public Element[] getCurrentDescendantNodes() {
1022: return currentDescendantNodes;
1023: }
1024:
1025: public void setCurrentDescendantNodes(
1026: Element[] currentDescendantNodes) {
1027: this .currentDescendantNodes = currentDescendantNodes;
1028: }
1029:
1030: public int getCurrentDescendantIndex() {
1031: return currentDescendantIndex;
1032: }
1033:
1034: public void setCurrentDescendantIndex(int currentDescendantIndex) {
1035: this .currentDescendantIndex = currentDescendantIndex;
1036: }
1037:
1038: boolean isReadDescendant() {
1039: return currentDescendantIndex != EMPTY_INDEX;
1040: }
1041:
1042: public CurrentContext beginReadDescendant(Element descendantNode) {
1043: if (descendantNode != null) {
1044: contexts.add(this );
1045: currentDescendantNodes = xmlDomHelper
1046: .getElements(descendantNode);
1047: currentDescendantIndex = 0;
1048: moveDescendantElement();
1049: }
1050: return this ;
1051: }
1052:
1053: public void moveDescendantElement() {
1054: if (isReadDescendant() && currentDescendantNodes != null) {
1055: if (currentDescendantIndex < currentDescendantNodes.length) {
1056: currentElement = currentDescendantNodes[currentDescendantIndex];
1057: currentDescendantIndex = currentDescendantIndex + 1;
1058: } else {
1059: currentDescendantIndex = EMPTY_INDEX;
1060: currentDescendantNodes = null;
1061: contexts.remove(this);
1062: }
1063: }
1064: }
1065:
1066: }
1067:
1068: }
|