org.wso2.carbon.mediator.datamapper.engine.input.readers.JSONReader.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.mediator.datamapper.engine.input.readers.JSONReader.java

Source

/*
 * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. 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.wso2.carbon.mediator.datamapper.engine.input.readers;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.simple.parser.ContentHandler;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.wso2.carbon.mediator.datamapper.engine.core.exceptions.InvalidPayloadException;
import org.wso2.carbon.mediator.datamapper.engine.core.exceptions.JSException;
import org.wso2.carbon.mediator.datamapper.engine.core.exceptions.ReaderException;
import org.wso2.carbon.mediator.datamapper.engine.core.exceptions.SchemaException;
import org.wso2.carbon.mediator.datamapper.engine.core.exceptions.SimpleJSONParserException;
import org.wso2.carbon.mediator.datamapper.engine.core.schemas.Schema;
import org.wso2.carbon.mediator.datamapper.engine.core.schemas.SchemaElement;
import org.wso2.carbon.mediator.datamapper.engine.input.InputModelBuilder;
import org.wso2.carbon.mediator.datamapper.engine.input.readers.events.ReaderEvent;
import org.wso2.carbon.mediator.datamapper.engine.input.readers.events.ReaderEventType;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.ARRAY_ELEMENT_TYPE;
import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.BOOLEAN_ELEMENT_TYPE;
import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.INTEGER_ELEMENT_TYPE;
import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.NULL_ELEMENT_TYPE;
import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.NUMBER_ELEMENT_TYPE;
import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.OBJECT_ELEMENT_TYPE;
import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.STRING_ELEMENT_TYPE;

/**
 * This is a JSON reader implementation based on JSON Simple library.
 */
public class JSONReader implements Reader, ContentHandler {
    private static final Log log = LogFactory.getLog(JSONReader.class);
    private InputModelBuilder modelBuilder;
    private Schema inputSchema;
    private Stack<ReaderEvent> readerEventStack;
    private List<SchemaElement> schemaElementList;

    public JSONReader() {
        this.readerEventStack = new Stack<>();
        this.schemaElementList = new ArrayList<>();
    }

    public Schema getInputSchema() {
        return inputSchema;
    }

    @Override
    public void read(InputStream input, InputModelBuilder inputModelBuilder, Schema inputSchema)
            throws ReaderException {

        this.modelBuilder = inputModelBuilder;
        this.inputSchema = inputSchema;
        java.io.Reader reader = new InputStreamReader(input, StandardCharsets.UTF_8);
        JSONParser parser = new JSONParser();
        try {
            parser.parse(reader, this);
        } catch (IOException e) {
            throw new ReaderException("IO Error while parsing JSON input stream. " + e.getMessage());
        } catch (ParseException e) {
            throw new ReaderException("Error while parsing JSON input stream. " + e.getMessage());
        }
    }

    @Override
    public void startJSON() throws ParseException, IOException {
    }

    @Override
    public void endJSON() throws ParseException, IOException {
        try {
            sendTerminateEvent();
        } catch (IOException | JSException | SchemaException | ReaderException e) {
            throw new SimpleJSONParserException(
                    "Error occurred while sending termination event. " + e.getMessage());
        }
    }

    @Override
    public boolean startObject() throws ParseException, IOException {
        try {
            if (!getReaderEventStack().isEmpty()) {
                ReaderEvent stackElement = getReaderEventStack().peek();
                String type = getInputSchema().getElementTypeByName(schemaElementList);
                if (ReaderEventType.OBJECT_START.equals(stackElement.getEventType())) {
                    if (ARRAY_ELEMENT_TYPE.equals(type)) {
                        throw new SimpleJSONParserException("Schema specifies an array of type " + type + ". But "
                                + "payload doesn't contain an array.");
                    }
                    sendObjectStartEvent(stackElement.getName());
                    return true;
                }
            } else {
                schemaElementList.add(new SchemaElement(getInputSchema().getName()));
            }
            sendAnonymousObjectStartEvent();
        } catch (JSException | InvalidPayloadException | SchemaException | ReaderException e) {
            throw new SimpleJSONParserException(
                    "Error occurred while processing start object event. " + e.getMessage());
        }
        return true;
    }

    @Override
    public boolean endObject() throws ParseException, IOException {
        if (!getReaderEventStack().isEmpty()) {
            ReaderEvent stackElement = getReaderEventStack().peek();
            try {
                sendObjectEndEvent(stackElement.getName());
            } catch (JSException | InvalidPayloadException | SchemaException | ReaderException e) {
                throw new SimpleJSONParserException(
                        "Error occurred while processing end object event. " + e.getMessage());
            }
        }
        return true;
    }

