001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.databinding.utils;
020:
021: import javax.xml.namespace.QName;
022: import javax.xml.stream.XMLStreamConstants;
023: import javax.xml.stream.XMLStreamException;
024: import javax.xml.stream.XMLStreamReader;
025:
026: /**
027: * A state machine to read elements with simple content. Returns the text of the element and the
028: * stream reader will be one event beyond the end element at return
029: */
030: public class SimpleElementReaderStateMachine implements States,
031: Constants {
032:
033: private QName elementNameToTest = null;
034: private int currentState = INIT_STATE;
035: private boolean nillable = false;
036: private String text = "";
037: private String errorMessage = "";
038: private boolean elementSkipped = false;
039:
040: public boolean isElementSkipped() {
041: return elementSkipped;
042: }
043:
044: /**
045: *
046: */
047: public String getText() {
048: return text;
049: }
050:
051: /** sets the nillable flag */
052: public void setNillable() {
053: nillable = true;
054: }
055:
056: /**
057: * the Qname of the element to be tested
058: *
059: * @param elementNameToTest
060: */
061: public void setElementNameToTest(QName elementNameToTest) {
062: this .elementNameToTest = elementNameToTest;
063:
064: }
065:
066: /**
067: * Resets the state machine. Once the reset is called the state machine is good enough for a
068: * fresh run
069: */
070: public void reset() {
071: elementNameToTest = null;
072: currentState = INIT_STATE;
073: nillable = false;
074: text = "";
075: errorMessage = "";
076: }
077:
078: /**
079: * public read method - reads a given reader to extract the text value
080: *
081: * @param reader
082: */
083: public void read(XMLStreamReader reader) throws XMLStreamException {
084:
085: do {
086: updateState(reader);
087:
088: //test for the nillable attribute
089: if (currentState == START_ELEMENT_FOUND_STATE && nillable) {
090: if (TRUE.equals(reader.getAttributeValue(XSI_NAMESPACE,
091: NIL))) {
092: text = null;
093: //force the state to be null found
094: currentState = NULLED_STATE;
095: }
096: }
097:
098: if (currentState == TEXT_FOUND_STATE) {
099: //read the text value and store it
100: text = reader.getText();
101: }
102: if (currentState != FINISHED_STATE
103: && currentState != ILLEGAL_STATE) {
104: reader.next();
105: }
106:
107: } while (currentState != FINISHED_STATE
108: && currentState != ILLEGAL_STATE);
109:
110: if (currentState == ILLEGAL_STATE) {
111: throw new RuntimeException("Illegal state!" + errorMessage);
112: }
113:
114: }
115:
116: /**
117: * Updates the state depending on the parser
118: *
119: * @param reader
120: */
121: private void updateState(XMLStreamReader reader)
122: throws XMLStreamException {
123: int event = reader.getEventType();
124:
125: switch (currentState) {
126: case INIT_STATE:
127: if (event == XMLStreamConstants.START_DOCUMENT) {
128: currentState = STARTED_STATE;
129: //start element found at init
130: } else if (event == XMLStreamConstants.START_ELEMENT) {
131: if (elementNameToTest.equals(reader.getName())) {
132: currentState = START_ELEMENT_FOUND_STATE;
133: } else {
134: currentState = STARTED_STATE;
135: }
136: } else if (event == XMLStreamConstants.END_ELEMENT) {
137: // an end element is found at the init state
138: // we should break the process here ?
139: currentState = FINISHED_STATE;
140: elementSkipped = true;
141: }
142: break;
143:
144: case STARTED_STATE:
145: if (event == XMLStreamConstants.START_ELEMENT) {
146: if (elementNameToTest.equals(reader.getName())) {
147: currentState = START_ELEMENT_FOUND_STATE;
148: }
149: }
150: break;
151:
152: case START_ELEMENT_FOUND_STATE:
153: if (event == XMLStreamConstants.CHARACTERS) {
154: currentState = TEXT_FOUND_STATE;
155: } else if (event == XMLStreamConstants.END_ELEMENT) {
156: //force the text to be empty!
157: text = "";
158: if (elementNameToTest.equals(reader.getName())) {
159: currentState = END_ELEMENT_FOUND_STATE;
160: } else {
161: currentState = ILLEGAL_STATE;
162: errorMessage = "Wrong element name "
163: + reader.getName(); //todo I18n this
164: }
165: }
166: break;
167:
168: case TEXT_FOUND_STATE:
169: if (event == XMLStreamConstants.END_ELEMENT) {
170: if (elementNameToTest.equals(reader.getName())) {
171: currentState = END_ELEMENT_FOUND_STATE;
172: } else {
173: currentState = ILLEGAL_STATE;
174: //set the error message
175: errorMessage = "Wrong element name "
176: + reader.getName(); //todo I18n this
177: }
178: } else if (event == XMLStreamConstants.CHARACTERS) {
179: text = text + reader.getText(); //append the text
180: //do not change the state
181: }
182: break;
183:
184: case END_ELEMENT_FOUND_STATE:
185: currentState = FINISHED_STATE;
186: break;
187:
188: //the element was found to be null and this state was forced.
189: //we are sure here that the parser was at the
190: //START_ELEMENT_FOUND_STATE before
191: //being forced. Hence we need to advance the parser upto the
192: // end element and set the state to be end element found
193: case NULLED_STATE:
194: while (event != XMLStreamConstants.END_ELEMENT) {
195: event = reader.next();
196: }
197: currentState = END_ELEMENT_FOUND_STATE;
198: break;
199:
200: default:
201: if (event == XMLStreamConstants.CHARACTERS) {
202: if (reader.getText().trim().length() == 0) {
203: //the text is empty - don't change the state
204: } else {
205: //we do NOT handle mixed content
206: currentState = ILLEGAL_STATE;
207: errorMessage = "Mixed Content " + reader.getText();
208: }
209: } else {
210: currentState = ILLEGAL_STATE;
211: errorMessage = "Current state is " + currentState;
212: }
213: break;
214: }
215:
216: }
217:
218: }
|