/** * 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.synapse.commons.staxon.core.json.JsonXMLConfig; import org.apache.synapse.commons.staxon.core.json.JsonXMLConfigBuilder; import org.apache.synapse.commons.staxon.core.json.JsonXMLInputFactory; 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.io.output.ByteArrayOutputStream; 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.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Writer; final class JsonDataSourceImpl implements OMDataSource { public static final String END_OBJECT = "}"; public static final String END_ARRAY = "}}"; public static final String EMPTY_OBJECT = "{}"; public static final String WRAPPER_OBJECT = "{" + Constants.K_OBJECT + ":"; public static final String WRAPPER_ARRAY = "{" + Constants.K_ARRAY + ":{" + Constants.K_ARRAY_ELEM + ":"; private byte[] stream; private int offset = 0; private int length = 0; private boolean isObject = true; private static final JsonXMLConfig xmlConfig = new JsonXMLConfigBuilder() .multiplePI(true) .autoArray(true) .autoPrimitive(true) .namespaceDeclarations(false) .build(); private static final JsonXMLInputFactory xmlInputFactory = new JsonXMLInputFactory(xmlConfig); /** * Configuration used to produce XML that has no processing instructions in it. */ private static final JsonXMLConfig xmlConfigNoPIs = new JsonXMLConfigBuilder() .multiplePI(false) .autoArray(true) .autoPrimitive(true) .namespaceDeclarations(false) .build(); private static final JsonXMLInputFactory xmlInputFactoryNoPIs = new JsonXMLInputFactory(xmlConfigNoPIs); private static final Log logger = LogFactory.getLog(JsonDataSourceImpl.class.getName()); public JsonDataSourceImpl(InputStream inputStream) { ByteArrayOutputStream stream = new ByteArrayOutputStream(); int c; try { while (((c = inputStream.read()) != -1) && Character.isWhitespace((char) c)) { } ++length; if (c == '{') { stream.write(WRAPPER_OBJECT.getBytes()); offset = WRAPPER_OBJECT.length(); } else if (c == '[') { stream.write(WRAPPER_ARRAY.getBytes()); isObject = false; offset = WRAPPER_ARRAY.length(); } else { logger.error("Could not create a JSON data source from the input stream. Found '" + ((char) c) + "' at the start of the input stream."); this.stream = EMPTY_OBJECT.getBytes(); return; } stream.write(c); while (((c = inputStream.read()) != -1)) { stream.write(c); ++length; } if (isObject) { stream.write(END_OBJECT.getBytes()); } else { stream.write(END_ARRAY.getBytes()); } stream.flush(); this.stream = stream.toByteArray(); if (logger.isDebugEnabled()) { logger.debug("Built JSON Data Source from the incoming stream."); } } catch (IOException e) { logger.error("Could not create a JSON data source from the input stream. " + e.getLocalizedMessage()); this.stream = EMPTY_OBJECT.getBytes(); isObject = true; } } public void serialize(OutputStream output, OMOutputFormat format) throws XMLStreamException { try { output.write(stream, offset, length); } catch (IOException e) { throw new OMException("Could not serialize payload. " + e.getLocalizedMessage()); } } public void serialize(Writer writer, OMOutputFormat format) throws XMLStreamException { try { IOUtils.copy(new ByteArrayInputStream(stream, offset, length), writer); } catch (IOException e) { throw new OMException("Could not serialize payload. " + e.getLocalizedMessage()); } } 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 { return new JsonReaderDelegate(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(stream)), false); } }