0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.dbschema.migration.archiver.deserializer;
0043:
0044: import java.lang.*;
0045: import java.util.*;
0046:
0047: import java.lang.reflect.Field;
0048: import java.lang.reflect.Array;
0049:
0050: import org.xml.sax.*;
0051:
0052: public class XMLGraphDeserializer extends BaseSpecificXMLDeserializer
0053: implements java.io.Serializable {
0054:
0055: // Fields
0056:
0057: // The following static fields control the various states that this
0058: // state machine expects and handles. Some states are currently no-op's
0059:
0060: public static final int XGD_END = 99;
0061: public static final int XGD_NEED_ATTRIBUTE = 1;
0062: public static final int XGD_NEED_END_ATTR = 2;
0063: public static final int XGD_NEED_END_NULLVALUE = 4;
0064: public static final int XGD_NEED_END_OBJECT = 5;
0065: public static final int XGD_NEED_END_PARAM = 10;
0066: public static final int XGD_NEED_END_ROW = 3;
0067: public static final int XGD_NEED_END_ROW_ELEMENT = 14;
0068: public static final int XGD_NEED_OBJECT = 7;
0069: public static final int XGD_NEED_PARAM = 9;
0070: public static final int XGD_NEED_ROW = 6;
0071: public static final int XGD_NEED_ROW_ELEMENT = 13;
0072: public static final int XGD_NEED_ROW_TAG = 12;
0073: public static final int XGD_NEED_STRING = 11;
0074: public static final int XGD_NEED_VALUE = 8;
0075:
0076: // The following fields maintain various states
0077: //@olsen+MBO: used unsynchronized HashMap and ArrayListStack
0078: private java.util.HashMap ObjectHash;
0079: private ArrayListStack AttrNameStack;
0080: public ArrayListStack RowTypeStack;
0081: private ArrayListStack RowCountStack;
0082: /*
0083: private java.util.Hashtable ObjectHash;
0084: private java.util.Stack AttrNameStack;
0085: public java.util.Stack RowTypeStack;
0086: private java.util.Stack RowCountStack;
0087: */
0088:
0089: //@olsen+MBO: added field for reflection lookup
0090: private HashMap hashedClasses = new HashMap();
0091:
0092: // Constructors
0093:
0094: //@lars: added classloader-constructor
0095: public XMLGraphDeserializer(ClassLoader cl) {
0096: super (cl);
0097: //@olsen+MBO: used unsynchronized HashMap and ArrayListStack
0098: this .AttrNameStack = new ArrayListStack();
0099: this .ObjectHash = new java.util.HashMap(20);
0100: this .RowTypeStack = new ArrayListStack();
0101: this .RowCountStack = new ArrayListStack();
0102: /*
0103: this.AttrNameStack = new java.util.Stack();
0104: this.ObjectHash = new java.util.Hashtable(20, 0.75F);
0105: this.RowTypeStack = new java.util.Stack();
0106: this.RowCountStack = new java.util.Stack();
0107: */
0108: } /*Method-End*/
0109:
0110: public XMLGraphDeserializer() {
0111: this (null);
0112: }
0113:
0114: //@olsen+MBO: added method for reflection lookup
0115: private Field findField(Object lCurrentObj,
0116: final String lCurrentField)
0117: //String lCurrentField)
0118: {
0119: Field lField = null;
0120: Class lClass = lCurrentObj.getClass();
0121: HashMap hashedFields = (HashMap) hashedClasses.get(lClass);
0122: if (hashedFields == null) {
0123: hashedFields = new HashMap();
0124: hashedClasses.put(lClass, hashedFields);
0125: } else {
0126: lField = (Field) hashedFields.get(lCurrentField);
0127: }
0128:
0129: for (; lClass != null && lField == null; lClass = lClass
0130: .getSuperclass()) {
0131: /*
0132: try {
0133: lField = lClass.getDeclaredField(lCurrentField);
0134: if (lField != null) {
0135: hashedFields.put(lCurrentField, lField);
0136: lField.setAccessible(true);
0137: break;
0138: }
0139: } catch (java.lang.NoSuchFieldException ex) {
0140: }
0141: */
0142:
0143: final Class tmpClass = lClass;
0144: lField = (Field) java.security.AccessController
0145: .doPrivileged(new java.security.PrivilegedAction() {
0146: public Object run() {
0147: try {
0148: Field tmpField = tmpClass
0149: .getDeclaredField(lCurrentField);
0150: if (tmpField != null) {
0151: tmpField.setAccessible(true);
0152: }
0153: return tmpField;
0154: } catch (java.lang.NoSuchFieldException ex) {
0155: return null;
0156: }
0157: }
0158: });
0159: if (lField != null) {
0160: hashedFields.put(lCurrentField, lField);
0161: break;
0162: }
0163:
0164: }
0165: return lField;
0166: }
0167:
0168: public void endDocument() throws org.xml.sax.SAXException {
0169: super .endDocument();
0170:
0171: this .State = new Integer(this .XGD_END);
0172: } /*Method-End*/
0173:
0174: public void endElement(java.lang.String name)
0175: throws org.xml.sax.SAXException {
0176: // Debug information
0177: int lInitialState = this .State.intValue();
0178:
0179: try {
0180: if (name.equals("ARRAY"))
0181: this .popRowCount();
0182:
0183: if (!name.equals("_.ALIAS")) {
0184: switch (this .State.intValue()) {
0185: case XGD_NEED_ATTRIBUTE:
0186: this .validateTag(name, "OBJECT", true);
0187: this .popState();
0188:
0189: break;
0190: case XGD_NEED_END_ATTR:
0191: java.lang.String lFieldName = this .topAttrName();
0192: this .validateTag(this .unescapeName(name),
0193: lFieldName, true);
0194: java.lang.Object lObj = this .popObject();
0195: this .setCurrentAttribute(lObj);
0196: this .popAttrName();
0197: this .popState();
0198:
0199: break;
0200: case XGD_NEED_END_PARAM:
0201: this .validateTag(name, "PARAM", true);
0202:
0203: break;
0204: case XGD_NEED_END_ROW:
0205: this .validateTag(name, "ROW", true);
0206: this .popState();
0207: java.lang.Object lRow = this .popObject();
0208:
0209: Object lArrayRef = this .topObject();
0210: if (lArrayRef instanceof java.util.Collection) {
0211: java.util.Collection lArray = (java.util.Collection) (lArrayRef);
0212: lArray.add(lRow);
0213: } else if (lArrayRef.getClass().isArray()) {
0214: int lRowNo = this .currentRowCount();
0215: Array.set(lArrayRef, lRowNo, lRow);
0216: this .incrementRowCount();
0217: }
0218: break;
0219: case XGD_NEED_END_NULLVALUE:
0220: this .validateTag(name, "NULLVALUE", true);
0221: this .popState();
0222:
0223: break;
0224: case XGD_NEED_END_OBJECT:
0225: this .validateTag(name, "OBJECT", true);
0226: this .popState();
0227:
0228: break;
0229:
0230: case XGD_NEED_PARAM:
0231: // System.out.println("In endElement and this.XGD_NEED_PARAM currently a no op ");
0232: this .popState();
0233: break;
0234: case XGD_NEED_ROW:
0235: this .validateTag(name, "ARRAY", true);
0236: this .popState();
0237: this .popRowType();
0238:
0239: break;
0240:
0241: case XGD_NEED_VALUE:
0242: this .popState();
0243:
0244: java.lang.String lValue = null;
0245: java.lang.String lSource = this .getCharacters();
0246:
0247: int lLength = lSource.length();
0248:
0249: if (lLength != 0 || lLength != 1) {
0250: lValue = lSource;
0251: }
0252:
0253: switch (this .State.intValue()) {
0254: case XGD_NEED_END_ROW:
0255: this .validateTag(name, "ROW", true);
0256:
0257: java.util.Collection lArray2 = (java.util.Collection) (this
0258: .topObject());
0259:
0260: java.lang.Object lRow2 = null;
0261: java.lang.Class lRowType;
0262:
0263: lRowType = this .topRowType();
0264:
0265: if (lRowType == java.lang.String.class) {
0266: //java.lang.String lNewString = new String(lValue);
0267: java.lang.String lNewString = (lValue);
0268: lArray2.add(lNewString);
0269: } else {
0270: lArray2.add(lRow2);
0271: }// end if
0272: this .popState();
0273: break;
0274: case XGD_NEED_END_ATTR:
0275: this .validateTag(this .unescapeName(name), this
0276: .topAttrName(), true);
0277: this .setCurrentAttribute(lValue);
0278: this .popAttrName();
0279: this .popState();
0280: break;
0281: case XGD_NEED_END_PARAM:
0282: // System.out.println("In endElement and this.XGD_NEED_VALUE,XGD_NEED_END_PARAM currently a no op ");
0283: this .popState();
0284: this .pushState(this .XGD_NEED_PARAM);
0285: break;
0286: //AddParameter(value, ParameterClass, ParameterSetMethod);
0287: }// end case;
0288:
0289: break;
0290: case XGD_NEED_STRING:
0291: // System.out.println("In endElement and this.XGD_NEED_STRING currently a no op ");
0292: this .popState();
0293: break;
0294: case XGD_NEED_END_ROW_ELEMENT:
0295: // System.out.println("In endElement and this.XGD_NEED_END_ROW_ELEMENT currently a no op ");
0296:
0297: this .State = new Integer(this .XGD_NEED_ROW_ELEMENT);
0298: break;
0299: case XGD_NEED_ROW_ELEMENT:
0300: // System.out.println("In endElement and this.XGD_NEED_ROW_ELEMENT currently a no op ");
0301: this .State = new Integer(this .XGD_NEED_ROW_TAG);
0302: break;
0303: case XGD_NEED_ROW_TAG:
0304: // System.out.println("In endElement and this.XGD_NEED_ROW_TAG currently a no op ");
0305: this .popState();
0306:
0307: break;
0308: case XGD_NEED_OBJECT:
0309: // Cases we should never see
0310: this .unexpectedTag(name, "OBJECT", false);
0311:
0312: break;
0313: }// end case
0314: }// end if
0315:
0316: super .endElement(name);
0317: }// end try
0318: catch (SAXException lError) {
0319: // Dump so debug information if ew get an exception at this point
0320: lError.printStackTrace();
0321: System.out
0322: .println("Exception cause in XMLGraphDeserializer.endElement");
0323: System.out.println("Tag being process is " + name
0324: + " initial state was " + lInitialState);
0325: this .DumpStatus();
0326: // Now rethrow the exception
0327: throw lError;
0328:
0329: }// end catch
0330: catch (RuntimeException lError) {
0331: // Dump so debug information if ew get an exception at this point
0332: lError.printStackTrace();
0333: System.out
0334: .println("Exception cause in XMLGraphDeserializer.endElement");
0335: System.out.println("Tag being process is " + name
0336: + " initial state was " + lInitialState);
0337: this .DumpStatus();
0338: // Now rethrow the exception
0339: throw lError;
0340:
0341: }// end catch
0342:
0343: } /*Method-End*/
0344:
0345: public void startDocument() throws org.xml.sax.SAXException {
0346: super .startDocument();
0347:
0348: State = new Integer(this .XGD_END);
0349: this .pushState(this .XGD_NEED_OBJECT);
0350: } /*Method-End*/
0351:
0352: public void startElement(java.lang.String name,
0353: org.xml.sax.AttributeList atts)
0354: throws org.xml.sax.SAXException {
0355:
0356: // Debug information
0357: int lInitialState = this .State.intValue();
0358:
0359: /* System.out.println("startElement : Current State is " + this.State);
0360: System.out.println("startElement : State stack is ");
0361: System.out.println(this.StateStack);
0362: System.out.println("startElement : State stack finished ");
0363: System.out.println("Name is " + name);
0364: */
0365: try {
0366:
0367: if (name.equals("ARRAY"))
0368: this .pushRowCount();
0369:
0370: if (name.equals("_.ALIAS")) {
0371: java.lang.String lName = atts.getValue("NAME");
0372: java.lang.String lAlias = atts.getValue("ALIAS");
0373: this .addActiveAlias(lName, lAlias);
0374: } else {
0375: switch (this .State.intValue()) {
0376: case XGD_NEED_ATTRIBUTE:
0377: this .readAttributeHeader(name, atts);
0378: break;
0379: case XGD_NEED_ROW_TAG:
0380: // System.out.println("In startElement and this.XGD_NEED_ROW_TAG currently a no op ");
0381: this .State = new Integer(this .XGD_NEED_ROW_ELEMENT);
0382: break;
0383: // row : XMLRow = new;
0384: // row.Elements = new;
0385: // row.RowTag = name;
0386: // state = XGD_NEED_ROW_ELEMENT;
0387: // PushObject(row);
0388: case XGD_NEED_ROW_ELEMENT:
0389: // System.out.println("In startElement and this.XGD_NEED_ROW_ELEMENT currently a no op ");
0390: this .State = new Integer(
0391: this .XGD_NEED_END_ROW_ELEMENT);
0392: break;
0393: // elm : XMLRowElement = new;
0394: // elm.ElementNm = name;
0395: // elm.ClassNm = atts.GetValue('CLASS');
0396: // XMLRow(TopObject()).Elements.Add(elm);
0397: // PushObject(elm);
0398: // state = XGD_NEED_END_ROW_ELEMENT;
0399: case XGD_NEED_ROW:
0400: this .validateTag(name, "ROW", false);
0401:
0402: if (this .checkSimpleRow(name, atts)) {
0403: this .pushState(XGD_NEED_END_ROW);
0404: } else {
0405: this .pushState(XGD_NEED_END_ROW);
0406: this .pushState(XGD_NEED_VALUE);
0407: }
0408: break;
0409: case XGD_NEED_OBJECT:
0410: this .validateTag(name, "OBJECT", false);
0411: this .readObjectHeader(name, atts, false);
0412: break;
0413: case XGD_NEED_PARAM:
0414: // System.out.println("In startElement and this.XGD_NEED_PARAM currently a no op ");
0415: //this.validateTag(name, "PARAM", false);
0416: this .popState();
0417: this .pushState(this .XGD_NEED_END_PARAM);
0418: this .pushState(this .XGD_NEED_VALUE);
0419: //className : string = atts.GetValue('CLASS');
0420: //if className = NIL then
0421: // ParameterClass = NIL;
0422: //else
0423: // ParameterClass = FindClass(className);
0424: //end if;
0425: //ParameterSetMethod = atts.GetValue('SETMETHOD');
0426: //PopState();
0427: //PushState(XGD_NEED_END_PARAM);
0428: //PushState(XGD_NEED_VALUE);
0429: break;
0430: case XGD_NEED_VALUE:
0431: if (!name.equals("OBJECT") && !name.equals("ARRAY")
0432: && !name.equals("NULLVALUE")) {
0433: this .unexpectedTag(name,
0434: "OBJECT, ARRAY, NULLVALUE", false);
0435: }// end if;
0436: this .readValue(name, atts);
0437:
0438: break;
0439:
0440: case XGD_NEED_END_ATTR:
0441: // Cases we should never see
0442: this .unexpectedTag(name, this .topAttrName(), true);
0443: break;
0444: case XGD_NEED_END_PARAM:
0445: this .unexpectedTag(name, "/PARAM", false);
0446: break;
0447: case XGD_NEED_END_ROW:
0448:
0449: this .unexpectedTag(name, "/ROW", false);
0450: break;
0451: case XGD_NEED_END_NULLVALUE:
0452: this .unexpectedTag(name, "/NULLVALUE", false);
0453: break;
0454: case XGD_NEED_END_OBJECT:
0455: this .unexpectedTag(name, "/OBJECT", false);
0456: break;
0457: }// end case
0458: }// end if
0459:
0460: super .startElement(name, atts);
0461:
0462: }// end try
0463: catch (SAXException lError) {
0464: // Dump so debug information if ew get an exception at this point
0465: lError.printStackTrace();
0466: System.out
0467: .println("Exception cause in XMLGraphDeserializer.startElement");
0468: System.out.println("Tag being process is " + name
0469: + " initial state was " + lInitialState);
0470: System.out.println("Attribute list is :");
0471: for (int i = 0; i < atts.getLength(); i++) {
0472: System.out.println("Attribute " + atts.getName(i)
0473: + " Type " + atts.getType(i) + " value "
0474: + atts.getValue(i));
0475: }
0476: this .DumpStatus();
0477: // Now rethrow the exception
0478: throw lError;
0479:
0480: }// end catch
0481: catch (RuntimeException lError) {
0482: // Dump so debug information if ew get an exception at this point
0483: lError.printStackTrace();
0484: System.out
0485: .println("Exception cause in XMLGraphDeserializer.startElement");
0486: System.out.println("Tag being process is " + name
0487: + " initial state was " + lInitialState);
0488: System.out.println("Attribute list is :");
0489: for (int i = 0; i < atts.getLength(); i++) {
0490: System.out.println("Attribute " + atts.getName(i)
0491: + " Type " + atts.getType(i) + " value "
0492: + atts.getValue(i));
0493: }
0494: this .DumpStatus();
0495: // Now rethrow the exception
0496: throw lError;
0497:
0498: }// end catch
0499: } /*Method-End*/
0500:
0501: public java.lang.Class findClass(java.lang.String name)
0502: throws java.lang.ClassNotFoundException {
0503: return super .findClass(this .lookupAlias(name));
0504: } /*Method-End*/
0505:
0506: public java.lang.String popAttrName() {
0507: return (java.lang.String) (AttrNameStack.pop());
0508: } /*Method-End*/
0509:
0510: public void processObjectReference(java.lang.String refName)
0511: throws org.xml.sax.SAXException {
0512: //@olsen+MBO: assign directly
0513: java.lang.Object lObj = this .ObjectHash.get(refName);
0514:
0515: if (lObj == null) {
0516: //String message = new String("Object " + refName + " could not be found");
0517: String message = ("Object " + refName + " could not be found");
0518:
0519: SAXException objError = new SAXException(message);
0520:
0521: throw objError;
0522: }
0523: this .pushObject(lObj);
0524: } /*Method-End*/
0525:
0526: public void pushAttrName(java.lang.String name) {
0527: this .AttrNameStack.push(name);
0528: } /*Method-End*/
0529:
0530: public void readAttributeHeader(java.lang.String name,
0531: org.xml.sax.AttributeList atts) {
0532: //@olsen+MBO: intended to compare strings by '==' instead of equals()?
0533: if (name == "_.METHOD" || name == "_.CALLBACK") {
0534: this .pushAttrName(atts.getValue("NAME"));
0535: this .pushAttrName(name);
0536: this .pushState(this .XGD_NEED_PARAM);
0537: this .ParameterArray.clear();
0538: } else {
0539: this .pushAttrName(this .unescapeName(name));
0540: this .pushState(this .XGD_NEED_END_ATTR);
0541: this .pushState(this .XGD_NEED_VALUE);
0542: }
0543: } /*Method-End*/
0544:
0545: public void readObjectHeader(java.lang.String name,
0546: org.xml.sax.AttributeList atts, boolean refOK)
0547: throws org.xml.sax.SAXException {
0548: boolean lFirstObj = (this .ObjectStack.size() == 0);
0549: Object lObj = null;
0550: String lIDName = null;
0551:
0552: if (refOK) {
0553: java.lang.String lRefName = atts.getValue("REFERENCE");
0554: if (lRefName != null) {
0555: this .processObjectReference(lRefName);
0556: State = new Integer(this .XGD_NEED_END_OBJECT);
0557: return;
0558: }// end if
0559: }// end if;
0560:
0561: // MBO: need to get the object name here
0562: lIDName = atts.getValue("ID");
0563:
0564: if (lFirstObj
0565: || !this
0566: .useExistingAttribute(atts, topAttrName(), lObj)) {
0567: java.lang.String lClassName = atts.getValue("CLASS");
0568: if (lClassName == null) {
0569: lObj = null;
0570: } else {
0571: java.lang.Class lClass = null;
0572: try {
0573: lClass = this .findClass(lClassName);
0574: // MBO: special handling for wrapper classes.
0575: // We need to postpone the creation of the wrapper
0576: // class instance to the point in time where the value
0577: // is available, because the value field might be
0578: // final. Store all the information that is available
0579: // here (class object and object id) into a
0580: // WrapperClassHelper and push this on the object
0581: // stack. The helper will be replaced later by the
0582: // wrapper class instance.
0583: if (WrapperClassHelper.isWrapperClass(lClass))
0584: lObj = new WrapperClassHelper(lClass, lIDName);
0585: else
0586: lObj = lClass.newInstance();
0587: } catch (IllegalAccessException e1) {
0588: e1.printStackTrace();
0589: //java.lang.String message = new String("Illegal Access to class " + lClass.getName());
0590: java.lang.String message = ("Illegal Access to class " + lClass
0591: .getName());
0592: SAXException useError = new SAXException(message);
0593: throw useError;
0594: } catch (InstantiationException e2) {
0595:
0596: lObj = NewInstanceHelper.newInstance(lClassName,
0597: this .topObject());
0598: if (lObj == null) {
0599: e2.printStackTrace();
0600:
0601: //java.lang.String message = new String("Instantiation exception of class " + lClass.getName());
0602: java.lang.String message = ("Instantiation exception of class " + lClass
0603: .getName());
0604: SAXException useError = new SAXException(
0605: message);
0606: throw useError;
0607: }
0608: } catch (ClassNotFoundException e3) {
0609: e3.printStackTrace();
0610:
0611: //java.lang.String message = new String("Class " + lClass.getName() + " could not be found");
0612: java.lang.String message = ("Class "
0613: + lClass.getName() + " could not be found");
0614: SAXException useError = new SAXException(message);
0615: throw useError;
0616: }
0617: }// end if
0618: }// end if
0619:
0620: this .pushObject(lObj);
0621:
0622: // handle id
0623: if (lIDName != null) {
0624: this .ObjectHash.put(lIDName, lObj);
0625: }// end if
0626:
0627: if (lFirstObj) {
0628: this .MasterDeserializer.setInitialObject(lObj);
0629: }// end if
0630:
0631: if (lObj == null) {
0632: State = new Integer(this .XGD_NEED_END_OBJECT);
0633: }
0634: //else if (lobj.IsA(Stringizeable) then
0635: // State = XGD_NEED_STRING;
0636: //else if obj.IsA(UseXMLRows) then
0637: // UseXMLRows(obj).BeginXMLRows(FALSE);
0638: // State = XGD_NEED_ROW_TAG;
0639: else {
0640: State = new Integer(this .XGD_NEED_ATTRIBUTE);
0641: }
0642: } /*Method-End*/
0643:
0644: public java.lang.String topAttrName() {
0645:
0646: return (java.lang.String) (this .AttrNameStack.peek());
0647: } /*Method-End*/
0648:
0649: public void readValue(java.lang.String name,
0650: org.xml.sax.AttributeList atts)
0651: throws org.xml.sax.SAXException {
0652: boolean lFirstObj = (this .ObjectStack.size() == 0);
0653:
0654: if (name.equals("OBJECT")) {
0655: this .readObjectHeader(name, atts, true);
0656: } else if (name.equals("ARRAY")) {
0657: java.lang.Object lObj = null;
0658: java.lang.Class lRowClassType = null;
0659: java.lang.Object lArray = null;
0660:
0661: // really need a way of working out what type
0662: // of array this is but this will do for now
0663:
0664: String lArrayType = atts.getValue("CLASS");
0665: int lArraySize = Integer.parseInt(atts.getValue("SIZE"));
0666: java.lang.String lRowTypeName = atts.getValue("ROWCLASS");
0667:
0668: // if ( lArrayType.equals("PRIMITIVE") )
0669: // lArray = new ArrayList();
0670: // else
0671: if (!lArrayType.equals("PRIMITIVE")) {
0672: try {
0673: Class lArrayTypeClass = this .findClass(lArrayType);
0674: lArray = lArrayTypeClass.newInstance();
0675: } catch (ClassNotFoundException e1) {
0676: e1.printStackTrace();
0677: //java.lang.String message = new String("Class " + lArrayType + " could not be found, " +
0678: // "either it has the wrong name or cannot be found in lookup table");
0679: java.lang.String message = ("Class " + lArrayType
0680: + " could not be found, " + "either it has the wrong name or cannot be found in lookup table");
0681: SAXException classError = new SAXException(message);
0682: throw classError;
0683: } catch (IllegalAccessException e2) {
0684: e2.printStackTrace();
0685: //java.lang.String message = new String("Illegal Access exception whilst trying to init new instance of " + lArrayType);
0686: java.lang.String message = ("Illegal Access exception whilst trying to init new instance of " + lArrayType);
0687: SAXException accessError = new SAXException(message);
0688: throw accessError;
0689: } catch (InstantiationException e3) {
0690: e3.printStackTrace();
0691: //java.lang.String message = new String("Instantiation exception whilst trying to init new instance of " + lArrayType);
0692: java.lang.String message = ("Instantiation exception whilst trying to init new instance of " + lArrayType);
0693: SAXException initError = new SAXException(message);
0694: throw initError;
0695: }
0696:
0697: }
0698:
0699: if (!lFirstObj
0700: && this .useExistingAttribute(atts, this
0701: .topAttrName(), lObj)) {
0702: // lArray = (java.util.ArrayList)(lObj);
0703: lArray = lObj;
0704: }// end if;
0705:
0706: // I can't simply check the array for the row type
0707: // as array list does not have an default class
0708: // also I am assuming for the minutes that TOOL array map
0709: // to ArrayList's RESOLVE later
0710:
0711: if (lRowTypeName != null && !lRowTypeName.equals("")) {
0712: try {
0713: lRowClassType = this .findClass(lRowTypeName);
0714: } catch (ClassNotFoundException e1) {
0715: e1.printStackTrace();
0716: //java.lang.String message = new String("Class " + lRowTypeName + " could not be found, " +
0717: // "either it has the wrong name or cannot be found in lookup table");
0718: java.lang.String message = ("Class " + lRowTypeName
0719: + " could not be found, " + "either it has the wrong name or cannot be found in lookup table");
0720: SAXException classError = new SAXException(message);
0721: throw classError;
0722: }
0723: } else {
0724: lRowClassType = java.lang.Object.class;
0725: }// end if;
0726:
0727: if (lArrayType.equals("PRIMITIVE")) {
0728: lArray = Array.newInstance(lRowClassType, lArraySize);
0729: }
0730:
0731: this .pushRowType(lRowClassType);
0732: this .pushObject(lArray);
0733: this .State = new Integer(this .XGD_NEED_ROW);
0734: } else if (name.equals("NULLVALUE")) {
0735: java.lang.Object lCurrentObj = null;
0736: Field lField = null;
0737: try {
0738: lCurrentObj = this .topObject();
0739: // due to the fact that this method is currently
0740: // designed to handle tool to java conversion
0741: // we must get all of the declared fields and do
0742: // a caseless search as tool is not case sensitive
0743: // if we have someway of working out the destination
0744: // language then we should do a check here
0745: //lField = lCurrentObj.getClass().getDeclaredField(this.topAttrName());
0746:
0747: /* @olsen+MBO: perf. optimization: replace reflect:field lookup by method findField that caches Field objects
0748: Field[] lFields = null;
0749: lFields = lCurrentObj.getClass().getDeclaredFields();
0750:
0751:
0752: if (lFields == null ||
0753: lFields.length == 0)
0754: {
0755: java.lang.String message = new String("No fields on class " + lCurrentObj.getClass().getName());
0756: java.lang.NoSuchFieldException noFieldsError = new NoSuchFieldException(message);
0757: //SAXException noFieldsError = new SAXException(message);
0758:
0759: throw noFieldsError;
0760:
0761: }
0762:
0763: FORLOOP:
0764: for (int i = 0; i < lFields.length; i++)
0765: {
0766: if (lFields[i].getName().equalsIgnoreCase(this.topAttrName()))
0767: {
0768: lField = lFields[i];
0769: break FORLOOP;
0770: }
0771: }
0772: */
0773: // MBO: This code is suspicious!
0774: // - I could not find the place in the XMLGraphSerializer
0775: // that creates an element called NULLVALUE, so maybe this
0776: // code is never executed.
0777: // - It creates an instance of the type of the current
0778: // field, which fails if the field type is an interface!
0779: // - It pushes an instance on the object statck where it is
0780: // not clear to me where the instance is removed.
0781: //@olsen+MBO: perf. optimization
0782: lField = findField(lCurrentObj, this .topAttrName());
0783:
0784: if (lField == null)
0785: // MBO: field not found. The current version of the class
0786: // does not declare the field anymore => ignore.
0787: this .pushObject(new Object());
0788: else
0789: this .pushObject(lField.getType().newInstance());
0790:
0791: this .State = new Integer(this .XGD_NEED_END_NULLVALUE);
0792: } catch (InstantiationException e1) {
0793: e1.printStackTrace();
0794: //java.lang.String message = new String("Could not init instance of " + lField.getType().getName());
0795: java.lang.String message = ("Could not init instance of " + lField
0796: .getType().getName());
0797: SAXException initError = new SAXException(message);
0798: throw initError;
0799: } catch (IllegalAccessException e2) {
0800: e2.printStackTrace();
0801: //java.lang.String message = new String("Illegal access of field " + this.topAttrName());
0802: java.lang.String message = ("Illegal access of field " + this
0803: .topAttrName());
0804: SAXException illegalError = new SAXException(message);
0805: throw illegalError;
0806: }
0807: }// end if;
0808: } /*Method-End*/
0809:
0810: public void pushRowType(java.lang.Class type) {
0811: this .RowTypeStack.push(type);
0812: } /*Method-End*/
0813:
0814: public java.lang.Class popRowType() {
0815: return (java.lang.Class) (this .RowTypeStack.pop());
0816: } /*Method-End*/
0817:
0818: public void setCurrentAttribute(java.lang.Object value)
0819: throws org.xml.sax.SAXException {
0820: java.lang.Object lCurrentObj = this .topObject();
0821: java.lang.String lCurrentField = this .topAttrName();
0822:
0823: // MBO: special handling for wrapper class instances.
0824: // A WrapperClassHelper instance on top of the object stack
0825: // indicates the creation of the wrapper class instance was
0826: // postponed. Now we have the value, so we can create the wrapper
0827: // class instance.
0828: if (lCurrentObj instanceof WrapperClassHelper) {
0829: WrapperClassHelper helper = (WrapperClassHelper) lCurrentObj;
0830: // Represent the value as an instance of the wrapper class.
0831: lCurrentObj = helper.valueOf((String) value);
0832: // The top of the ObjectStack is a WrapperClassHelper, which
0833: // needs to be replaced by the wrapper class instance itself.
0834: popObject();
0835: pushObject(lCurrentObj);
0836: // In case of a named object (having an ID) we need to replace
0837: // the WrapperClassHelper instance in the ObjectMap by the
0838: // wrapper class instance itself.
0839: String id = helper.getId();
0840: if (id != null)
0841: this .ObjectHash.put(id, lCurrentObj);
0842:
0843: // The wrapper class object is created with its value, so we
0844: // are done with this instace => return.
0845: return;
0846: }
0847:
0848: Field lField = null;
0849:
0850: try {
0851: // due to the fact that this method is currently
0852: // designed to handle tool to java conversion
0853: // we must get all of the declared fields and do
0854: // a caseless search as tool is not case sensitive
0855: // if we have someway of working out the destination
0856: // language then we should do a check here
0857: //lField = lCurrentObj.getClass().getDeclaredField(lCurrentField);
0858:
0859: // also to handle a particular tool convension that is not
0860: // used much in java we will strip leading '_' characters of
0861: // field name and check both types. This is a fudge that we may wish
0862: // to remove
0863:
0864: /* @olsen+MBO: perf. optimization: replace reflect:field lookup by method findField that caches Field objects
0865: java.lang.StringBuffer lSBuff = new StringBuffer(lCurrentField);
0866: java.lang.String lAltFieldName = null;
0867: if (lSBuff.charAt(0) == '_')
0868: {
0869: // chop the '_' character off
0870: lSBuff.deleteCharAt(0);
0871: lAltFieldName = lSBuff.toString();
0872: }
0873:
0874: // this is a tmp store of the fields
0875: Field[] lTFields = null;
0876: // this is were all of the fields including the
0877: // super classes fields will end up
0878: java.util.ArrayList lFields = new ArrayList();
0879:
0880: // place holder for a class reference which initially
0881: // points to the class of the current object
0882: // but later will point to the currect objects's super clases
0883: java.lang.Class lClass = lCurrentObj.getClass();
0884:
0885: //lTFields = lCurrentObj.getClass().getDeclaredFields();
0886:
0887: while (lClass != null)
0888: {
0889: lTFields = lClass.getDeclaredFields();
0890: lFields.ensureCapacity(lTFields.length);
0891:
0892: for (int i = 0; i < lTFields.length; i++)
0893: {
0894: lFields.add(lTFields[i]);
0895: }
0896:
0897: lClass = lClass.getSuperclass();
0898: }
0899:
0900:
0901: // if (lFields == null ||
0902: // lFields.length == 0)
0903: if (lFields.isEmpty())
0904: {
0905: java.lang.String message = new String("No fields on class " + lCurrentObj.getClass().getName());
0906: java.lang.NoSuchFieldException noFieldsError = new NoSuchFieldException(message);
0907: //SAXException noFieldsError = new SAXException(message);
0908:
0909: throw noFieldsError;
0910:
0911: }
0912:
0913: // for (int i = 0; i < lFields.length; i++)
0914: int lSize = lFields.size();
0915: FORLOOP:
0916: for (int i = 0; i < lSize; i++)
0917: {
0918: Field tField = (Field)(lFields.get(i));
0919: if (tField.getName().equalsIgnoreCase(lCurrentField))
0920: {
0921: lField = tField;
0922: break FORLOOP;
0923: }// end if
0924:
0925: if (lAltFieldName != null)
0926: {
0927: if (tField.getName().equalsIgnoreCase(lAltFieldName))
0928: {
0929: lField = tField;
0930: break FORLOOP;
0931: }// end if
0932: }// end if
0933: }// end for
0934: */
0935:
0936: //@olsen+MBO: perf. optimization
0937: lField = findField(lCurrentObj, lCurrentField);
0938:
0939: if (lField == null)
0940: // MBO: field not found. The current version of the class
0941: // does not declare the field anymore => ignore.
0942: return;
0943:
0944: // System.out.println(lField.toString());
0945: // System.out.println(lField.getType().getName());
0946: // System.out.println("Value is :" + value + ":");
0947:
0948: // first thing we are going to do it set the accessibility
0949: // flag such that we are able to access the field just in
0950: // case it is private/package/protected visibility
0951:
0952: //@olsen+MBO: moved to findField()
0953: //lField.setAccessible(true);
0954:
0955: java.lang.Class lFieldClass = lField.getType();
0956: if (lFieldClass.isPrimitive()
0957: && value instanceof java.lang.String) {
0958: //@olsen+MBO: use .class instead of .TYPE
0959: if (lFieldClass == int.class)
0960: lField.setInt(lCurrentObj, java.lang.Integer
0961: .parseInt((java.lang.String) (value)));
0962: else if (lFieldClass == short.class)
0963: lField.setShort(lCurrentObj, java.lang.Short
0964: .parseShort((java.lang.String) (value)));
0965: else if (lFieldClass == long.class)
0966: lField.setLong(lCurrentObj, java.lang.Long
0967: .parseLong((java.lang.String) (value)));
0968: //@olsen+MBO: changed for Byte
0969: else if (lFieldClass == byte.class)
0970: lField.setByte(lCurrentObj, java.lang.Byte
0971: .parseByte((java.lang.String) (value)));
0972: else if (lFieldClass == double.class)
0973: lField.setDouble(lCurrentObj, java.lang.Double
0974: .parseDouble((java.lang.String) (value)));
0975: else if (lFieldClass == float.class)
0976: lField.setFloat(lCurrentObj, java.lang.Float
0977: .parseFloat((java.lang.String) (value)));
0978: else if (lFieldClass == boolean.class)
0979: lField.setBoolean(lCurrentObj, (java.lang.Boolean
0980: .valueOf((java.lang.String) (value)))
0981: .booleanValue());
0982: else if (lFieldClass == char.class)
0983: lField.setChar(lCurrentObj,
0984: ((java.lang.String) (value)).charAt(0));
0985: } else if (lFieldClass.isArray()
0986: && value instanceof ArrayList) {
0987: // OK we are actually dealing with a primitive array here
0988: // but we have got an ArrayList so we need to do some transformation
0989:
0990: Class lArrayType = lFieldClass.getComponentType();
0991: ArrayList lList = (ArrayList) (value);
0992:
0993: Object lArray = Array.newInstance(lArrayType, lList
0994: .size());
0995: for (int i = 0; i < lList.size(); i++) {
0996: Array.set(lArray, i, lList.get(i));
0997: }
0998:
0999: lField.set(lCurrentObj, lArray);
1000: }
1001: // else if (lFieldClass.isArray())
1002: // {
1003: // lField.set(lCurrentObj, value);
1004: // }
1005: else {
1006: lField.set(lCurrentObj, value);
1007: }
1008: } catch (IllegalAccessException e1) {
1009: e1.printStackTrace();
1010: //java.lang.String message = new String("Illegal access of field " + lCurrentField);
1011: java.lang.String message = ("Illegal access of field " + lCurrentField);
1012: SAXException accessError = new SAXException(message);
1013:
1014: throw accessError;
1015: }
1016:
1017: catch (SecurityException e3) {
1018: e3.printStackTrace();
1019: //java.lang.String message = new String("Security Exception accessing fields of" + lCurrentObj.getClass().getName());
1020: java.lang.String message = ("Security Exception accessing fields of" + lCurrentObj
1021: .getClass().getName());
1022: SAXException accessError = new SAXException(message);
1023:
1024: throw accessError;
1025: } catch (RuntimeException e4) {
1026: e4.printStackTrace();
1027: throw e4;
1028: }
1029: } /*Method-End*/
1030:
1031: public java.lang.Class topRowType() {
1032: return (java.lang.Class) (this .RowTypeStack.peek());
1033: } /*Method-End*/
1034:
1035: private boolean checkSimpleRow(java.lang.String name,
1036: org.xml.sax.AttributeList atts)
1037: throws org.xml.sax.SAXException {
1038: boolean isSimple = false;
1039:
1040: String lRowType = atts.getValue("ROWCLASS");
1041: String lRowValue = atts.getValue("VALUE");
1042:
1043: if (lRowType != null && !lRowType.equals("")) {
1044: isSimple = true;
1045:
1046: if (lRowType.equals("java.lang.String"))
1047: this .pushObject(lRowValue);
1048: else if (lRowType.equals("java.lang.StringBuffer"))
1049: this .pushObject(new StringBuffer(lRowValue));
1050: else if (lRowType.equals("int")
1051: || lRowType.equals("java.lang.Integer"))
1052: this .pushObject(Integer.valueOf(lRowValue));
1053: else if (lRowType.equals("short")
1054: || lRowType.equals("java.lang.Short"))
1055: this .pushObject(Short.valueOf(lRowValue));
1056: else if (lRowType.equals("long")
1057: || lRowType.equals("java.lang.Long"))
1058: this .pushObject(Long.valueOf(lRowValue));
1059: else if (lRowType.equals("float")
1060: || lRowType.equals("java.lang.Float"))
1061: this .pushObject(Float.valueOf(lRowValue));
1062: else if (lRowType.equals("double")
1063: || lRowType.equals("java.lang.Double"))
1064: this .pushObject(Double.valueOf(lRowValue));
1065: else if (lRowType.equals("boolean")
1066: || lRowType.equals("java.lang.Boolean"))
1067: this .pushObject(Boolean.valueOf(lRowValue));
1068: else if (lRowType.equals("char")
1069: || lRowType.equals("java.lang.Character"))
1070: this .pushObject(new Character(lRowValue.charAt(0)));
1071: else {
1072: System.out.println("Found and unknow type in a row");
1073: this .pushObject(null);
1074: }
1075:
1076: }
1077:
1078: return isSimple;
1079: }
1080:
1081: public void DumpStatus() {
1082: // This method is a debug method to dump status information about this object
1083: super .DumpStatus();
1084:
1085: System.out.println("Dump Status from class XMLGraphSerializer");
1086: System.out.println("Row Type stack " + this .RowTypeStack);
1087: System.out.println("Row Counter stack " + this .RowCountStack);
1088: System.out.println("Object hash table " + this .ObjectHash);
1089: System.out
1090: .println("Dump Status from class XMLGraphSerializer - END");
1091:
1092: }
1093:
1094: private void pushRowCount() {
1095: Integer lInt = new Integer(0);
1096: this .RowCountStack.push(lInt);
1097: }
1098:
1099: private void popRowCount() {
1100: this .RowCountStack.pop();
1101: }
1102:
1103: private int currentRowCount() {
1104: Integer lInt = (Integer) (this .RowCountStack.peek());
1105: return lInt.intValue();
1106: }
1107:
1108: private void incrementRowCount() {
1109: Integer lInt = (Integer) (this .RowCountStack.pop());
1110: int lRowCount = lInt.intValue();
1111: lRowCount++;
1112: this .RowCountStack.push(new Integer(lRowCount));
1113: }
1114:
1115: // MBO: added new class WrapperClassHelper.
1116:
1117: /**
1118: * The WrapperClassHelper stores all necessary information (the wrapper
1119: * class object and an ID) in case the creation of a wrapper class
1120: * instance is postponed to when the value is available. Use method
1121: * valueOf(String s) to convert a String represenation into a value of
1122: * the wrapper class stored in the helper.
1123: */
1124: private static class WrapperClassHelper {
1125: /**
1126: * Interface defining a valueOf method that converts the specified
1127: * string into an instance of a wrapper class.
1128: */
1129: private static interface Converter {
1130: public Object valueOf(String s);
1131: }
1132:
1133: /** Map of wrapper class to Converter instances. */
1134: private static final Map converters;
1135:
1136: static {
1137: // Initialize wrapper class to converter map
1138: converters = new HashMap(8);
1139: converters.put(Boolean.class, new Converter() {
1140: public Object valueOf(String s) {
1141: return Boolean.valueOf(s);
1142: }
1143: });
1144: converters.put(Byte.class, new Converter() {
1145: public Object valueOf(String s) {
1146: return Byte.valueOf(s);
1147: }
1148: });
1149: converters.put(Short.class, new Converter() {
1150: public Object valueOf(String s) {
1151: return Short.valueOf(s);
1152: }
1153: });
1154: converters.put(Character.class, new Converter() {
1155: public Object valueOf(String s) {
1156: return new Character(s.charAt(0));
1157: }
1158: });
1159: converters.put(Integer.class, new Converter() {
1160: public Object valueOf(String s) {
1161: return Integer.valueOf(s);
1162: }
1163: });
1164: converters.put(Long.class, new Converter() {
1165: public Object valueOf(String s) {
1166: return Long.valueOf(s);
1167: }
1168: });
1169: converters.put(Float.class, new Converter() {
1170: public Object valueOf(String s) {
1171: return Float.valueOf(s);
1172: }
1173: });
1174: converters.put(Double.class, new Converter() {
1175: public Object valueOf(String s) {
1176: return Double.valueOf(s);
1177: }
1178: });
1179: }
1180:
1181: /** Class instance of the wrapper class. */
1182: private Class wrapperClass;
1183:
1184: /** Key in the ObjectHash map. */
1185: private String id;
1186:
1187: /**
1188: * Constructor.
1189: * @param wrapperClasses the Class instance of the wrapper class.
1190: * @param id the key in the the ObjectHash map.
1191: */
1192: public WrapperClassHelper(Class wrapperClass, String id) {
1193: this .wrapperClass = wrapperClass;
1194: this .id = id;
1195: }
1196:
1197: /** Returns the key in the ObjectHash map. */
1198: public String getId() {
1199: return id;
1200: }
1201:
1202: /**
1203: * Returns a wrapper Class object holding the value given by the
1204: * specified String. This method converts the specified string into
1205: * an instance of the wrapper class stored in this
1206: * WrapperClassHelper.
1207: * @param s the string to be parsed.
1208: * @return a wrapper Class object holding the value represented by
1209: * the string argument.
1210: */
1211: public Object valueOf(String s) {
1212: Converter conv = (Converter) converters.get(wrapperClass);
1213: return conv != null ? conv.valueOf(s) : null;
1214: }
1215:
1216: /**
1217: * Determines if the specified argument represents a Java wrapper
1218: * class.
1219: * @param class the Class to be tested
1220: * @return true if the specified argument represents a Java wrapper
1221: * class.
1222: */
1223: public static boolean isWrapperClass(Class clazz) {
1224: return converters.containsKey(clazz);
1225: }
1226:
1227: }
1228:
1229: } // end of class
|