<!--
  ~ 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.
  -->
<html>
<head>
  <meta http-equiv="content-type" content=""/>
  <title></title>
  <link href="../css/axis-docs.css" rel="stylesheet" type="text/css"
  media="all"/>
</head>

<body>
<h1>How to Write Your Own Axis2 Transport</h1>

<h2>Prologue</h2>

<p>To stop you from re-inventing the wheel, before we get started, I will
quickly list the transports that are already supported in Axis2 with a small
description.</p>

<p></p>
<ul>
  <li><b>HTTP</b> - In the HTTP transport, the transport Listener is either a
    Servlet or a Simple HTTP server provided by Axis2. The transport Sender
    uses sockets to connect and send the SOAP message. Currently we have the
    commons-httpclient based HTTP Transport sender as the default
  transport.</li>
  <li><b>TCP</b> - This is the most simple transport, but needs Addressing
    support to be functional.</li>
  <li><b>SMTP</b> - This can work off a single email account or a mail
    server. The Mail Transport Receiver is a thread that checks for emails in
    fixed time intervals.</li>
</ul>

<p>To understand the rest of this document you will need some understanding
of the architecture of Axis2. If you are not familiar with the Axis2
architecture, please go through the <a
href="Axis2ArchitectureGuide.html">Axis2 Architecture Guide</a> before you
read any further.</p>

<h2>Introduction</h2>

<p>Broadly speaking, a transport inside Axis2 can be classified as a way of
getting messages that arrive though some channel into the Axis2 engine. The
core of Axis2 is transport independent. All data that is transport specific
is stripped out of the incoming message and inserted into the MessageContext.
In the outgoing message, all transport specific information, like headers,
are added and sent.</p>

<p>To write your own transport, you will primarily need to write two classes:
one is the TransportSender and the other is the TransportReceiver. To
register a transport with Axis2 you will need to put entries corresponding
to these two classes in the axis2.xml file. I will take you through the 
process of adding the entries in the relevant sections.</p>

<h2>Transport Receiver</h2>

<p>Any message that is coming into Axis2 needs to go through a transport
receiver. All information about how the message is received at the Axis2
server from the wire (or via an e-mail) is isolated inside the transport
receiver. It extracts the data that is coming on the wire and transforms it
into a state that the Axis2 server understands.</p>

<p>So now that we have some background information about how transports work
inside Axis2, without further delay, lets dive into some coding and start
building our own transport.</p>

<p></p>

<p>To get things stared, you will first need to extend from the
org.apache.Axis2.transport.TransportListener class and write your own
transport listener. To create an engine to process the MessageContext, we
need a configuration context. The following code fragment will do this. This
should ideally be only done once for the lifetime of the Transport
receiver.</p>

<p></p><source>
<pre>try {
        //Create a factory 
        ConfigurationContextFactory factory = new ConfigurationContextFactory();
        //Use the factory and an Axis2 repository to create a new Configuration Context
        configurationContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem(repository_directory, 
axis2xmllocation);
} catch (Exception e) {
        log.info(e.getMessage());
}</pre>
</source>
<p>Now we need some kind of a Listener to listen to the requests that come
in. You need to implement this according to the transport that you are trying
to build. After a message is received at the Receiver, you can use the
following code to process the request and then forward the message context to
the engine using the engine.receive(msgContext) method. (The following code
is extracted from the MailListener as an example)</p>
<source><pre>AxisEngine engine = new AxisEngine(configurationContext);
MessageContext msgContext = null;

