<?xml version="1.0"?>
<!--
  ~ 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.
  -->
<document xmlns="http://maven.apache.org/XDOC/2.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
    <properties>
        <title>JSON Support in Axis2</title>
    </properties>
    <body>
        <h1>JSON Support in Axis2</h1>
        <section name="Introduction">
            <p>This document explains the JSON support implementation in Axis2.
            It includes an introduction to JSON, an outline as to why JSON
            support is useful to Axis2 and how it should be used. This document
            also provides details on test cases and samples.</p>
        </section>
        <section name="What is JSON?">
            <p><a href="http://www.json.org/">JSON</a> (Java Script Object
            Notation) is another data exchangeable format like XML, but more
            lightweight and easily readable. It is based on a subset of the
            JavaScript language. Therefore, JavaScript can understand JSON, and
            it can make JavaScript objects by using JSON strings. JSON is based
            on key-value pairs and it uses colons to separate keys and values.
            JSON doesn't use end tags, and it uses braces (curly brackets) to
            enclose JSON Objects.</p>
            <p><font size="3">e.g. <font size="2">&lt;root&gt;&lt;test&gt;json
            object&lt;/test&gt;&lt;/root&gt; ==
            {{json object}}</font></font></p>
            <p>When it comes to converting XML to JSON and vice versa, there
            are two major conventions, one named "<a href=
            "http://www.sklar.com/badgerfish/">Badgerfish</a>" and the other,
            Mapped. The main difference
            between these two conventions exists in the way they map XML
            namespaces into JSON.</p>
            <p><font size="3">e.g. <font size="2">&lt;xsl:root
            xmlns:xsl="http://foo.com"&gt;&lt;data&gt;my json
            string&lt;/data&gt;&lt;/xsl:root&gt;</font></font></p>
            <p>This XML string can be converted into JSON as follows.</p>
            <p><b>Using Badgerfish</b></p>
            <p><font size=
            "2">{"xsl:root":{"@xmlns":{"xsl":"http://foo.com"},"data":{"$":"my
            json string"}}}</font></p>
            <p><b>Using Mapped</b></p>
            <p>If we use the namespace mapping as http://foo.com -&gt; foo</p>
            <p><font size="2">{"foo.root":{"data":"my json string"}}</font></p>
        </section>
        <section name="Why JSON Support for Axis2?">
            <p><a href="../index.html">Apache Axis2</a> is a Web
            services stack that delivers incoming messages into target
            applications. In most cases, these messages are SOAP messages. In
            addition, it is also possible to send REST messages through Axis2.
            Both types of messages use XML as their data exchangeable format.
            So if we can use XML as a format, why use JSON as another
            format?</p>
            <p>There are many advantages of implementing JSON support in Axis2.
            Mainly, it helps the JavaScript users (services and clients written
            in JavaScript) to deal with Axis2. When the service or the client
            is in JavaScript, it can use the JSON string and directly build
            JavaScript objects to retrieve information, without having to build
            the object model (OMElement in Axis2). Also, JavaScript services
            can return the response through Axis2, just as a JSON string can be
            shipped in a JSONDataSource.</p>
            <p>Other than for that, there are some extra advantages of using
            JSON in comparison to XML. Although the conversation
            XML or JSON? is still a hot topic,
            many people accept the fact that JSON can be passed and built more
            easily by machines than XML.</p>
        </section>
        <section name="How to use JSON in Axis2">
            <p>At the moment JSON doesn't have a standard and unique content
            type. <tt>application/json</tt> (this is
            the content type which is approved in the <a href=
            "http://www.ietf.org/rfc/rfc4627.txt">JSON RFC</a>),
            <tt>text/javascript</tt> and
            <tt>text/json</tt> are some of the commonly
            used content types for JSON. Fortunately, in Axis2, the user
            has the freedom of specifying the content type to use.</p>
            <subsection name="Configuring axis2.xml">
                <p>First of all, you need to map the appropriate message formatters and builders to the
                content type you are using in the <tt>axis2.xml</tt> file. This applies both the to
                client side and the server side.</p>
                <p>E.g., if you are using the
                Mapped convention with the content
                type <tt>application/json</tt>, add the following declaration:</p>
<pre><![CDATA[
    <messageFormatters>        
        <messageFormatter contentType="application/json"
                          class="org.apache.axis2.json.JSONMessageFormatter"/>
        <!-- more message formatters -->
    </messageFormatters>   

    <messageBuilders>
        <messageBuilder contentType="application/json"
                        class="org.apache.axis2.json.JSONOMBuilder"/>
        <!-- more message builders -->
    </messageBuilders>
]]></pre>
                <p>If you are using the
                Badgerfish convention with the
                content type <tt>text/javascript</tt>, add:</p>
<pre><![CDATA[
    <messageFormatters>        
        <messageFormatter contentType="text/javascript"
                          class="org.apache.axis2.json.JSONBadgerfishMessageFormatter">
        <!-- more message formatters -->
    </messageFormatters> 

    <messageBuilders>
        <messageBuilder contentType="text/javascript"
                        class="org.apache.axis2.json.JSONBadgerfishOMBuilder"/>
        <!-- more message builders -->
    </messageBuilders>
]]></pre>
            </subsection>
            <subsection name="Client-side configuration">
                <p>On the client side, make the ConfigurationContext by reading the
                axis2.xml in which the correct mappings are given.</p>
                <p>e.g.</p>
<pre>
        File configFile = new File("test-resources/axis2.xml");
        configurationContext = ConfigurationContextFactory
                        .createConfigurationContextFromFileSystem(null, configFile.getAbsolutePath());
        ..........        
        ServiceClient sender = new ServiceClient(configurationContext, null);
</pre>
                <p>Set the <i>MESSAGE_TYPE</i> option with exactly the same content
                type you used in the axis2.xml.</p>
                <p>e.g. If you use the content type
                application/json,</p>
<pre>
        Options options = new Options();        
        options.setProperty(Constants.Configuration.MESSAGE_TYPE, "application/json");
        //more options
        //...................        

        ServiceClient sender = new ServiceClient(configurationContext, null);        
        sender.setOptions(options);
</pre>
                <p>If you are sending a request to a remote service, you have to
                know the exact JSON content type that is used by that service, and
                you have to use that content type in your client as well.</p>
                <p>HTTP POST is used as the default method to send JSON messages
                through Axis2, if the HTTP method is not explicitly set by the
                user. But if you want to send JSON in HTTP GET method as a
                parameter, you can do that by just setting an option on the client
                side.</p>
                <p>e.g.</p>
<code>options.setProperty(Constants.Configuration.HTTP_METHOD,
Constants.Configuration.HTTP_METHOD_GET);</code>
                <p>Here, the Axis2 receiving side (JSONOMBuilder) builds the
                OMElement by reading the JSON string which is sent as a parameter.
                The request can be made even through the browser.</p>
                <p>e.g. Sample JSON request through HTTP GET. The JSON message is
                encoded and sent.</p>
<code>GET
/axis2/services/EchoXMLService/echoOM?query=%7B%22echoOM%22:%7B%22data%22:%5B%22my%20json%20string%22,%22my%20second%20json%20string%22%5D%7D%7D
HTTP/1.1</code>
            </subsection>
            <subsection name="Server-side configuration">
                <p>Since Badgerfish defines a 1-to-1 transformation between JSON and XML, no additional configuration
                is required on the server side if that convention is used. Any service deployed into Axis2 will work
                out of the box.</p>
                <p>On the other hand, if the Mapped JSON convention is used, then Axis2 needs to know the mappings
                between XML namespaces and JSON "namespaces" in order to translate messages from JSON
                into XML representations and vice-versa. To use the Mapped convention with a service deployed into Axis2,
                add a <tt>xmlToJsonNamespaceMap</tt> property with these mappings to the <tt>services.xml</tt> file for that service, as
                shown in the following example:</p>
<pre><![CDATA[
<service name="...">
    ...
    <parameter name="xmlToJsonNamespaceMap">
        <mappings>
            <mapping xmlNamespace="http://example.org/foo" jsonNamespace=""/>
            <mapping xmlNamespace="http://example.org/bar" jsonNamespace="bar"/>
        </mappings>
    </parameter>
    ...
</service>
]]></pre>
            </subsection>
        </section>
        <section name="How the JSON implementation works - Architecture">
            <subsection name="Introduction">
                <p>The Axis2 architecture is based on the assumption that any message flowing through
                the Axis2 runtime is representable as a SOAP infoset, i.e. as XML wrapped in a SOAP
                envelope. Conceptually, the two message builders <code>JSONOMBuilder</code> and
                <code>JSONBadgerfishOMBuilder</code> convert incoming messages from JSON to XML and
                the two message formatters <code>JSONMessageFormatter</code> and <code>JSONBadgerfishMessageFormatter</code>
                convert outgoing messages from XML to JSON. Axis2 doesn't implement its own JSON parser and serializer, and
                instead relies on <a href="http://jettison.codehaus.org/">Jettison</a> to do the JSON&lt;->XML conversions.</p>
                <p>On the server side the XML for an incoming
                message is typically converted to Java objects by a databinding (such as ADB or JAX-WS)
                before the invocation of the service implementation. In the same way, the Java object returned by the
                service implementation is converted to XML. In the case we are interested in, that XML is then converted
                by the message formatters to JSON. The usage of an intermediate XML representation is the reason why
                JSON can be enabled on any service deployed in Axis2.</p>
                <p>It is important to note that the explanation given in the previous two paragraphs is only valid from
                a conceptual point of view. The actual processing model is more complicated. In the next two sections
                we will explain in detail how Axis2 processes incoming and outgoind JSON messages.</p>
            </subsection>
            <subsection name="Processing of incoming JSON messages">
                <p>Axis2 relies on <a href="http://ws.apache.org/axiom/">Apache Axiom</a> as its XML object model. Although
                Axiom has a DOM like API, it also has several advanced features that enable Axis2 to avoid
                building a complete object model representation of the XML message. This is important for performance
                reasons and distinguishes Axis2 from previous generation SOAP stacks. To leverage these features, the
                JSON message builders create a SOAP envelope the body of which contains a single <code>OMSourcedElement</code>.</p>
                <p>An <code>OMSourcedElement</code> is a special kind of <code>OMElement</code> that wraps an arbitrary
                Java object that can be converted to XML in a well defined way. More precisely, the Java object as well as the logic
                to convert the object to XML are encapsulated in an <code>OMDataSource</code> instance and it is that
                <code>OMDataSource</code> instance that is used to create the <code>OMSourcedElement</code>.
                For JSON, the <code>OMDataSource</code> implementation is <code>JSONDataSource</code> or <code>JSONBadgerfishDataSource</code>,
                depending on the convention being used. The base class (<code>AbstractJSONDataSource</code>) of these two classes
                actually contains the code that invokes Jettison to perform the JSON to XML conversion.</p>
                <p>An <code>OMSourcedElement</code> still behaves like a normal <code>OMElement</code>. In particular, if the
                element is accessed using DOM like methods, then Axiom will convert the data encapsulated by
                the <code>OMDataSource</code> on the fly to an object model representation. This process is called <i>expansion</i> of the
                <code>OMSourcedElement</code>. However, the <code>OMDataSource</code> API is designed such that the conversion to
                XML is always done using a streaming API: either the <code>OMDataSource</code> produces an <code>XMLStreamReader</code>
                instance from which the XML representation can be read (this is the case for JSON and the <code>XMLStreamReader</code> implementation
                is actually provided by Jettison) or it serializes the XML representation to an <code>XMLStreamWriter</code>. 
                Because of this, expansion of the <code>OMSourcedElement</code> is often not necessary, so that the overhead of
                creating an object model representation can usually be avoided. E.g. a databinding will typically consume the message by requesting an
                <code>XMLStreamReader</code> for the element in the SOAP body, and this doesn't require expansion of the
                <code>OMSourcedElement</code>. In this case, the databinding pulls the XML data almost directly from the
                underlying Jettison <code>XMLStreamReader</code> and no additional Axiom objects are created.</p>
                <p>Actually here again, things are slightly more complicated because in order to dispatch to the right
                operation, Axis2 needs to determine the name of the element in the body. Since the name is not known
                in advance, that operation requires expansion of the <code>OMSourcedElement</code>. However, at this point
                none of the children of the <code>OMSourcedElement</code> will be built. Fortunately the databindings
                generally request the <code>XMLStreamReader</code> with caching turned off, so that the child nodes will never be
                built. Therefore the conclusion of the previous paragraph remains valid: processing the message with a databinding
                will not create a complete object model representation of the XML.</p>
                <p>Usage of an <code>OMSourcedElement</code> also solves another architectural challenge posed by
                the Mapped JSON convention: the JSON payload can only be converted to XML if the namespace mappings
                are known. Since they are defined per service, they are only known after the incoming message has been
                dispatched and the target service has been identified. This typically occurs
                in <code>RequestURIBasedDispatcher</code>, which is executed after
                the message builder. This means that <code>JSONOMBuilder</code> cannot actually perform the conversion.
                Usage of an <code>OMSourcedElement</code> avoids this issue because the conversion is done lazily when
                the <code>OMSourcedElement</code> is first accessed, and this occurs after <code>RequestURIBasedDispatcher</code>
                has been executed.</p>
                <p>Another advantage of using <code>OMSourcedElement</code> is that a JSON aware service could directly process
                the JSON payload without going through the JSON to XML conversion. That is possible because the <code>OMDataSource</code>
                simply keeps a reference to the JSON payload and this reference is accessible to JSON aware code.</p>
            </subsection>
            <subsection name="Processing of outgoing messages">
                <p>For outgoing messages, the two JSON message formatters <code>JSONMessageFormatter</code> and
                <code>JSONBadgerfishMessageFormatter</code> use Jettision to create an appropriate <code>XMLStreamWriter</code>
                and then request Axiom to serialize the body element to that <code>XMLStreamWriter</code>. If a databinding
                is used, then the body element will typically be an <code>OMSourcedElement</code> with an <code>OMDataSource</code>
                implementation specific to that databinding. <code>OMSourcedElement</code> will delegate the serialization
                request to the appropriate method defined by <code>OMDataSource</code>. This means that the databinding code
                directly writes to the <code>XMLStreamWriter</code> instance provided by Jettision, without building an
                intermediate XML object model.</p>
                <p>Before doing this, the JSON message formatters actually check if the element is an <code>OMSourcedElement</code>
                backed by a corresponding JSON <code>OMDataSource</code> implementation. If that is the case, then they will
                extract the JSON payload and directly write it to the output stream. This allows JSON aware services to
                bypass the XML to JSON conversion entirely.</p>
            </subsection>
        </section>
        <section name="Tests and Samples">
            <subsection name="Integration Test">
                <p>The JSON integration test is available under
                test in the
                json module of Axis2. It uses the
                SimpleHTTPServer to deploy the service. A simple echo service is
                used to return the incoming OMSourcedElement object, which
                contains the JSONDataSource. There are two test cases for two
                different conventions and another one test case to send the request
                in GET.</p>
            </subsection>
            <subsection name="Yahoo-JSON Sample">
                <p>This sample is available in the
                samples module of Axis2. It is a
                client which calls the Yahoo search API using the GET method, with
                the parameter output=json. The
                Yahoo search service sends the response as a
                formatted JSON string with
                the content type text/javascript.
                This content type is mapped with the JSONOMBuilder in the
                axis2.xml. All the results are shown in a GUI. To run the sample,
                execute the ant script.</p>
                <p>These two applications provide good examples of using JSON
                within Axis2. By reviewing these samples, you will be able to
                better understand Axis2's JSON support implementation.</p>
            </subsection>
            <subsection name="Enabling mapped JSON on the ADB quickstart sample">
                <p>To illustrate how JSON can be enabled on an existing service deployed in Axis2,
                we will use the ADB stock quote service sample from the
                <a href="quickstartguide.html#adb">Quick Start Guide</a>. The code for this sample
                can be found in the <tt>samples/quickstartadb</tt> folder in the binary distribution.</p>
                <p>Only a few steps are necessary to enable JSON (using the Mapped convention) on
                that service:</p>
                <ol>
                    <li>
                        <p>Configure the JSON message builders and formatters in <tt>conf/axis2.xml</tt>.
                        Add the following element to the <tt>messageFormatters</tt>:</p>
<pre><![CDATA[
<messageFormatter contentType="application/json"
                  class="org.apache.axis2.json.JSONMessageFormatter"/>
]]></pre>
                        <p>Also add the following element to the <tt>messageBuilders:</tt></p>
<pre><![CDATA[
<messageBuilder contentType="application/json"
                class="org.apache.axis2.json.JSONOMBuilder"/>
]]></pre>
                    </li>
                    <li>
                        <p>Edit the <tt>services.xml</tt> for the stock quote service and add the following
                        configuration:</p>
<pre><![CDATA[
<parameter name="xmlToJsonNamespaceMap">
    <mappings>
        <mapping xmlNamespace="http://quickstart.samples/xsd" jsonNamespace=""/>
    </mappings>
</parameter>
]]></pre>
                        <p>The <tt>services.xml</tt> file can be found under
                        <tt>samples/quickstartadb/resources/META-INF</tt>.</p>
                    </li>
                    <li>
                        <p>Build and deploy the service by executing the ant script in
                        <tt>samples/quickstartadb</tt> and then start the Axis2 server using
                        <tt>bin/axis2server.sh</tt> or <tt>bin/axis2server.bat</tt>.</p>
                    </li>
                </ol>
                <p>That's it; the stock quote service can now be invoked using JSON. This can be tested
                using the well known <a href="http://curl.haxx.se/">curl</a> tool:</p>
                <pre>curl -H 'Content-Type: application/json' -d '{"getPrice":{"symbol":"IBM"}}' http://localhost:8080/axis2/services/StockQuoteService</pre>
                <p>This will give the following result:</p>
                <pre>{"getPriceResponse":{"return":42}}</pre>
            </subsection>
        </section>
    </body>
</document>
