org.apache.axis2.json.gson.GsonXMLStreamReader.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.axis2.json.gson.GsonXMLStreamReader.java

Source

/*
 * 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.gson;

import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.json.gson.factory.JSONType;
import org.apache.axis2.json.gson.factory.JsonConstant;
import org.apache.axis2.json.gson.factory.JsonObject;
import org.apache.axis2.json.gson.factory.XmlNode;
import org.apache.axis2.json.gson.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.Stack;

public class GsonXMLStreamReader implements XMLStreamReader {

    private static final Log log = LogFactory.getLog(GsonXMLStreamReader.class);

    private JsonReader jsonReader;

    private JsonState state = JsonState.StartState;

    private JsonToken tokenType;

    private String localName;

    private String value;

    private boolean isProcessed;

    private ConfigurationContext configContext;

    private QName elementQname;

    private XmlNode mainXmlNode;

    private List<XmlSchema> xmlSchemaList;

    private List<JsonObject> schemaList = new LinkedList<JsonObject>();
    private boolean skipSchemaListElement = false;
    private int schemaListPointer = 0;

    private List<JsonObject> miniList = new LinkedList<JsonObject>();
    private boolean skipMiniListElement = false;
    private int miniListPointer = 0;

    private XmlNodeGenerator xmlNodeGenerator;

    private Stack<JsonObject> stackObj = new Stack<JsonObject>();
    private JsonObject topNestedArrayObj = null;
    private Stack<JsonObject> processedJsonObject = new Stack<JsonObject>();

    private String namespace;

    public GsonXMLStreamReader(JsonReader jsonReader) {
        this.jsonReader = jsonReader;
    }

    public GsonXMLStreamReader(JsonReader jsonReader, QName elementQname, List<XmlSchema> xmlSchemaList,
            ConfigurationContext configContext) {
        this.jsonReader = jsonReader;
        initXmlStreamReader(elementQname, xmlSchemaList, configContext);
    }

    public JsonReader getJsonReader() {
        return jsonReader;
    }

    public void initXmlStreamReader(QName elementQname, List<XmlSchema> xmlSchemaList,
            ConfigurationContext configContext) {
        processSchemaUpdates(elementQname, xmlSchemaList, configContext);
        this.elementQname = elementQname;
        this.xmlSchemaList = xmlSchemaList;
        this.configContext = configContext;
        process();
        isProcessed = true;

    }

    private void processSchemaUpdates(QName elementQname, List<XmlSchema> xmlSchemaList,
            ConfigurationContext configContext) {
        Object ob = configContext.getProperty(JsonConstant.CURRENT_XML_SCHEMA);
        if (ob != null) {
            Map<QName, XmlSchema> schemaMap = (Map<QName, XmlSchema>) ob;
            if (schemaMap != null) {
                XmlSchema currentXmlSchema = schemaMap.get(elementQname);
                for (XmlSchema xmlSchema : xmlSchemaList) {
                    if (xmlSchema.getTargetNamespace().equals(elementQname.getNamespaceURI())) {
                        if (currentXmlSchema != xmlSchema) {
                            schemaMap.put(elementQname, xmlSchema);
                            configContext.setProperty(JsonConstant.XMLNODES, null);
                            if (log.isDebugEnabled()) {
                                log.debug("Updating message schema. [Current:" + currentXmlSchema + ", New:"
                                        + xmlSchema + "]");
                            }
                        }
                        break;
                    }
                }
            }
        } else {
            Map<QName, XmlSchema> schemaMap = new HashMap<QName, XmlSchema>();
            for (XmlSchema xmlSchema : xmlSchemaList) {
                if (xmlSchema.getTargetNamespace().equals(elementQname.getNamespaceURI())) {
                    schemaMap.put(elementQname, xmlSchema);
                    configContext.setProperty(JsonConstant.CURRENT_XML_SCHEMA, schemaMap);
                    break;
                }
            }
        }
    }

    private void process() {
        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();
                schemaList = xmlNodeGenerator.getSchemaList(requesNode);
            } else {
                xmlNodeGenerator = new XmlNodeGenerator(xmlSchemaList, elementQname);
                mainXmlNode = xmlNodeGenerator.getMainXmlNode();
                schemaList = xmlNodeGenerator.getSchemaList(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();
            schemaList = xmlNodeGenerator.getSchemaList(mainXmlNode);
            newNodeMap.put(elementQname, mainXmlNode);
            configContext.setProperty(JsonConstant.XMLNODES, newNodeMap);
        }
        isProcessed = true;
    }

    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();
            if (tokenType == JsonToken.END_DOCUMENT) {
                return false;
            } else {
                return true;
            }
        } 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() {
        if (state == JsonState.NameName || state == JsonState.NameValue || state == JsonState.ValueValue_CHAR
                || state == JsonState.EndObjectBeginObject_START) {
            return true;
        } else {
            return false;
        }
    }

    public boolean isEndElement() {
        if (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) {
            return true;
        } else {
            return false;
        }
    }

    public boolean isCharacters() {
        if (state == JsonState.ValueValue_END || state == JsonState.ValueEndArray
                || state == JsonState.ValueEndObject_END_1 || state == JsonState.ValueName_END) {
            return true;
        } else {
            return false;
        }

    }

    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; //To change body of implemented methods use File | Settings | File Templates.
            }

            public String getPublicId() {
                return null; //To change body of implemented methods use File | Settings | File Templates.
            }

            public String getSystemId() {
                return null; //To change body of implemented methods use File | Settings | File Templates.
            }
        };
    }

    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;
            fillMiniList();
        } 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 fillMiniList() {
        miniList.clear();
        skipMiniListElement = false;
        JsonObject nestedArray = stackObj.peek();
        while (!processedJsonObject.peek().equals(nestedArray)) {
            miniList.add(0, processedJsonObject.pop());
        }
    }

    private void readName() throws IOException, XMLStreamException {
        nextName();
        tokenType = jsonReader.peek();
        if (tokenType == JsonToken.BEGIN_OBJECT) {
            beginObject();
            state = JsonState.NameName;
        } else if (tokenType == JsonToken.BEGIN_ARRAY) {
            beginArray();
            tokenType = jsonReader.peek();
            if (tokenType == JsonToken.BEGIN_OBJECT) {
                beginObject();
                state = JsonState.NameName;
            } else {
                state = JsonState.NameValue;
            }
        } else if (tokenType == JsonToken.STRING || tokenType == JsonToken.NUMBER || tokenType == JsonToken.BOOLEAN
                || tokenType == JsonToken.NULL) {
            state = JsonState.NameValue;
        }
    }

    private void readValue() throws IOException {
        nextValue();
        tokenType = jsonReader.peek();
        if (tokenType == JsonToken.NAME) {
            state = JsonState.ValueName_END;
        } else if (tokenType == JsonToken.STRING || tokenType == JsonToken.NUMBER || tokenType == JsonToken.BOOLEAN
                || tokenType == JsonToken.NULL) {
            state = JsonState.ValueValue_END;
        } else if (tokenType == JsonToken.END_ARRAY) {
            state = JsonState.ValueEndArray;
        } else if (tokenType == JsonToken.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 == JsonToken.END_OBJECT) {
            removeStackObj();
            state = JsonState.EndObjectEndObject;
        } else if (tokenType == JsonToken.END_ARRAY) {
            readEndArray();
            removeStackObj();
        } else if (tokenType == JsonToken.NAME) {
            removeStackObj();
            state = JsonState.EndObjectName;
        } else if (tokenType == JsonToken.BEGIN_OBJECT) {
            state = JsonState.EndObjectBeginObject_END;
        } else if (tokenType == JsonToken.END_DOCUMENT) {
            removeStackObj();
            state = JsonState.EndObjectEndDocument;
        }
    }

    private void readEndArray() throws IOException {
        endArray();
        tokenType = jsonReader.peek();
        if (tokenType == JsonToken.END_OBJECT) {
            state = JsonState.EndArrayEndObject;
        } else if (tokenType == JsonToken.NAME) {
            state = JsonState.EndArrayName;
        }
    }

    private void nextName() throws IOException, XMLStreamException {
        String name = jsonReader.nextName();
        boolean isElementExists = false;
        if (!miniList.isEmpty()) {
            while (!isElementExists && (miniListPointer < miniList.size() || skipMiniListElement)) {
                if (miniListPointer >= miniList.size()) {
                    skipMiniListElement = false;
                    miniListPointer = 0;
                }
                JsonObject jsonObject = miniList.get(miniListPointer);
                if (jsonObject.getName().equals(name)) {
                    isElementExists = true;
                    namespace = jsonObject.getNamespaceUri();
                    stackObj.push(jsonObject);
                    miniList.remove(miniListPointer);
                    if (miniListPointer > 0)
                        skipMiniListElement = true;
                } else {
                    ++miniListPointer;
                }
                if (miniListPointer > miniList.size() && isElementExists) {
                    throw new XMLStreamException(
                            JsonConstant.IN_JSON_MESSAGE_NOT_VALID + name + " does not exist in schema");
                }
            }
        } else {
            if (!schemaList.isEmpty()) {
                while (!isElementExists && (schemaListPointer < schemaList.size() || skipSchemaListElement)) {
                    if (schemaListPointer >= schemaList.size()) {
                        skipSchemaListElement = false;
                        schemaListPointer = 0;
                    }
                    JsonObject jsonObject = schemaList.get(schemaListPointer);
                    if (jsonObject.getName().equals(name)) {
                        isElementExists = true;
                        namespace = jsonObject.getNamespaceUri();
                        stackObj.push(jsonObject);
                        schemaList.remove(schemaListPointer);
                        if (schemaListPointer > 0)
                            skipSchemaListElement = true;
                    } else {
                        ++schemaListPointer;
                    }
                }
                if (schemaListPointer > schemaList.size() && !isElementExists) {
                    throw new XMLStreamException(
                            JsonConstant.IN_JSON_MESSAGE_NOT_VALID + name + " does not exist in schema");
                }
            }
        }
        localName = name;
        value = null;
    }

    private String nextValue() {
        try {
            tokenType = jsonReader.peek();
            JsonObject peek = stackObj.peek();
            String valueType = peek.getValueType();
            if (!validateArgumentTypes(tokenType, valueType)) {
                log.error("Value type miss match, Expected value type - '" + valueType + "', but found - '"
                        + tokenType.toString() + "'");
                throw new IllegalArgumentException("Value type miss match, Expected value type - '" + valueType
                        + "', but found - '" + tokenType.toString() + "'");
            }
            if (tokenType == JsonToken.STRING) {
                value = jsonReader.nextString();
            } else if (tokenType == JsonToken.BOOLEAN) {
                value = String.valueOf(jsonReader.nextBoolean());
            } else if (tokenType == JsonToken.NUMBER) {
                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 == JsonToken.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;
    }

    /**
     * this method is to check whether input json type matches with the types specified in the schema
     *
     * @param tokenType
     * @param expectedType
     * @return true if it matches false otherwise
     */
    private boolean validateArgumentTypes(JsonToken tokenType, String expectedType) {
        if (expectedType.equalsIgnoreCase(tokenType.toString())) {
            return true;
        } else if (tokenType == JsonToken.NULL) {
            return true;
        } else if (tokenType == JsonToken.NUMBER) {
            if (expectedType.equals("int") || expectedType.equals("long") || expectedType.equals("double")
                    || expectedType.equals("float")) {
                return true;
            }
        }
        return false;
    }

    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,
    }
}