// create and initialize a message context
try {
        TransportInDescription transportIn =
                reg.getAxisConfiguration().getTransportIn(new QName(Constants.TRANSPORT_NAME));
        TransportOutDescription transportOut =
                reg.getAxisConfiguration().getTransportOut(new QName(Constants.TRANSPORT_NAME));
        if (transportIn != null &amp;&amp; transportOut != null) {
                //create Message Context
                
                msgContext = new MessageContext(configurationContext, transportIn, transportOut);
                msgContext.setServerSide(true);
                msgContext.setProperty(MailSrvConstants.CONTENT_TYPE, message.getContentType());
                msgContext.setProperty(MessageContext.CHARACTER_SET_ENCODING, message.getEncoding());

                String soapAction = message.getSOAPActionHeader();
                msgContext.setWSAAction(soapAction);
                msgContext.setSoapAction(soapAction);

                // Here we are trying to set the reply to if it is present in the transport information.
                msgContext.setReplyTo(new EndpointReference(message.getReplyTo());

                //Create the SOAP Message -- This code in from the mail transport and will change depending
                //on how the data is handled in each transport.
                ByteArrayInputStream bais = new ByteArrayInputStream(message.getContent().toString().getBytes());
                XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(bais);

                String soapNamespaceURI = "";
                if(message.getContentType().indexOf(SOAP12Constants.SOAP_12_CONTENT_TYPE) &gt; -1){
                        soapNamespaceURI = SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI;
                }else if(message.getContentType().indexOf(SOAP11Constants.SOAP_11_CONTENT_TYPE) &gt; -1){
                        soapNamespaceURI = SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI;
                }

                StAXBuilder builder = new StAXSOAPModelBuilder(reader, soapNamespaceURI);

                SOAPEnvelope envelope = (SOAPEnvelope) builder.getDocumentElement();
                msgContext.setEnvelope(envelope);
                engine.receive(msgContext);
        } else {
                throw new AxisFault(Messages.getMessage("unknownTransport",Constants.TRANSPORT_NAME));
        }

} catch (Exception e) {
        try {
                if (msgContext != null) {
                        MessageContext faultContext = engine.createFaultMessageContext(msgContext, e);
                        engine.sendFault(faultContext);
                } else {
                        log.error(e);
                }
        } catch (AxisFault e1) {
                log.error(e);
        }
}</pre>
</source>
<p>Now that we have the coding in place, we need to let Axis2 know about our
new transport receiver. We do this by adding an entry into the axis2.xml
file. If you need to pass any properties for the transport to operate, it can
also be done through the axis2.xml file.</p>
<source><pre>   &lt;transportReceiver name="TRANSPORT_NAME" class="org.apache.Axis2.transport.TRANSPORT_NAME.TRANSPORT_LISTNER_CLASS"&gt;
        &lt;parameter name="PROPERTY_NAME"&gt;PROPERTY_VALUE&lt;/parameter&gt;
        &lt;parameter name="PROPERTY_NAME_2"&gt;PROPERTY_VALUE_2&lt;/parameter&gt;
  &lt;/transportReceiver&gt;
  </pre>
</source>
<p>By using a code fragment like
<code>Utils.getParameterValue(transportOut.getParameter(MailSrvConstants.SMTP_USER))</code>
we can extract the parameters that we inserted into the axis2.xml file.</p>

<p>As you can see, getting a new transport receiver up and running is a task
that requires very little effort.</p>

<h2>Transport Sender</h2>

<p>Any message that is to be sent out of Axis2, is sent through the Transport
Sender. The Transport Sender needs to be extended from the
org.apache.Axis2.transport.AbstractTransportSender class.</p>

<p>The following bit of code from the abstract transport sender will call the
Transport Sender that you wrote.</p>
<source><pre>// If an EPR is present then the message is going on a different channel.
if (epr != null) {
        out = openTheConnection(epr, msgContext);
        OutputStream newOut = startSendWithToAddress(msgContext, out);
        if (newOut != null) {
                out = newOut;
        }
        writeMessage(msgContext, out);
        finalizeSendWithToAddress(msgContext, out);
        } else {
        out = (OutputStream) msgContext.getProperty(MessageContext.TRANSPORT_OUT);
        if (out != null) {
                startSendWithOutputStreamFromIncomingConnection(msgContext, out);
                writeMessage(msgContext, out);
                finalizeSendWithOutputStreamFromIncomingConnection(msgContext, out);
        } else {
                throw new AxisFault(
                        "Both the TO and Property MessageContext.TRANSPORT_WRITER is Null, No way to send response.");
        }
}</pre>
</source>
<p>Therefore, depending on whether your transport is using the same channel
to send the response or using a different channel, you will need to implement
a sub-set of the methods from the abstract class.</p>

<p>After implementing the necessary methods, you can let Axis2 know about
your new transport sender by adding an entry to the axis2.xml file, like you
did for the TransportReceiver.</p>
<source><pre>  &lt;transportSender name="TRANSPORT_NAME" class="org.apache.Axis2.transport.TRANSPORT_NAME.TRANSPORT_SENDER_CLASS"&gt;
        &lt;parameter name="PROPERTY_NAME"&gt;PROPERTY_VALUE&lt;/parameter&gt;
        &lt;parameter name="PROPERTY_NAME_2"&gt;PROPERTY_VALUE_2&lt;/parameter&gt;
  &lt;/transportSender&gt;
  </pre>
</source>
<p>Have a look at org.apache.Axis2.transport.mail.MailTransportSender for a
very simple Transport Sender. Also have a look at
org.apache.Axis2.transport.http.CommonsHTTPTransportSender which is used to
send HTTP responses.</p>

<p>Once we have written our transport receiver and our transport sender, and
inserted the required entries into the axis2.xml file, we are done. It is as
simple as that!</p>
</body>
</html>
