blob: 67009026a49b4d97a16b83294c4fc18e14cc2315 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.axis2.json.moshi;
import com.squareup.moshi.JsonReader;
import static com.squareup.moshi.JsonReader.Token.NULL;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.json.factory.JSONType;
import org.apache.axis2.json.factory.JsonConstant;
import org.apache.axis2.json.factory.JsonObject;
import org.apache.axis2.json.factory.XmlNode;
import org.apache.axis2.json.factory.XmlNodeGenerator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.commons.schema.XmlSchema;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.Stack;
public class MoshiXMLStreamReader implements XMLStreamReader {
private static final Log log = LogFactory.getLog(MoshiXMLStreamReader.class);
private JsonReader jsonReader;
private JsonState state = JsonState.StartState;
private JsonReader.Token tokenType;
private String localName;
private String value;
private boolean isProcessed;
private ConfigurationContext configContext;
private QName elementQname;
private XmlNode mainXmlNode;
private List<XmlSchema> xmlSchemaList;
private Queue<JsonObject> queue = new LinkedList<JsonObject>();
private XmlNodeGenerator xmlNodeGenerator;
private Stack<JsonObject> stackObj = new Stack<JsonObject>();
private Stack<JsonObject> miniStack = new Stack<JsonObject>();
private JsonObject topNestedArrayObj = null;
private Stack<JsonObject> processedJsonObject = new Stack<JsonObject>();
private String namespace;
public MoshiXMLStreamReader(JsonReader jsonReader) {
this.jsonReader = jsonReader;
}
public MoshiXMLStreamReader(JsonReader jsonReader, QName elementQname, List<XmlSchema> xmlSchemaList,
ConfigurationContext configContext) throws AxisFault {
this.jsonReader = jsonReader;
initXmlStreamReader(elementQname, xmlSchemaList, configContext);
}
public JsonReader getJsonReader() {
return jsonReader;
}
public void initXmlStreamReader(QName elementQname, List<XmlSchema> xmlSchemaList, ConfigurationContext configContext) throws AxisFault {
this.elementQname = elementQname;
this.xmlSchemaList = xmlSchemaList;
this.configContext = configContext;
try {
process();
} catch (AxisFault axisFault) {
throw new AxisFault("Error while initializing XMLStreamReader ", axisFault);
}
isProcessed = true;
}
private void process() throws AxisFault {
Object ob = configContext.getProperty(JsonConstant.XMLNODES);
if (ob != null) {
Map<QName, XmlNode> nodeMap = (Map<QName, XmlNode>) ob;
XmlNode requesNode = nodeMap.get(elementQname);
if (requesNode != null) {
xmlNodeGenerator = new XmlNodeGenerator();
queue = xmlNodeGenerator.getQueue(requesNode);
} else {
xmlNodeGenerator = new XmlNodeGenerator(xmlSchemaList, elementQname);
mainXmlNode = xmlNodeGenerator.getMainXmlNode();
queue = xmlNodeGenerator.getQueue(mainXmlNode);
nodeMap.put(elementQname, mainXmlNode);
configContext.setProperty(JsonConstant.XMLNODES, nodeMap);
}
} else {
Map<QName, XmlNode> newNodeMap = new HashMap<QName, XmlNode>();
xmlNodeGenerator = new XmlNodeGenerator(xmlSchemaList, elementQname);
mainXmlNode = xmlNodeGenerator.getMainXmlNode();
queue = xmlNodeGenerator.getQueue(mainXmlNode);
newNodeMap.put(elementQname, mainXmlNode);
configContext.setProperty(JsonConstant.XMLNODES, newNodeMap);
}
isProcessed = true;
log.debug("MoshiXMLStreamReader.process() completed");
}
public Object getProperty(String name) throws IllegalArgumentException {
return null;
}
public int next() throws XMLStreamException {
if (hasNext()) {
try {
stateTransition();
} catch (IOException e) {
throw new XMLStreamException("I/O error while reading JSON input Stream");
}
return getEventType();
} else {
throw new NoSuchElementException("There is no any next event");
}
}
public void require(int type, String namespaceURI, String localName) throws XMLStreamException {
throw new UnsupportedOperationException("Method is not implemented");
}
public String getElementText() throws XMLStreamException {
throw new UnsupportedOperationException("Method is not implemented");
}
public int nextTag() throws XMLStreamException {
throw new UnsupportedOperationException("Method is not implemented");
}
public boolean hasNext() throws XMLStreamException {
try {
tokenType = jsonReader.peek();
return !(tokenType == JsonReader.Token.END_DOCUMENT);
} catch (IOException e) {
throw new XMLStreamException("Unexpected end of json stream");
}
}
public void close() throws XMLStreamException {
throw new UnsupportedOperationException("Method is not implemented");
}
public String getNamespaceURI(String prefix) {
if (isStartElement() || isEndElement()) {
return namespace;
} else {
return null;
}
}
public boolean isStartElement() {
return (state == JsonState.NameName
|| state == JsonState.NameValue
|| state == JsonState.ValueValue_CHAR
|| state == JsonState.EndObjectBeginObject_START);
}
public boolean isEndElement() {
return (state == JsonState.ValueValue_START
|| state == JsonState.EndArrayName
|| state == JsonState.ValueEndObject_END_2
|| state == JsonState.ValueName_START
|| state == JsonState.EndObjectName
|| state == JsonState.EndObjectBeginObject_END
|| state == JsonState.EndArrayEndObject
|| state == JsonState.EndObjectEndObject);
}
public boolean isCharacters() {
return (state == JsonState.ValueValue_END
|| state == JsonState.ValueEndArray
|| state == JsonState.ValueEndObject_END_1
|| state == JsonState.ValueName_END);
}
public boolean isWhiteSpace() {
return false;
}
public String getAttributeValue(String namespaceURI, String localName) {
throw new UnsupportedOperationException("Method is not implemented");
}
public int getAttributeCount() {
if (isStartElement()) {
return 0; // don't support attributes on tags in JSON convention
} else {
throw new IllegalStateException("Only valid on START_ELEMENT state");
}
}
public QName getAttributeName(int index) {
throw new UnsupportedOperationException("Method is not implemented");
}
public String getAttributeNamespace(int index) {
throw new UnsupportedOperationException("Method is not implemented");
}
public String getAttributeLocalName(int index) {
throw new UnsupportedOperationException("Method is not implemented");
}
public String getAttributePrefix(int index) {
throw new UnsupportedOperationException("Method is not implemented");
}
public String getAttributeType(int index) {
throw new UnsupportedOperationException("Method is not implemented");
}
public String getAttributeValue(int index) {
throw new UnsupportedOperationException("Method is not implemented");
}
public boolean isAttributeSpecified(int index) {
throw new UnsupportedOperationException("Method is not implemented");
}
public int getNamespaceCount() {
if (isStartElement() || isEndElement()) {
return 1; // we have one default namesapce
} else {
throw new IllegalStateException("only valid on a START_ELEMENT or END_ELEMENT state");
}
}
public String getNamespacePrefix(int index) {
if (isStartElement() || isEndElement()) {
return null;
} else {
throw new IllegalStateException("only valid on a START_ELEMENT or END_ELEMENT state");
}
}
public String getNamespaceURI(int index) {
if (isStartElement() || isEndElement()) {
return namespace;
} else {
throw new IllegalStateException("only valid on a START_ELEMENT or END_ELEMENT state");
}
}
public NamespaceContext getNamespaceContext() {
throw new UnsupportedOperationException("Method is not implemented");
}
public int getEventType() {
if (state == JsonState.StartState) {
return START_DOCUMENT;
} else if (isStartElement()) {
return START_ELEMENT;
} else if (isCharacters()) {
return CHARACTERS;
} else if (isEndElement()) {
return END_ELEMENT;
} else if (state == JsonState.EndObjectEndDocument) {
return END_DOCUMENT;
} else {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
}
public String getText() {
if (isCharacters()) {
return value;
} else {
return null;
}
}
public char[] getTextCharacters() {
if (isCharacters()) {
if (value == null) {
return new char[0];
} else {
return value.toCharArray();
}
} else {
throw new IllegalStateException("This is not a valid state");
}
}
public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException {
throw new UnsupportedOperationException("Method is not implemented");
}
public int getTextStart() {
throw new UnsupportedOperationException("Method is not implemented");
}
public int getTextLength() {
throw new UnsupportedOperationException("Method is not implemented");
}
public String getEncoding() {
return null;
}
public boolean hasText() {
return isCharacters();
}
public Location getLocation() {
return new Location() { // Location is unKnown
public int getLineNumber() {
return -1;
}
public int getColumnNumber() {
return -1;
}
public int getCharacterOffset() {
return 0;
}
public String getPublicId() {
return null;
}
public String getSystemId() {
return null;
}
};
}
public QName getName() {
if (isStartElement() || isEndElement()) {
return new QName(namespace, localName);
} else {
throw new IllegalStateException("getName method is valid only for the START_ELEMENT or END_ELEMENT event");
}
}
public String getLocalName() {
int i = getEventType();
if (i == XMLStreamReader.START_ELEMENT || i == XMLStreamReader.END_ELEMENT) {
return localName;
} else {
throw new IllegalStateException("To get local name state should be START_ELEMENT or END_ELEMENT");
}
}
public boolean hasName() {
return (isStartElement() || isEndElement());
}
public String getNamespaceURI() {
if (isStartElement() || isEndElement()) {
return namespace;
} else {
return null;
}
}
public String getPrefix() {
return null;
}
public String getVersion() {
return null;
}
public boolean isStandalone() {
return false;
}
public boolean standaloneSet() {
return false;
}
public String getCharacterEncodingScheme() {
return null;
}
public String getPITarget() {
throw new UnsupportedOperationException("Method is not implemented");
}
public String getPIData() {
throw new UnsupportedOperationException("Method is not implemented");
}
private void stateTransition() throws XMLStreamException, IOException {
if (state == JsonState.StartState) {
beginObject();
JsonObject topElement = new JsonObject("StackTopElement", JSONType.NESTED_OBJECT,
null, "http://axis2.apache.org/axis/json");
stackObj.push(topElement);
readName();
} else if (state == JsonState.NameName) {
readName();
} else if (state == JsonState.NameValue) {
readValue();
} else if (state == JsonState.ValueEndObject_END_1) {
state = JsonState.ValueEndObject_END_2;
removeStackObj();
} else if (state == JsonState.ValueEndObject_END_2) {
readEndObject();
} else if (state == JsonState.ValueName_END) {
state = JsonState.ValueName_START;
removeStackObj();
} else if (state == JsonState.ValueName_START) {
readName();
} else if (state == JsonState.ValueValue_END) {
state = JsonState.ValueValue_START;
} else if (state == JsonState.ValueValue_START) {
value = null;
state = JsonState.ValueValue_CHAR;
} else if (state == JsonState.ValueValue_CHAR) {
readValue();
} else if (state == JsonState.ValueEndArray) {
readEndArray();
removeStackObj();
} else if (state == JsonState.EndArrayName) {
readName();
} else if (state == JsonState.EndObjectEndObject) {
readEndObject();
} else if (state == JsonState.EndObjectName) {
readName();
} else if (state == JsonState.EndObjectBeginObject_END) {
state = JsonState.EndObjectBeginObject_START;
fillMiniStack();
} else if (state == JsonState.EndObjectBeginObject_START) {
readBeginObject();
} else if (state == JsonState.EndArrayEndObject) {
readEndObject();
}
}
private void removeStackObj() throws XMLStreamException {
if (!stackObj.empty()) {
if (topNestedArrayObj == null) {
stackObj.pop();
} else {
if (stackObj.peek().equals(topNestedArrayObj)) {
topNestedArrayObj = null;
processedJsonObject.clear();
stackObj.pop();
} else {
processedJsonObject.push(stackObj.pop());
}
}
if (!stackObj.empty()) {
localName = stackObj.peek().getName();
} else {
localName = "";
}
} else {
System.out.println("stackObj is empty");
throw new XMLStreamException("Error while processing input JSON stream, JSON request may not valid ," +
" it may has more end object characters ");
}
}
private void fillMiniStack() {
miniStack.clear();
JsonObject nestedArray = stackObj.peek();
while (!processedJsonObject.peek().equals(nestedArray)) {
miniStack.push(processedJsonObject.pop());
}
}
private void readName() throws IOException, XMLStreamException {
nextName();
tokenType = jsonReader.peek();
if (tokenType == JsonReader.Token.BEGIN_OBJECT) {
beginObject();
state = JsonState.NameName;
} else if (tokenType == JsonReader.Token.BEGIN_ARRAY) {
beginArray();
tokenType = jsonReader.peek();
if (tokenType == JsonReader.Token.BEGIN_OBJECT) {
beginObject();
state = JsonState.NameName;
} else {
state = JsonState.NameValue;
}
} else if (tokenType == JsonReader.Token.STRING || tokenType == JsonReader.Token.NUMBER || tokenType == JsonReader.Token.BOOLEAN
|| tokenType == JsonReader.Token.NULL) {
state = JsonState.NameValue;
}
}
private void readValue() throws IOException {
nextValue();
tokenType = jsonReader.peek();
if (tokenType == JsonReader.Token.NAME) {
state = JsonState.ValueName_END;
} else if (tokenType == JsonReader.Token.STRING || tokenType == JsonReader.Token.NUMBER || tokenType == JsonReader.Token.BOOLEAN
|| tokenType == JsonReader.Token.NULL) {
state = JsonState.ValueValue_END;
} else if (tokenType == JsonReader.Token.END_ARRAY) {
state = JsonState.ValueEndArray;
} else if (tokenType == JsonReader.Token.END_OBJECT) {
state = JsonState.ValueEndObject_END_1;
}
}
private void readBeginObject() throws IOException, XMLStreamException {
beginObject();
readName();
}
private void readEndObject() throws IOException, XMLStreamException {
endObject();
tokenType = jsonReader.peek();
if (tokenType == JsonReader.Token.END_OBJECT) {
removeStackObj();
state = JsonState.EndObjectEndObject;
} else if (tokenType == JsonReader.Token.END_ARRAY) {
readEndArray();
removeStackObj();
} else if (tokenType == JsonReader.Token.NAME) {
removeStackObj();
state = JsonState.EndObjectName;
} else if (tokenType == JsonReader.Token.BEGIN_OBJECT) {
state = JsonState.EndObjectBeginObject_END;
} else if (tokenType == JsonReader.Token.END_DOCUMENT) {
removeStackObj();
state = JsonState.EndObjectEndDocument;
}
}
private void readEndArray() throws IOException {
endArray();
tokenType = jsonReader.peek();
if (tokenType == JsonReader.Token.END_OBJECT) {
state = JsonState.EndArrayEndObject;
} else if (tokenType == JsonReader.Token.NAME) {
state = JsonState.EndArrayName;
}
}
private void nextName() throws IOException, XMLStreamException {
String name = jsonReader.nextName();
if (!miniStack.empty()) {
JsonObject jsonObj = miniStack.peek();
if (jsonObj.getName().equals(name)) {
namespace = jsonObj.getNamespaceUri();
stackObj.push(miniStack.pop());
} else {
throw new XMLStreamException(JsonConstant.IN_JSON_MESSAGE_NOT_VALID + "expected : " + jsonObj.getName() + " but found : " + name);
}
} else if (!queue.isEmpty()) {
JsonObject jsonObj = queue.peek();
if (jsonObj.getName().equals(name)) {
namespace = jsonObj.getNamespaceUri();
stackObj.push(queue.poll());
} else {
throw new XMLStreamException(JsonConstant.IN_JSON_MESSAGE_NOT_VALID + "expected : " + jsonObj.getName() + " but found : " + name);
}
} else {
throw new XMLStreamException(JsonConstant.IN_JSON_MESSAGE_NOT_VALID);
}
localName = stackObj.peek().getName();
value = null;
}
private String nextValue() {
try {
tokenType = jsonReader.peek();
if (tokenType == JsonReader.Token.STRING) {
value = jsonReader.nextString();
} else if (tokenType == JsonReader.Token.BOOLEAN) {
value = String.valueOf(jsonReader.nextBoolean());
} else if (tokenType == JsonReader.Token.NUMBER) {
JsonObject peek = stackObj.peek();
String valueType = peek.getValueType();
if (valueType.equals("int")) {
value = String.valueOf(jsonReader.nextInt());
} else if (valueType.equals("long")) {
value = String.valueOf(jsonReader.nextLong());
} else if (valueType.equals("double")) {
value = String.valueOf(jsonReader.nextDouble());
} else if (valueType.equals("float")) {
value = String.valueOf(jsonReader.nextDouble());
}
} else if (tokenType == JsonReader.Token.NULL) {
jsonReader.nextNull();
value = null;
} else {
log.error("Couldn't read the value, Illegal state exception");
throw new RuntimeException("Couldn't read the value, Illegal state exception");
}
} catch (IOException e) {
log.error("IO error while reading json stream");
throw new RuntimeException("IO error while reading json stream");
}
return value;
}
private void beginObject() throws IOException {
jsonReader.beginObject();
}
private void beginArray() throws IOException {
jsonReader.beginArray();
if (stackObj.peek().getType() == JSONType.NESTED_ARRAY) {
if (topNestedArrayObj == null) {
topNestedArrayObj = stackObj.peek();
}
processedJsonObject.push(stackObj.peek());
}
}
private void endObject() throws IOException {
jsonReader.endObject();
}
private void endArray() throws IOException {
jsonReader.endArray();
if (stackObj.peek().equals(topNestedArrayObj)) {
topNestedArrayObj = null;
}
}
public boolean isProcessed() {
return isProcessed;
}
public enum JsonState {
StartState,
NameValue,
NameName,
ValueValue_END,
ValueValue_START,
ValueValue_CHAR,
ValueEndArray,
ValueEndObject_END_1,
ValueEndObject_END_2,
ValueName_END,
ValueName_START,
EndObjectEndObject,
EndObjectName,
EndArrayName,
EndArrayEndObject,
EndObjectBeginObject_END,
EndObjectBeginObject_START,
EndObjectEndDocument,
}
}