0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one
0003: * or more contributor license agreements. See the NOTICE file
0004: * distributed with this work for additional information
0005: * regarding copyright ownership. The ASF licenses this file
0006: * to you under the Apache License, Version 2.0 (the
0007: * "License"); you may not use this file except in compliance
0008: * with the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing,
0013: * software distributed under the License is distributed on an
0014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015: * KIND, either express or implied. See the License for the
0016: * specific language governing permissions and limitations
0017: * under the License.
0018: */
0019: package org.apache.axis2.databinding.utils.reader;
0020:
0021: import org.apache.axiom.om.OMAttribute;
0022: import org.apache.axiom.om.OMElement;
0023: import org.apache.axiom.om.OMNamespace;
0024: import org.apache.axiom.om.impl.util.OMSerializerUtil;
0025: import org.apache.axis2.databinding.ADBBean;
0026: import org.apache.axis2.databinding.utils.BeanUtil;
0027: import org.apache.axis2.databinding.utils.ConverterUtil;
0028: import org.apache.axis2.description.java2wsdl.TypeTable;
0029:
0030: import javax.activation.DataHandler;
0031: import javax.xml.namespace.NamespaceContext;
0032: import javax.xml.namespace.QName;
0033: import javax.xml.stream.Location;
0034: import javax.xml.stream.XMLStreamException;
0035: import javax.xml.stream.XMLStreamReader;
0036: import java.util.Arrays;
0037: import java.util.HashMap;
0038: import java.util.Map;
0039: import java.util.Iterator;
0040:
0041: /**
0042: * This is the new implementation of the ADBpullaparser. The approach here is simple When the pull
0043: * parser needs to generate events for a particular name-value(s) pair it always handes over
0044: * (delegates) the task to another pull parser which knows how to deal with it The common types of
0045: * name value pairs we'll come across are 1. String name/QName name - String value 2. String
0046: * name/QName name - String[] value 3. OMElementkey - OMElement value 4. QName name/String name -
0047: * ADBBean value 5. QName name/String name - Java bean 5. QName name/String name - Datahandler
0048: * <p/>
0049: * As for the attributes, these are the possible combinations in the array 1. String name/QName name
0050: * - String value 2. OMAttributeKey - OMAttribute
0051: * <p/>
0052: * Note that certain array methods have been deliberately removed to avoid complications. The
0053: * generated code will take the trouble to lay the elements of the array in the correct order
0054: * <p/>
0055: * <p/>
0056: * Hence there will be a parser impl that knows how to handle these types, and this parent parser
0057: * will always delegate these tasks to the child pullparasers in effect this is one huge state
0058: * machine that has only a few states and delegates things down to the child parsers whenever
0059: * possible
0060: * <p/>
0061: */
0062: public class ADBXMLStreamReaderImpl implements ADBXMLStreamReader {
0063:
0064: private Object[] properties;
0065: private Object[] attributes;
0066: private QName elementQName;
0067:
0068: //This is to store the QName which are in the typeTable after setting the correct prefix
0069: private HashMap qnameMap = new HashMap();
0070:
0071: //we always create a new namespace context
0072: private ADBNamespaceContext namespaceContext = new ADBNamespaceContext();
0073:
0074: private Map declaredNamespaceMap = new HashMap();
0075:
0076: //states for this pullparser - it can only have four states
0077: private static final int START_ELEMENT_STATE = 0;
0078: private static final int END_ELEMENT_STATE = 1;
0079: private static final int DELEGATED_STATE = 2;
0080: private static final int TEXT_STATE = 3;
0081:
0082: //integer field that keeps the state of this
0083: //parser.
0084: private int state = START_ELEMENT_STATE;
0085:
0086: //reference to the child reader
0087: private ADBXMLStreamReader childReader;
0088:
0089: //current property index
0090: //initialized at zero
0091: private int currentPropertyIndex = 0;
0092:
0093: //To keep element formdefault qualified or not
0094: private boolean qualified = false;
0095:
0096: //to keep the current types which are in AxisService
0097: private TypeTable typeTable = null;
0098:
0099: /*
0100: * we need to pass in a namespace context since when delegated, we've no
0101: * idea of the current namespace context. So it needs to be passed on
0102: * here!
0103: */
0104: public ADBXMLStreamReaderImpl(QName adbBeansQName,
0105: Object[] properties, Object[] attributes) {
0106: //validate the lengths, since both the arrays are supposed
0107: //to have
0108: this .properties = properties;
0109: this .elementQName = adbBeansQName;
0110: this .attributes = attributes;
0111: }
0112:
0113: public ADBXMLStreamReaderImpl(QName adbBeansQName,
0114: Object[] properties, Object[] attributes,
0115: TypeTable typeTable, boolean qualified) {
0116: this (adbBeansQName, properties, attributes);
0117: this .qualified = qualified;
0118: this .typeTable = typeTable;
0119: if (this .typeTable != null) {
0120: Map complexTypeMap = this .typeTable.getComplexSchemaMap();
0121: if (complexTypeMap != null) {
0122: Iterator keys = complexTypeMap.keySet().iterator();
0123: while (keys.hasNext()) {
0124: String key = (String) keys.next();
0125: QName qname = (QName) complexTypeMap.get(key);
0126: if (qname != null) {
0127: String prefix = qname.getPrefix();
0128: if (prefix == null && "".equals(prefix)) {
0129: prefix = OMSerializerUtil.getNextNSPrefix();
0130: }
0131: qname = new QName(qname.getNamespaceURI(),
0132: qname.getLocalPart(), prefix);
0133: this .typeTable.getComplexSchemaMap().put(key,
0134: qname);
0135: qnameMap.put(qname.getNamespaceURI(), prefix);
0136: addToNsMap(prefix, qname.getNamespaceURI());
0137: }
0138: }
0139: }
0140: }
0141: }
0142:
0143: /** add the namespace context */
0144:
0145: public void addNamespaceContext(NamespaceContext nsContext) {
0146: // register the namespace context passed in to this
0147: this .namespaceContext.setParentNsContext(nsContext);
0148:
0149: }
0150:
0151: /**
0152: * we need to split out the calling to the populate namespaces seperately since this needs to be
0153: * done *after* setting the parent namespace context. We cannot assume it will happen at
0154: * construction!
0155: */
0156: public void init() {
0157: // here we have an extra issue to attend to. we need to look at the
0158: // prefixes and uris (the combination) and populate a hashmap of
0159: // namespaces. The hashmap of namespaces will be used to serve the
0160: // namespace context
0161:
0162: populateNamespaceContext();
0163: }
0164:
0165: /**
0166: * @param key
0167: * @throws IllegalArgumentException
0168: */
0169: public Object getProperty(String key)
0170: throws IllegalArgumentException {
0171: if (state == START_ELEMENT_STATE || state == END_ELEMENT_STATE) {
0172: if (OPTIMIZATION_ENABLED.equals(key)) {
0173: return Boolean.TRUE;
0174: } else {
0175: return null;
0176: }
0177: } else if (state == TEXT_STATE) {
0178: if (IS_BINARY.equals(key)) {
0179: return Boolean.FALSE;
0180: } else {
0181: return null;
0182: }
0183: } else if (state == DELEGATED_STATE) {
0184: return childReader.getProperty(key);
0185: } else {
0186: return null;
0187: }
0188:
0189: }
0190:
0191: public void require(int i, String string, String string1)
0192: throws XMLStreamException {
0193: throw new UnsupportedOperationException();
0194: }
0195:
0196: /**
0197: * todo implement the right contract for this
0198: *
0199: * @throws XMLStreamException
0200: */
0201: public String getElementText() throws XMLStreamException {
0202: if (state == DELEGATED_STATE) {
0203: return childReader.getElementText();
0204: } else {
0205: return null;
0206: }
0207:
0208: }
0209:
0210: /**
0211: * todo implement this
0212: *
0213: * @throws XMLStreamException
0214: */
0215: public int nextTag() throws XMLStreamException {
0216: return 0;
0217: }
0218:
0219: /** @throws XMLStreamException */
0220: public boolean hasNext() throws XMLStreamException {
0221: if (state == DELEGATED_STATE) {
0222: if (childReader.isDone()) {
0223: //the child reader is done. We shouldn't be getting the
0224: //hasnext result from the child pullparser then
0225: return true;
0226: } else {
0227: return childReader.hasNext();
0228: }
0229: } else {
0230: return (state == START_ELEMENT_STATE || state == TEXT_STATE);
0231:
0232: }
0233: }
0234:
0235: public void close() throws XMLStreamException {
0236: //do nothing here - we have no resources to free
0237: }
0238:
0239: public String getNamespaceURI(String prefix) {
0240: return namespaceContext.getNamespaceURI(prefix);
0241: }
0242:
0243: public boolean isStartElement() {
0244: if (state == START_ELEMENT_STATE) {
0245: return true;
0246: } else if (state == END_ELEMENT_STATE) {
0247: return false;
0248: }
0249: return childReader.isStartElement();
0250: }
0251:
0252: public boolean isEndElement() {
0253: if (state == START_ELEMENT_STATE) {
0254: return false;
0255: } else if (state == END_ELEMENT_STATE) {
0256: return true;
0257: }
0258: return childReader.isEndElement();
0259: }
0260:
0261: public boolean isCharacters() {
0262: if (state == START_ELEMENT_STATE || state == END_ELEMENT_STATE) {
0263: return false;
0264: }
0265: return childReader.isCharacters();
0266: }
0267:
0268: public boolean isWhiteSpace() {
0269: if (state == START_ELEMENT_STATE || state == END_ELEMENT_STATE) {
0270: return false;
0271: }
0272: return childReader.isWhiteSpace();
0273: }
0274:
0275: ///////////////////////////////////////////////////////////////////////////
0276: /// attribute handling
0277: ///////////////////////////////////////////////////////////////////////////
0278:
0279: public String getAttributeValue(String nsUri, String localName) {
0280:
0281: int attribCount = getAttributeCount();
0282: String returnValue = null;
0283: QName attribQualifiedName;
0284: for (int i = 0; i < attribCount; i++) {
0285: attribQualifiedName = getAttributeName(i);
0286: if (nsUri == null) {
0287: if (localName
0288: .equals(attribQualifiedName.getLocalPart())) {
0289: returnValue = getAttributeValue(i);
0290: break;
0291: }
0292: } else {
0293: if (localName
0294: .equals(attribQualifiedName.getLocalPart())
0295: && nsUri.equals(attribQualifiedName
0296: .getNamespaceURI())) {
0297: returnValue = getAttributeValue(i);
0298: break;
0299: }
0300: }
0301:
0302: }
0303:
0304: return returnValue;
0305: }
0306:
0307: public int getAttributeCount() {
0308: return (state == DELEGATED_STATE) ? childReader
0309: .getAttributeCount()
0310: : ((attributes != null)
0311: && (state == START_ELEMENT_STATE) ? attributes.length / 2
0312: : 0);
0313: }
0314:
0315: /** @param i */
0316: public QName getAttributeName(int i) {
0317: if (state == DELEGATED_STATE) {
0318: return childReader.getAttributeName(i);
0319: } else if (state == START_ELEMENT_STATE) {
0320: if (attributes == null) {
0321: return null;
0322: } else {
0323: if ((i >= (attributes.length / 2)) || i < 0) { //out of range
0324: return null;
0325: } else {
0326: //get the attribute pointer
0327: Object attribPointer = attributes[i * 2];
0328: //case one - attrib name is null
0329: //this should be the pointer to the OMAttribute then
0330: if (attribPointer == null) {
0331: Object omAttribObj = attributes[(i * 2) + 1];
0332: if (omAttribObj == null
0333: || !(omAttribObj instanceof OMAttribute)) {
0334: // wrong object set to have in the attrib array -
0335: // this should have been detected by now but just be
0336: // sure
0337: throw new UnsupportedOperationException();
0338: }
0339: OMAttribute att = (OMAttribute) omAttribObj;
0340: return att.getQName();
0341: } else if (attribPointer instanceof OMAttribKey) {
0342: Object omAttribObj = attributes[(i * 2) + 1];
0343: if (omAttribObj == null
0344: || !(omAttribObj instanceof OMAttribute)) {
0345: // wrong object set to have in the attrib array -
0346: // this should have been detected by now but just be
0347: // sure
0348: throw new UnsupportedOperationException();
0349: }
0350: OMAttribute att = (OMAttribute) omAttribObj;
0351: return att.getQName();
0352: //case two - attrib name is a plain string
0353: } else if (attribPointer instanceof String) {
0354: return new QName((String) attribPointer);
0355: } else if (attribPointer instanceof QName) {
0356: return (QName) attribPointer;
0357: } else {
0358: return null;
0359: }
0360: }
0361: }
0362: } else {
0363: throw new IllegalStateException();//as per the api contract
0364: }
0365:
0366: }
0367:
0368: public String getAttributeNamespace(int i) {
0369: if (state == DELEGATED_STATE) {
0370: return childReader.getAttributeNamespace(i);
0371: } else if (state == START_ELEMENT_STATE) {
0372: QName name = getAttributeName(i);
0373: if (name == null) {
0374: return null;
0375: } else {
0376: return name.getNamespaceURI();
0377: }
0378: } else {
0379: throw new IllegalStateException();
0380: }
0381: }
0382:
0383: public String getAttributeLocalName(int i) {
0384: if (state == DELEGATED_STATE) {
0385: return childReader.getAttributeLocalName(i);
0386: } else if (state == START_ELEMENT_STATE) {
0387: QName name = getAttributeName(i);
0388: if (name == null) {
0389: return null;
0390: } else {
0391: return name.getLocalPart();
0392: }
0393: } else {
0394: throw new IllegalStateException();
0395: }
0396: }
0397:
0398: public String getAttributePrefix(int i) {
0399: if (state == DELEGATED_STATE) {
0400: return childReader.getAttributePrefix(i);
0401: } else if (state == START_ELEMENT_STATE) {
0402: QName name = getAttributeName(i);
0403: if (name == null) {
0404: return null;
0405: } else {
0406: return name.getPrefix();
0407: }
0408: } else {
0409: throw new IllegalStateException();
0410: }
0411: }
0412:
0413: public String getAttributeType(int i) {
0414: return null; //not supported
0415: }
0416:
0417: public String getAttributeValue(int i) {
0418: if (state == DELEGATED_STATE) {
0419: return childReader.getAttributeValue(i);
0420: } else if (state == START_ELEMENT_STATE) {
0421: if (attributes == null) {
0422: return null;
0423: } else {
0424: if ((i >= (attributes.length / 2)) || i < 0) { //out of range
0425: return null;
0426: } else {
0427: //get the attribute pointer
0428: Object attribPointer = attributes[i * 2];
0429: Object omAttribObj = attributes[(i * 2) + 1];
0430: //case one - attrib name is null
0431: //this should be the pointer to the OMAttribute then
0432: if (attribPointer == null) {
0433:
0434: if (omAttribObj == null
0435: || !(omAttribObj instanceof OMAttribute)) {
0436: // wrong object set to have in the attrib array -
0437: // this should have been detected by now but just be
0438: // sure
0439: throw new UnsupportedOperationException();
0440: }
0441: OMAttribute att = (OMAttribute) omAttribObj;
0442: return att.getAttributeValue();
0443: } else if (attribPointer instanceof OMAttribKey) {
0444: if (omAttribObj == null
0445: || !(omAttribObj instanceof OMAttribute)) {
0446: // wrong object set to have in the attrib array -
0447: // this should have been detected by now but just be
0448: // sure
0449: throw new UnsupportedOperationException();
0450: }
0451: OMAttribute att = (OMAttribute) omAttribObj;
0452: return att.getAttributeValue();
0453: //case two - attrib name is a plain string
0454: } else if (attribPointer instanceof String) {
0455: return (String) omAttribObj;
0456: } else if (attribPointer instanceof QName) {
0457: if (omAttribObj instanceof QName) {
0458: QName attributeQName = (QName) omAttribObj;
0459: // first check it is already there if not add the namespace.
0460: String prefix = namespaceContext
0461: .getPrefix(attributeQName
0462: .getNamespaceURI());
0463: if (prefix == null) {
0464: prefix = OMSerializerUtil
0465: .getNextNSPrefix();
0466: addToNsMap(prefix, attributeQName
0467: .getNamespaceURI());
0468: }
0469:
0470: String attributeValue = null;
0471: if (prefix.equals("")) {
0472: // i.e. this is the default namespace
0473: attributeValue = attributeQName
0474: .getLocalPart();
0475: } else {
0476: attributeValue = prefix + ":"
0477: + attributeQName.getLocalPart();
0478: }
0479: return attributeValue;
0480: } else {
0481: return (String) omAttribObj;
0482: }
0483:
0484: } else {
0485: return null;
0486: }
0487: }
0488: }
0489: } else {
0490: throw new IllegalStateException();
0491: }
0492:
0493: }
0494:
0495: public boolean isAttributeSpecified(int i) {
0496: return false; //not supported
0497: }
0498:
0499: ///////////////////////////////////////////////////////////////////////////
0500: ////////////// end of attribute handling
0501: ///////////////////////////////////////////////////////////////////////////
0502:
0503: ////////////////////////////////////////////////////////////////////////////
0504: ////////////// namespace handling
0505: ////////////////////////////////////////////////////////////////////////////
0506:
0507: public int getNamespaceCount() {
0508: if (state == DELEGATED_STATE) {
0509: return childReader.getNamespaceCount();
0510: } else {
0511: return declaredNamespaceMap.size();
0512: }
0513: }
0514:
0515: /** @param i */
0516: public String getNamespacePrefix(int i) {
0517: if (state == DELEGATED_STATE) {
0518: return childReader.getNamespacePrefix(i);
0519: } else if (state != TEXT_STATE) {
0520: //order the prefixes
0521: String[] prefixes = makePrefixArray();
0522: if ((i >= prefixes.length) || (i < 0)) {
0523: return null;
0524: } else {
0525: return prefixes[i];
0526: }
0527:
0528: } else {
0529: throw new IllegalStateException();
0530: }
0531:
0532: }
0533:
0534: /** Get the prefix list from the hastable and take that into an array */
0535: private String[] makePrefixArray() {
0536: String[] prefixes = (String[]) declaredNamespaceMap.keySet()
0537: .toArray(new String[declaredNamespaceMap.size()]);
0538: Arrays.sort(prefixes);
0539: return prefixes;
0540: }
0541:
0542: public String getNamespaceURI(int i) {
0543: if (state == DELEGATED_STATE) {
0544: return childReader.getNamespaceURI(i);
0545: } else if (state != TEXT_STATE) {
0546: String namespacePrefix = getNamespacePrefix(i);
0547: return namespacePrefix == null ? null
0548: : (String) declaredNamespaceMap
0549: .get(namespacePrefix);
0550: } else {
0551: throw new IllegalStateException();
0552: }
0553:
0554: }
0555:
0556: public NamespaceContext getNamespaceContext() {
0557: if (state == DELEGATED_STATE) {
0558: return childReader.getNamespaceContext();
0559: } else {
0560: return namespaceContext;
0561: }
0562:
0563: }
0564:
0565: ///////////////////////////////////////////////////////////////////////////
0566: ///////// end of namespace handling
0567: ///////////////////////////////////////////////////////////////////////////
0568:
0569: public int getEventType() {
0570: if (state == START_ELEMENT_STATE) {
0571: return START_ELEMENT;
0572: } else if (state == END_ELEMENT_STATE) {
0573: return END_ELEMENT;
0574: } else { // this is the delegated state
0575: return childReader.getEventType();
0576: }
0577:
0578: }
0579:
0580: public String getText() {
0581: if (state == DELEGATED_STATE) {
0582: return childReader.getText();
0583: } else if (state == TEXT_STATE) {
0584: Object property = properties[currentPropertyIndex - 1];
0585: if (property instanceof DataHandler) {
0586: return ConverterUtil
0587: .getStringFromDatahandler((DataHandler) property);
0588: } else {
0589: return (String) properties[currentPropertyIndex - 1];
0590: }
0591: } else {
0592: throw new IllegalStateException();
0593: }
0594: }
0595:
0596: public char[] getTextCharacters() {
0597: if (state == DELEGATED_STATE) {
0598: return childReader.getTextCharacters();
0599: } else if (state == TEXT_STATE) {
0600: return properties[currentPropertyIndex - 1] == null ? new char[0]
0601: : ((String) properties[currentPropertyIndex - 1])
0602: .toCharArray();
0603: } else {
0604: throw new IllegalStateException();
0605: }
0606: }
0607:
0608: public int getTextCharacters(int i, char[] chars, int i1, int i2)
0609: throws XMLStreamException {
0610: if (state == DELEGATED_STATE) {
0611: return childReader.getTextCharacters(i, chars, i1, i2);
0612: } else if (state == TEXT_STATE) {
0613: //todo - implement this
0614: return 0;
0615: } else {
0616: throw new IllegalStateException();
0617: }
0618: }
0619:
0620: public int getTextStart() {
0621: if (state == DELEGATED_STATE) {
0622: return childReader.getTextStart();
0623: } else if (state == TEXT_STATE) {
0624: return 0;//assume text always starts at 0
0625: } else {
0626: throw new IllegalStateException();
0627: }
0628: }
0629:
0630: public int getTextLength() {
0631: if (state == DELEGATED_STATE) {
0632: return childReader.getTextLength();
0633: } else if (state == TEXT_STATE) {
0634: return 0;//assume text always starts at 0
0635: } else {
0636: throw new IllegalStateException();
0637: }
0638: }
0639:
0640: public String getEncoding() {
0641: if (state == DELEGATED_STATE) {
0642: return childReader.getEncoding();
0643: } else {
0644: //we've no idea what the encoding is going to be in this case
0645: //perhaps we ought to return some constant here, which the user might
0646: //have access to change!
0647: return null;
0648: }
0649: }
0650:
0651: /** check the validity of this implementation */
0652: public boolean hasText() {
0653: if (state == DELEGATED_STATE) {
0654: return childReader.hasText();
0655: } else
0656: return state == TEXT_STATE;
0657:
0658: }
0659:
0660: /**
0661: */
0662: public Location getLocation() {
0663: //return a default location
0664: return new Location() {
0665: public int getLineNumber() {
0666: return 0;
0667: }
0668:
0669: public int getColumnNumber() {
0670: return 0;
0671: }
0672:
0673: public int getCharacterOffset() {
0674: return 0;
0675: }
0676:
0677: public String getPublicId() {
0678: return null;
0679: }
0680:
0681: public String getSystemId() {
0682: return null;
0683: }
0684: };
0685: }
0686:
0687: public QName getName() {
0688: if (state == DELEGATED_STATE) {
0689: return childReader.getName();
0690: } else if (state != TEXT_STATE) {
0691: return elementQName;
0692: } else {
0693: throw new IllegalStateException();
0694: }
0695:
0696: }
0697:
0698: public String getLocalName() {
0699: if (state == DELEGATED_STATE) {
0700: return childReader.getLocalName();
0701: } else if (state != TEXT_STATE) {
0702: return elementQName.getLocalPart();
0703: } else {
0704: throw new IllegalStateException();
0705: }
0706: }
0707:
0708: public boolean hasName() {
0709: //since this parser always has a name, the hasname
0710: //has to return true if we are still navigating this element
0711: //if not we should ask the child reader for it.
0712: if (state == DELEGATED_STATE) {
0713: return childReader.hasName();
0714: } else
0715: return state != TEXT_STATE;
0716: }
0717:
0718: public String getNamespaceURI() {
0719: if (state == DELEGATED_STATE) {
0720: return childReader.getNamespaceURI();
0721: } else if (state == TEXT_STATE) {
0722: return null;
0723: } else {
0724: return elementQName.getNamespaceURI();
0725: }
0726: }
0727:
0728: public String getPrefix() {
0729: if (state == DELEGATED_STATE) {
0730: return childReader.getPrefix();
0731: } else if (state == TEXT_STATE) {
0732: return null;
0733: } else {
0734: String prefix = elementQName.getPrefix();
0735: return "".equals(prefix) ? null : prefix;
0736: }
0737: }
0738:
0739: public String getVersion() {
0740: return null;
0741: }
0742:
0743: public boolean isStandalone() {
0744: return true;
0745: }
0746:
0747: public boolean standaloneSet() {
0748: return true;
0749: }
0750:
0751: public String getCharacterEncodingScheme() {
0752: return null; //todo - should we return something for this ?
0753: }
0754:
0755: public String getPITarget() {
0756: throw new UnsupportedOperationException(
0757: "Yet to be implemented !!");
0758: }
0759:
0760: public String getPIData() {
0761: throw new UnsupportedOperationException(
0762: "Yet to be implemented !!");
0763: }
0764:
0765: ///////////////////////////////////////////////////////////////////////////
0766: /// Other utility methods
0767: //////////////////////////////////////////////////////////////////////////
0768:
0769: /** Populates a namespace context */
0770: private void populateNamespaceContext() {
0771:
0772: //first add the current element namespace to the namespace context
0773: //declare it if not found
0774: addToNsMap(elementQName.getPrefix(), elementQName
0775: .getNamespaceURI());
0776:
0777: //traverse through the attributes and populate the namespace context
0778: //the attrib list can be of many combinations
0779: // the valid combinations are
0780: // String - String
0781: // QName - QName
0782: // null - OMAttribute
0783:
0784: if (attributes != null) {
0785: for (int i = 0; i < attributes.length; i = i + 2) { //jump in two
0786: Object attribName = attributes[i];
0787: if (attribName == null) {
0788: //this should be the OMAttrib case!
0789: OMAttribute OMAttrib = (OMAttribute) attributes[i + 1];
0790: OMNamespace namespace = OMAttrib.getNamespace();
0791: if (namespace != null) {
0792: addToNsMap(namespace.getPrefix(), namespace
0793: .getNamespaceURI());
0794: }
0795: } else if (attribName instanceof OMAttribKey) {
0796: //this is definitely the OMAttribute case
0797: OMAttribute OMAttrib = (OMAttribute) attributes[i + 1];
0798: OMNamespace namespace = OMAttrib.getNamespace();
0799: if (namespace != null) {
0800: addToNsMap(namespace.getPrefix(), namespace
0801: .getNamespaceURI());
0802: }
0803: } else if (attribName instanceof String) {
0804: //ignore this case - Nothing to do
0805: } else if (attribName instanceof QName) {
0806: QName attribQName = ((QName) attribName);
0807: addToNsMap(attribQName.getPrefix(), attribQName
0808: .getNamespaceURI());
0809:
0810: }
0811: }
0812: }
0813:
0814: }
0815:
0816: /**
0817: * @param prefix
0818: * @param uri
0819: */
0820: private void addToNsMap(String prefix, String uri) {
0821: if (!uri.equals(namespaceContext.getNamespaceURI(prefix))) {
0822: namespaceContext.pushNamespace(prefix, uri);
0823: declaredNamespaceMap.put(prefix, uri);
0824: }
0825: }
0826:
0827: /**
0828: * By far this should be the most important method in this class this method changes the state
0829: * of the parser
0830: */
0831: public int next() throws XMLStreamException {
0832: int returnEvent = -1; //invalid state is the default state
0833: switch (state) {
0834: case START_ELEMENT_STATE:
0835: //current element is start element. We should be looking at the
0836: //property list and making a pullparser for the property value
0837: if (properties == null || properties.length == 0) {
0838: //no properties - move to the end element state straightaway
0839: state = END_ELEMENT_STATE;
0840: returnEvent = END_ELEMENT;
0841: } else {
0842: //there are properties. now we should delegate this task to a
0843: //child reader depending on the property type
0844: returnEvent = processProperties();
0845:
0846: }
0847: break;
0848: case END_ELEMENT_STATE:
0849: //we've reached the end element already. If the user tries to push
0850: // further ahead then it is an exception
0851: throw new XMLStreamException(
0852: "Trying to go beyond the end of the pullparser");
0853:
0854: case DELEGATED_STATE:
0855: if (childReader.isDone()) {
0856: //we've reached the end!
0857: if (currentPropertyIndex > (properties.length - 1)) {
0858: state = END_ELEMENT_STATE;
0859: returnEvent = END_ELEMENT;
0860: } else {
0861: returnEvent = processProperties();
0862: }
0863: } else {
0864: returnEvent = childReader.next();
0865: }
0866: break;
0867:
0868: case TEXT_STATE:
0869: // if there are any more event we should be delegating to
0870: // processProperties. if not we just return an end element
0871: if (currentPropertyIndex > (properties.length - 1)) {
0872: state = END_ELEMENT_STATE;
0873: returnEvent = END_ELEMENT;
0874: } else {
0875: returnEvent = processProperties();
0876: }
0877: break;
0878: }
0879: return returnEvent;
0880: }
0881:
0882: /**
0883: * A convenient method to reuse the properties
0884: *
0885: * @return event to be thrown
0886: * @throws XMLStreamException
0887: */
0888: private int processProperties() throws XMLStreamException {
0889: //move to the next property depending on the current property
0890: //index
0891: Object propPointer = properties[currentPropertyIndex];
0892: QName propertyQName = null;
0893: boolean textFound = false;
0894: if (propPointer == null) {
0895: throw new XMLStreamException("property key cannot be null!");
0896: } else if (propPointer instanceof String) {
0897: // propPointer being a String has a special case
0898: // that is it can be a the special constant ELEMENT_TEXT that
0899: // says this text event
0900: if (ELEMENT_TEXT.equals(propPointer)) {
0901: textFound = true;
0902: } else {
0903: propertyQName = new QName((String) propPointer);
0904: }
0905: } else if (propPointer instanceof QName) {
0906: propertyQName = (QName) propPointer;
0907: } else if (propPointer instanceof OMElementKey) {
0908: // ah - in this case there's nothing to be done
0909: //about the propertyQName in this case - we'll just leave
0910: //it as it is
0911: } else {
0912: //oops - we've no idea what kind of key this is
0913: throw new XMLStreamException("unidentified property key!!!"
0914: + propPointer);
0915: }
0916:
0917: if (propertyQName != null) {
0918: String prefix = (String) qnameMap.get(propertyQName
0919: .getNamespaceURI());
0920: if (prefix != null) {
0921: propertyQName = new QName(propertyQName
0922: .getNamespaceURI(), propertyQName
0923: .getLocalPart(), prefix);
0924: }
0925: }
0926:
0927: //ok! we got the key. Now look at the value
0928: Object propertyValue = properties[currentPropertyIndex + 1];
0929: //cater for the special case now
0930: if (textFound) {
0931: //no delegation here - make the parser null and immediately
0932: //return with the event characters
0933: childReader = null;
0934: state = TEXT_STATE;
0935: currentPropertyIndex = currentPropertyIndex + 2;
0936: return CHARACTERS;
0937: } else if (propertyValue == null) {
0938: //if the value is null we delegate the work to a nullable
0939: // parser
0940: childReader = new NullXMLStreamReader(propertyQName);
0941: childReader.addNamespaceContext(this .namespaceContext);
0942: childReader.init();
0943:
0944: //we've a special pullparser for a datahandler!
0945: } else if (propertyValue instanceof DataHandler) {
0946: childReader = new ADBDataHandlerStreamReader(propertyQName,
0947: (DataHandler) propertyValue);
0948: childReader.addNamespaceContext(this .namespaceContext);
0949: childReader.init();
0950:
0951: } else if (propertyValue instanceof String) {
0952: //strings are handled by the NameValuePairStreamReader
0953: childReader = new NameValuePairStreamReader(propertyQName,
0954: (String) propertyValue);
0955: childReader.addNamespaceContext(this .namespaceContext);
0956: childReader.init();
0957: } else if (propertyValue instanceof String[]) {
0958: //string[] are handled by the NameValueArrayStreamReader
0959: //if the array is empty - skip it
0960: if (((String[]) propertyValue).length == 0) {
0961: //advance the index
0962: currentPropertyIndex = currentPropertyIndex + 2;
0963: return processProperties();
0964: } else {
0965: childReader = new NameValueArrayStreamReader(
0966: propertyQName, (String[]) propertyValue);
0967: childReader.addNamespaceContext(this .namespaceContext);
0968: childReader.init();
0969: }
0970:
0971: } else if (propertyValue instanceof ADBBean) {
0972: //ADBbean has it's own method to get a reader
0973: XMLStreamReader reader = ((ADBBean) propertyValue)
0974: .getPullParser(propertyQName);
0975: // we know for sure that this is an ADB XMLStreamreader.
0976: // However we need to make sure that it is compatible
0977: if (reader instanceof ADBXMLStreamReader) {
0978: childReader = (ADBXMLStreamReader) reader;
0979: childReader.addNamespaceContext(this .namespaceContext);
0980: childReader.init();
0981: } else {
0982: //wrap it to make compatible
0983: childReader = new WrappingXMLStreamReader(reader);
0984: }
0985: } else if (propertyValue instanceof OMElement) {
0986: //OMElements do not provide the kind of parser we need
0987: //there is no other option than wrapping
0988: childReader = new WrappingXMLStreamReader(
0989: ((OMElement) propertyValue).getXMLStreamReader());
0990: //we cannot register the namespace context here!!
0991:
0992: } else {
0993: //all special possiblilities has been tried! Let's treat
0994: //the thing as a bean and try generating events from it
0995: childReader = new WrappingXMLStreamReader(BeanUtil
0996: .getPullParser(propertyValue, propertyQName,
0997: typeTable, qualified, false));
0998: //we cannot register the namespace context here
0999: }
1000:
1001: //set the state here
1002: state = DELEGATED_STATE;
1003: //we are done with the delegation
1004: //increment the property index
1005: currentPropertyIndex = currentPropertyIndex + 2;
1006: return childReader.getEventType();
1007: }
1008:
1009: /** are we done ? */
1010: public boolean isDone() {
1011: return (state == END_ELEMENT_STATE);
1012: }
1013:
1014: }
|