    @Override
    public boolean startObjectEntry(String s) throws ParseException, IOException {
        try {
            schemaElementList.add(new SchemaElement(s));
            String type = getInputSchema().getElementTypeByName(schemaElementList);
            if (ARRAY_ELEMENT_TYPE.equals(type)) {
                pushObjectStartEvent(s);
            } else if (OBJECT_ELEMENT_TYPE.equals(type)) {
                pushObjectStartEvent(s);
            } else if (STRING_ELEMENT_TYPE.equals(type) || BOOLEAN_ELEMENT_TYPE.equals(type)
                    || NUMBER_ELEMENT_TYPE.equals(type) || INTEGER_ELEMENT_TYPE.equals(type)
                    || NULL_ELEMENT_TYPE.equals(type)) {
                pushObjectStartEvent(s);
            }
        } catch (JSException | InvalidPayloadException | SchemaException e) {
            throw new SimpleJSONParserException(
                    "Error occurred while processing start element event. " + e.getMessage());
        }
        return true;
    }

    @Override
    public boolean endObjectEntry() throws ParseException, IOException {
        if (!getReaderEventStack().isEmpty()) {
            ReaderEvent stackElement = getReaderEventStack().peek();
            try {
                popObjectEndEvent(stackElement.getName());
                schemaElementList.remove(schemaElementList.size() - 1);
            } catch (JSException | InvalidPayloadException | SchemaException e) {
                throw new SimpleJSONParserException("Error while sending end object entry. " + e.getMessage());
            }
        }
        return true;
    }

    @Override
    public boolean startArray() throws ParseException, IOException {
        try {
            if (!getReaderEventStack().isEmpty()) {
                ReaderEvent stackElement = getReaderEventStack().peek();
                String type = getInputSchema().getElementTypeByName(schemaElementList);

                if (ARRAY_ELEMENT_TYPE.equals(type)) {
                    try {
                        sendArrayStartEvent(stackElement.getName());
                    } catch (JSException | SchemaException | ReaderException e) {
                        throw new SimpleJSONParserException(
                                "Error occurred while processing start array event. " + e.getMessage());
                    }
                } else {
                    throw new SimpleJSONParserException("Found an array in the payload but schema doesn't specify "
                            + "any" + " array of type " + type);
                }
            }
        } catch (InvalidPayloadException | SchemaException e) {
            throw new SimpleJSONParserException("Error while sending array start entry. " + e.getMessage());
        }
        return true;
    }

    @Override
    public boolean endArray() throws ParseException, IOException {
        if (!getReaderEventStack().isEmpty()) {
            ReaderEvent stackElement = getReaderEventStack().peek();
            String type = null;
            try {
                type = getInputSchema().getElementTypeByName(schemaElementList);
            } catch (InvalidPayloadException | SchemaException e) {
                throw new SimpleJSONParserException(e.getMessage());
            }
            if (ARRAY_ELEMENT_TYPE.equals(type)) {
                try {
                    sendArrayEndEvent(stackElement.getName());
                } catch (JSException | SchemaException | ReaderException e) {
                    throw new SimpleJSONParserException(
                            "Error occurred while processing end array event. " + e.getMessage());
                }
            } else {
                throw new SimpleJSONParserException("Array element not found " + type);
            }
        }
        return true;
    }

    @Override
    public boolean primitive(Object value) throws ParseException, IOException {
        if (!getReaderEventStack().isEmpty()) {
            ReaderEvent stackElement = getReaderEventStack().peek();
            if (ReaderEventType.ARRAY_START.equals(stackElement.getEventType())) {
                try {
                    String fieldType = getFieldType(value);
                    sendPrimitiveEvent(value, fieldType);
                } catch (JSException | SchemaException | ReaderException e) {
                    throw new SimpleJSONParserException("Error while sending field value. " + e.getMessage());
                }
            } else {
                try {
                    String fieldType = getFieldType(value);
                    sendFieldEvent(stackElement.getName(), value, fieldType);
                } catch (JSException | SchemaException | ReaderException e) {
                    throw new SimpleJSONParserException("Error while sending field value. " + e.getMessage());
                }
            }
        }
        return true;
    }

