# JsonDataSource.java

    /**
     *  Copyright (c) 2005-2010, 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.apache.synapse.commons.json;

    import org.apache.axiom.om.OMDataSource;
    import org.apache.axiom.om.OMException;
    import org.apache.axiom.om.OMOutputFormat;
    import org.apache.commons.io.IOUtils;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    import javax.xml.stream.XMLStreamConstants;
    import javax.xml.stream.XMLStreamException;
    import javax.xml.stream.XMLStreamReader;
    import javax.xml.stream.XMLStreamWriter;
    import java.io.*;

    final class JsonDataSource implements OMDataSource {
        private static final Log logger = LogFactory.getLog(JsonDataSourceImpl.class.getName());

        private final InputStream inputStream;

        public JsonDataSource(InputStream inputStream) {
            if (inputStream instanceof BufferedInputStream) {
                this.inputStream = inputStream;
                // and we assume that this passed in input stream is fresh and it has been marked first.
            } else if (inputStream != null) {
                this.inputStream = new BufferedInputStream(inputStream);
                this.inputStream.mark(Integer.MAX_VALUE);
            } else {
                this.inputStream = null;
                logger.error("#JsonDataSource. Created invalid JSON DataSource. No JSON input stream found.");
            }
        }

        public void serialize(OutputStream output, OMOutputFormat format) throws XMLStreamException {
            try {
                if (format != null && format.getContentType() != null) {
                    if (format.getContentType().contains("xml")) {
                        inputStream.reset(); // reuse the stream
                        JsonUtil.toXml(inputStream, false).serialize(output, format);
                        return;
                    }
                }
                inputStream.reset();
                IOUtils.copy(inputStream, output);
            } catch (IOException e) {
                logger.error("#serialize:OutputStream. Could not serialize JSON payload. Error>>> " + e.getLocalizedMessage());
                throw new OMException("Could not serialize JSON payload.", e);
            }
        }

        public void serialize(Writer writer, OMOutputFormat format) throws XMLStreamException {
            try {
                if (format != null && format.getContentType() != null) {
                    if (format.getContentType().contains("xml")) {
                        inputStream.reset(); // reuse the stream
                        JsonUtil.toXml(inputStream, false).serialize(writer, format);
                        return;
                    }
                }
                inputStream.reset();
                IOUtils.copy(inputStream, writer);
            } catch (IOException e) {
                logger.error("#serialize:Writer. Could not serialize JSON payload. Error>>> " + e.getLocalizedMessage());
                throw new OMException("Could not serialize JSON payload.", e);
            }
        }

        public void serialize(XMLStreamWriter xmlWriter) throws XMLStreamException {
            XMLStreamReader reader = getReader();
            xmlWriter.writeStartDocument();
            while (reader.hasNext()) {
                int x = reader.next();
                switch (x) {
                    case XMLStreamConstants.START_ELEMENT:
                        xmlWriter.writeStartElement(reader.getPrefix(), reader.getLocalName(),
                                reader.getNamespaceURI());
                        int namespaceCount = reader.getNamespaceCount();
                        for (int i = namespaceCount - 1; i >= 0; i--) {
                            xmlWriter.writeNamespace(reader.getNamespacePrefix(i),
                                    reader.getNamespaceURI(i));
                        }
                        int attributeCount = reader.getAttributeCount();
                        for (int i = 0; i < attributeCount; i++) {
                            xmlWriter.writeAttribute(reader.getAttributePrefix(i),
                                    reader.getAttributeNamespace(i),
                                    reader.getAttributeLocalName(i),
                                    reader.getAttributeValue(i));
                        }
                        break;
                    case XMLStreamConstants.START_DOCUMENT:
                        break;
                    case XMLStreamConstants.CHARACTERS:
                        xmlWriter.writeCharacters(reader.getText());
                        break;
                    case XMLStreamConstants.CDATA:
                        xmlWriter.writeCData(reader.getText());
                        break;
                    case XMLStreamConstants.END_ELEMENT:
                        xmlWriter.writeEndElement();
                        break;
                    case XMLStreamConstants.END_DOCUMENT:
                        xmlWriter.writeEndDocument();
                        break;
                    case XMLStreamConstants.SPACE:
                        break;
                    case XMLStreamConstants.COMMENT:
                        xmlWriter.writeComment(reader.getText());
                        break;
                    case XMLStreamConstants.DTD:
                        xmlWriter.writeDTD(reader.getText());
                        break;
                    case XMLStreamConstants.PROCESSING_INSTRUCTION:
                        xmlWriter
                                .writeProcessingInstruction(reader.getPITarget(), reader.getPIData());
                        break;
                    case XMLStreamConstants.ENTITY_REFERENCE:
                        xmlWriter.writeEntityRef(reader.getLocalName());
                        break;
                    default:
                        throw new OMException();
                }
            }
            xmlWriter.writeEndDocument();
            xmlWriter.flush();
            xmlWriter.close();
        }

        public XMLStreamReader getReader() throws XMLStreamException {
            try {
                inputStream.reset();
            } catch (IOException e) {
                logger.error("#getReader. Could not reuse JSON stream from JSON Data Source. Error>> " + e.getLocalizedMessage());
                throw new XMLStreamException("Could not reuse JSON stream from JSON Data Source.", e);
            }
            // Inform reader to add or remove PI's from XML output as per the configurations
            return JsonUtil.getReader(inputStream, JsonUtil.isPiEnabled());
        }
    }