001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.streaming;
038:
039: import javax.xml.namespace.QName;
040: import static javax.xml.stream.XMLStreamConstants.*;
041: import javax.xml.stream.XMLStreamException;
042: import javax.xml.stream.XMLStreamReader;
043: import javax.xml.stream.XMLStreamConstants;
044:
045: /**
046: * <p> XMLStreamReaderUtil provides some utility methods intended to be used
047: * in conjunction with a StAX XMLStreamReader. </p>
048: *
049: * @author WS Development Team
050: */
051: public class XMLStreamReaderUtil {
052:
053: private XMLStreamReaderUtil() {
054: }
055:
056: public static void close(XMLStreamReader reader) {
057: try {
058: reader.close();
059: } catch (XMLStreamException e) {
060: throw wrapException(e);
061: }
062: }
063:
064: public static void readRest(XMLStreamReader reader) {
065: try {
066: while (reader.getEventType() != XMLStreamConstants.END_DOCUMENT) {
067: reader.next();
068: }
069: } catch (XMLStreamException e) {
070: throw wrapException(e);
071: }
072: }
073:
074: public static int next(XMLStreamReader reader) {
075: try {
076: int readerEvent = reader.next();
077:
078: while (readerEvent != END_DOCUMENT) {
079: switch (readerEvent) {
080: case START_ELEMENT:
081: case END_ELEMENT:
082: case CDATA:
083: case CHARACTERS:
084: case PROCESSING_INSTRUCTION:
085: return readerEvent;
086: default:
087: // falls through ignoring event
088: }
089: readerEvent = reader.next();
090: }
091:
092: return readerEvent;
093: } catch (XMLStreamException e) {
094: throw wrapException(e);
095: }
096: }
097:
098: public static int nextElementContent(XMLStreamReader reader) {
099: int state = nextContent(reader);
100: if (state == CHARACTERS) {
101: throw new XMLStreamReaderException(
102: "xmlreader.unexpectedCharacterContent", reader
103: .getText());
104: }
105: return state;
106: }
107:
108: public static int nextContent(XMLStreamReader reader) {
109: for (;;) {
110: int state = next(reader);
111: switch (state) {
112: case START_ELEMENT:
113: case END_ELEMENT:
114: case END_DOCUMENT:
115: return state;
116: case CHARACTERS:
117: if (!reader.isWhiteSpace()) {
118: return CHARACTERS;
119: }
120: }
121: }
122: }
123:
124: /**
125: * Skip current element, leaving the cursor at END_ELEMENT of
126: * current element.
127: */
128: public static void skipElement(XMLStreamReader reader) {
129: assert reader.getEventType() == START_ELEMENT;
130: skipTags(reader, true);
131: assert reader.getEventType() == END_ELEMENT;
132: }
133:
134: /**
135: * Skip following siblings, leaving cursor at END_ELEMENT of
136: * parent element.
137: */
138: public static void skipSiblings(XMLStreamReader reader, QName parent) {
139: skipTags(reader, reader.getName().equals(parent));
140: assert reader.getEventType() == END_ELEMENT;
141: }
142:
143: private static void skipTags(XMLStreamReader reader,
144: boolean exitCondition) {
145: try {
146: int state, tags = 0;
147: while ((state = reader.next()) != END_DOCUMENT) {
148: if (state == START_ELEMENT) {
149: tags++;
150: } else if (state == END_ELEMENT) {
151: if (tags == 0 && exitCondition)
152: return;
153: tags--;
154: }
155: }
156: } catch (XMLStreamException e) {
157: throw wrapException(e);
158: }
159: }
160:
161: /*
162: * Get the text of an element
163: */
164: public static String getElementText(XMLStreamReader reader) {
165: try {
166: return reader.getElementText();
167: } catch (XMLStreamException e) {
168: throw wrapException(e);
169: }
170: }
171:
172: /*
173: * Get a QName with 'someUri' and 'localname' from an
174: * element of qname type:
175: * <xyz xmlns:ns1="someUri">ns1:localname</xyz>
176: */
177: public static QName getElementQName(XMLStreamReader reader) {
178: try {
179: String text = reader.getElementText().trim();
180: String prefix = text.substring(0, text.indexOf(':'));
181: String namespaceURI = reader.getNamespaceContext()
182: .getNamespaceURI(prefix);
183: if (namespaceURI == null) {
184: namespaceURI = "";
185: }
186: String localPart = text.substring(text.indexOf(':') + 1,
187: text.length());
188: return new QName(namespaceURI, localPart);
189: } catch (XMLStreamException e) {
190: throw wrapException(e);
191: }
192: }
193:
194: /**
195: * Read all attributes into an data structure. Note that this method cannot
196: * be called multiple times to get the same list of attributes.
197: */
198: public static Attributes getAttributes(XMLStreamReader reader) {
199: return (reader.getEventType() == START_ELEMENT || reader
200: .getEventType() == ATTRIBUTE) ? new AttributesImpl(
201: reader) : null;
202: }
203:
204: public static void verifyReaderState(XMLStreamReader reader,
205: int expectedState) {
206: int state = reader.getEventType();
207: if (state != expectedState) {
208: throw new XMLStreamReaderException(
209: "xmlreader.unexpectedState",
210: getStateName(expectedState), getStateName(state));
211: }
212: }
213:
214: public static void verifyTag(XMLStreamReader reader,
215: String namespaceURI, String localName) {
216: if (!localName.equals(reader.getLocalName())
217: || !namespaceURI.equals(reader.getNamespaceURI())) {
218: throw new XMLStreamReaderException(
219: "xmlreader.unexpectedState.tag", "{" + namespaceURI
220: + "}" + localName, "{"
221: + reader.getNamespaceURI() + "}"
222: + reader.getLocalName());
223: }
224: }
225:
226: public static void verifyTag(XMLStreamReader reader, QName name) {
227: verifyTag(reader, name.getNamespaceURI(), name.getLocalPart());
228: }
229:
230: public static String getStateName(XMLStreamReader reader) {
231: return getStateName(reader.getEventType());
232: }
233:
234: public static String getStateName(int state) {
235: switch (state) {
236: case ATTRIBUTE:
237: return "ATTRIBUTE";
238: case CDATA:
239: return "CDATA";
240: case CHARACTERS:
241: return "CHARACTERS";
242: case COMMENT:
243: return "COMMENT";
244: case DTD:
245: return "DTD";
246: case END_DOCUMENT:
247: return "END_DOCUMENT";
248: case END_ELEMENT:
249: return "END_ELEMENT";
250: case ENTITY_DECLARATION:
251: return "ENTITY_DECLARATION";
252: case ENTITY_REFERENCE:
253: return "ENTITY_REFERENCE";
254: case NAMESPACE:
255: return "NAMESPACE";
256: case NOTATION_DECLARATION:
257: return "NOTATION_DECLARATION";
258: case PROCESSING_INSTRUCTION:
259: return "PROCESSING_INSTRUCTION";
260: case SPACE:
261: return "SPACE";
262: case START_DOCUMENT:
263: return "START_DOCUMENT";
264: case START_ELEMENT:
265: return "START_ELEMENT";
266: default:
267: return "UNKNOWN";
268: }
269: }
270:
271: private static XMLStreamReaderException wrapException(
272: XMLStreamException e) {
273: return new XMLStreamReaderException("xmlreader.ioException", e);
274: }
275:
276: // -- Auxiliary classes ----------------------------------------------
277:
278: /**
279: * AttributesImpl class copied from old StAXReader. This class is used to implement
280: * getAttributes() on a StAX Reader.
281: */
282: public static class AttributesImpl implements Attributes {
283:
284: static final String XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";
285:
286: static class AttributeInfo {
287:
288: private QName name;
289: private String value;
290:
291: public AttributeInfo(QName name, String value) {
292: this .name = name;
293: if (value == null) {
294: // e.g., <return xmlns=""> -- stax returns null
295: this .value = "";
296: } else {
297: this .value = value;
298: }
299: }
300:
301: QName getName() {
302: return name;
303: }
304:
305: String getValue() {
306: return value;
307: }
308:
309: /*
310: * Return "xmlns:" as part of name if namespace.
311: */
312: String getLocalName() {
313: if (isNamespaceDeclaration()) {
314: if (name.getLocalPart().equals("")) {
315: return "xmlns";
316: }
317: return "xmlns:" + name.getLocalPart();
318: }
319: return name.getLocalPart();
320: }
321:
322: boolean isNamespaceDeclaration() {
323: return (name.getNamespaceURI() == XMLNS_NAMESPACE_URI);
324: }
325: }
326:
327: // stores qname and value for each attribute
328: AttributeInfo[] atInfos;
329:
330: /*
331: * Will create a list that contains the namespace declarations
332: * as well as the other attributes.
333: */
334: public AttributesImpl(XMLStreamReader reader) {
335: if (reader == null) {
336:
337: // this is the case when we call getAttributes() on the
338: // reader when it is not on a start tag
339: atInfos = new AttributeInfo[0];
340: } else {
341:
342: // this is the normal case
343: int index = 0;
344: int namespaceCount = reader.getNamespaceCount();
345: int attributeCount = reader.getAttributeCount();
346: atInfos = new AttributeInfo[namespaceCount
347: + attributeCount];
348: for (int i = 0; i < namespaceCount; i++) {
349: String namespacePrefix = reader
350: .getNamespacePrefix(i);
351:
352: // will be null if default prefix. QName can't take null
353: if (namespacePrefix == null) {
354: namespacePrefix = "";
355: }
356: atInfos[index++] = new AttributeInfo(new QName(
357: XMLNS_NAMESPACE_URI, namespacePrefix,
358: "xmlns"), reader.getNamespaceURI(i));
359: }
360: for (int i = 0; i < attributeCount; i++) {
361: atInfos[index++] = new AttributeInfo(reader
362: .getAttributeName(i), reader
363: .getAttributeValue(i));
364: }
365: }
366: }
367:
368: public int getLength() {
369: return atInfos.length;
370: }
371:
372: public String getLocalName(int index) {
373: if (index >= 0 && index < atInfos.length) {
374: return atInfos[index].getLocalName();
375: }
376: return null;
377: }
378:
379: public QName getName(int index) {
380: if (index >= 0 && index < atInfos.length) {
381: return atInfos[index].getName();
382: }
383: return null;
384: }
385:
386: public String getPrefix(int index) {
387: if (index >= 0 && index < atInfos.length) {
388: return atInfos[index].getName().getPrefix();
389: }
390: return null;
391: }
392:
393: public String getURI(int index) {
394: if (index >= 0 && index < atInfos.length) {
395: return atInfos[index].getName().getNamespaceURI();
396: }
397: return null;
398: }
399:
400: public String getValue(int index) {
401: if (index >= 0 && index < atInfos.length) {
402: return atInfos[index].getValue();
403: }
404: return null;
405: }
406:
407: public String getValue(QName name) {
408: int index = getIndex(name);
409: if (index != -1) {
410: return atInfos[index].getValue();
411: }
412: return null;
413: }
414:
415: public String getValue(String localName) {
416: int index = getIndex(localName);
417: if (index != -1) {
418: return atInfos[index].getValue();
419: }
420: return null;
421: }
422:
423: public String getValue(String uri, String localName) {
424: int index = getIndex(uri, localName);
425: if (index != -1) {
426: return atInfos[index].getValue();
427: }
428: return null;
429: }
430:
431: public boolean isNamespaceDeclaration(int index) {
432: if (index >= 0 && index < atInfos.length) {
433: return atInfos[index].isNamespaceDeclaration();
434: }
435: return false;
436: }
437:
438: public int getIndex(QName name) {
439: for (int i = 0; i < atInfos.length; i++) {
440: if (atInfos[i].getName().equals(name)) {
441: return i;
442: }
443: }
444: return -1;
445: }
446:
447: public int getIndex(String localName) {
448: for (int i = 0; i < atInfos.length; i++) {
449: if (atInfos[i].getName().getLocalPart().equals(
450: localName)) {
451: return i;
452: }
453: }
454: return -1;
455: }
456:
457: public int getIndex(String uri, String localName) {
458: QName qName;
459: for (int i = 0; i < atInfos.length; i++) {
460: qName = atInfos[i].getName();
461: if (qName.getNamespaceURI().equals(uri)
462: && qName.getLocalPart().equals(localName)) {
463:
464: return i;
465: }
466: }
467: return -1;
468: }
469: }
470: }
|