    private String getFieldType(Object value) {
        if (value instanceof String) {
            return STRING_ELEMENT_TYPE;
        } else if (value instanceof Integer || value instanceof Long) {
            return INTEGER_ELEMENT_TYPE;
        } else if (value instanceof Double || value instanceof Float) {
            return NUMBER_ELEMENT_TYPE;
        } else if (value instanceof Boolean) {
            return BOOLEAN_ELEMENT_TYPE;
        }
        throw new IllegalArgumentException("Unsupported value type found" + value.toString());
    }

    public InputModelBuilder getModelBuilder() {
        return modelBuilder;
    }

    private void sendFieldEvent(String fieldName, Object value, String type)
            throws IOException, JSException, SchemaException, ReaderException {
        ReaderEvent fieldEvent = new ReaderEvent(ReaderEventType.FIELD, fieldName, value, type);
        getModelBuilder().notifyEvent(fieldEvent);
    }

    private void pushObjectStartEvent(String fieldName) throws IOException, JSException {
        ReaderEvent objectStartEvent = new ReaderEvent(ReaderEventType.OBJECT_START, fieldName, null);
        readerEventStack.push(objectStartEvent);
    }

    private void sendObjectStartEvent(String fieldName)
            throws IOException, JSException, SchemaException, ReaderException {
        ReaderEvent objectStartEvent = new ReaderEvent(ReaderEventType.OBJECT_START, fieldName, null);
        getModelBuilder().notifyEvent(objectStartEvent);
        readerEventStack.push(objectStartEvent);
    }

    private void sendObjectEndEvent(String fieldName)
            throws IOException, JSException, InvalidPayloadException, SchemaException, ReaderException {
        ReaderEvent objectEndEvent = new ReaderEvent(ReaderEventType.OBJECT_END, fieldName, null);
        getModelBuilder().notifyEvent(objectEndEvent);
        if (fieldName != null) {
            if (!ARRAY_ELEMENT_TYPE.equals(getInputSchema().getElementTypeByName(schemaElementList))) {
                readerEventStack.pop();
            }
        } else {
            readerEventStack.pop();
        }
    }

    private void popObjectEndEvent(String fieldName)
            throws IOException, JSException, InvalidPayloadException, SchemaException {
        ReaderEvent objectEndEvent = new ReaderEvent(ReaderEventType.OBJECT_END, fieldName, null);
        if (!ARRAY_ELEMENT_TYPE.equals(getInputSchema().getElementTypeByName(schemaElementList))
                || fieldName.equals(objectEndEvent.getName())) {
            readerEventStack.pop();
        }
    }

    private void sendArrayStartEvent(String fieldName)
            throws IOException, JSException, SchemaException, ReaderException {
        ReaderEvent arrayStartEvent = new ReaderEvent(ReaderEventType.ARRAY_START, fieldName, null);
        getModelBuilder().notifyEvent(arrayStartEvent);
        readerEventStack.push(arrayStartEvent);
    }

    private void sendArrayEndEvent(String fieldName)
            throws IOException, JSException, SchemaException, ReaderException {
        ReaderEvent arrayEndEvent = new ReaderEvent(ReaderEventType.ARRAY_END, fieldName, null);
        getModelBuilder().notifyEvent(arrayEndEvent);
        readerEventStack.pop();
    }

    public Stack<ReaderEvent> getReaderEventStack() {
        return readerEventStack;
    }

    private void sendTerminateEvent() throws IOException, JSException, SchemaException, ReaderException {
        getModelBuilder().notifyEvent(new ReaderEvent(ReaderEventType.TERMINATE, null, null));
        if (schemaElementList.size() != 1) {
            throw new ReaderException(
                    "schemaElementList contain more than one value in the end : " + schemaElementList.size());
        } else {
            schemaElementList.remove(0);
        }
    }

    private void sendAnonymousObjectStartEvent() throws IOException, JSException, SchemaException, ReaderException {
        ReaderEvent anonymousObjectStartEvent = new ReaderEvent(ReaderEventType.ANONYMOUS_OBJECT_START, null, null);
        getModelBuilder().notifyEvent(anonymousObjectStartEvent);
        readerEventStack.push(anonymousObjectStartEvent);
    }

    private void sendPrimitiveEvent(Object value, String fieldType)
            throws JSException, SchemaException, ReaderException, IOException {
        ReaderEvent primitiveEvent = new ReaderEvent(ReaderEventType.PRIMITIVE, null, value, fieldType);
        getModelBuilder().notifyEvent(primitiveEvent);
    }
}