Thursday, November 24, 2016

Quick start with SOAP using Apache Axis2 Framework



Why SOAP?

There are some great advantages which SOAP provides such as, SOAP can make use of any transport protocol not just HTTP/HTTPS. When security and reliability is a concern then you would need SOAP. SOAP security is well standardized through WS-SECURITY. SOAP supports transactions and complies with ACID phenomenon; it is reliable channel when you need transaction support.  

What is SOAP?

SOAP stands for Simple Object Access Protocol. It is a XML based communication medium/protocol. At the core it is an extension of HTTP protocol which uses XML for sending and receiving messages/information.

As we know that web services are platform and language independent, SOAP is used to create web services.   SOAP is the XML way of defining what information is sent and how. The definition of soap messages are done in WSDL file which stands for web service definition language. We define endpoints, request and response message definition using WSDL.

There are two versions/standards of SOAP. SOAP 1.1 (SOAP 11 Binding) and SOAP 1.2 (SOAP 12 Binding). Both are W3C standards.

Homework:
  • Find the difference between SOAP 1.1 and SOAP 1.2
  • Does SOAP use GET or POST?

SOAP can be used in multiple ways of messaging systems such as RPC, RMI, CORBA, DCOM etc. All of these messaging frameworks can work with SOAP. But mainly SOAP is used with RPC.

A SOAP message is an XML document with the following elements −
Ø  Envelope (Mandatory) – Used to define the start and the end of the message.
Ø  Header (Optional) − Contains a header information.
Ø  Body (Mandatory) − Contains the XML data which is being sent.
Ø  Fault (Optional) − It provides information about any error that occurs while processing the message.

Example:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://webservice.abhinavmishra14.github.com">
   <soapenv:Header/>
   <soapenv:Body>
      <web:authenticateUser>
         <web:user>admin</web:user>
         <web:password>admin</web:password>
      </web:authenticateUser>
   </soapenv:Body>
</soapenv:Envelope>

Homework: Read about SOAP xml elements in detail.

WSDL: It stands for web service definition language. WSDL describes how to access a web service and what operations it will perform. WSDL is an integral part of Universal Description, Discovery, and Integration (UDDI). UDDI is a worldwide Webservice registry. WSDL is the language that UDDI uses.
The three major elements of WSDL that can be defined separately are:
  1. Types
  2. Operations
  3.  Binding

A WSDL document has various elements, but they are contained within these three main elements, which can be developed as separate documents and then they can be combined or reused to form complete WSDL files.

WSDL Elements:

A WSDL document contains the following elements:

Definitions: It is the root element of WSDL. It defines the name of the web service, declares namespaces, and contains all the service elements definitions.

Types: The data types to be used in the soap messages are actually XML schemas (W3C Standard).

Message: It is used to define the request and response messages which are used as part of services.

PortType: It is a collection of operations mapped to service methods; it is used as a type for multiple bindings.

Operation: It is the abstract definition of the operation for a message, such as naming a method, message queue, or business process, that will accept and process the message.

Binding: It is the concrete protocol and data formats for the operations and messages defined for a particular port type.

Service: It is a collection of related end-points; the services map the binding to the port.

Port: It is a combination of a binding and a network address. It is used to configure the target address of service.

Documentation: This element is used to provide documentation.

Import: This element is used to import another WSDLs or XML Schemas.

Visit for more details: https://www.w3.org/TR/wsdl


Example of WSDL:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:ns1="http://org.apache.axis2/xsd" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
 xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:abhi="http://webservice.abhinavmishra14.github.com"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
 targetNamespace="http://webservice.abhinavmishra14.github.com">
               <wsdl:types>
                              <xs:schema attributeFormDefault="qualified" elementFormDefault="qualified"
                              targetNamespace="http://webservice.abhinavmishra14.github.com">
                                             <xs:element name="authenticateUser">
                                                            <xs:complexType>
                                                                           <xs:sequence>
                                                                                          <xs:element minOccurs="0" name="user" nillable="true" type="xs:string"/>
                                                                                          <xs:element minOccurs="0" name="password" nillable="true" type="xs:string"/>
                                                                           </xs:sequence>
                                                            </xs:complexType>
                                             </xs:element>
                                             <xs:element name="authenticateUserResponse">
                                                            <xs:complexType>
                                                                           <xs:sequence>
                                                                                          <xs:element minOccurs="0" name="return" nillable="true" type="xs:anyType"/>
                                                                           </xs:sequence>
                                                            </xs:complexType>
                                             </xs:element>
                              </xs:schema>
               </wsdl:types>

               <wsdl:message name="authenticateUserRequest">
                              <wsdl:part name="parameters" element="abhi:authenticateUser"/>
               </wsdl:message>

               <wsdl:message name="authenticateUserResponse">
                              <wsdl:part name="parameters" element="abhi:authenticateUserResponse"/>
               </wsdl:message>

               <wsdl:portType name="MyWebservicesPortType">
                              <wsdl:operation name="authenticateUser">
                                             <wsdl:input message="abhi:authenticateUserRequest"
                                                         wsaw:Action="urn:authenticateUser"/>
                                             <wsdl:output message="abhi:authenticateUserResponse"
                                                          wsaw:Action="urn:authenticateUserResponse"/>
                              </wsdl:operation>
               </wsdl:portType>

               <wsdl:binding name="MyWebservicesHttpBinding" type="abhi:MyWebservicesPortType">
                              <http:binding verb="POST"/>
                              <wsdl:operation name="authenticateUser">
                                             <http:operation location="authenticateUser"/>
                                             <wsdl:input>
                                                            <mime:content type="application/xml" part="parameters"/>
                                             </wsdl:input>
                                             <wsdl:output>
                                                            <mime:content type="application/xml" part="parameters"/>
                                             </wsdl:output>
                              </wsdl:operation>
               </wsdl:binding>
               <wsdl:service name="MyWebservices">
                              <wsdl:port name="MyWebservicesHttpEndpoint"
                                          binding="abhi:MyWebservicesHttpBinding">
                                             <http:address location="http://127.0.0.1:8082/mywebservices/services/MyWebservices"/>
                              </wsdl:port>
               </wsdl:service>
</wsdl:definitions>

Homework:
  • Explore more about WSDL
  • What is UUDI?
SOAP Services can be implemented using two approaches:
  1. POJO based 
  2. RAW XML based
Prerequisites:
  • Create a web project using maven "maven-archetype-j2ee-simple" archetype.
  • Add following dependencies in the pom file.

<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2</artifactId>
<version>1.6.3</version>
</dependency>

<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-http</artifactId>
<version>1.6.3</version>
</dependency>

<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-local</artifactId>
<version>1.6.3</version>
</dependency>

<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>2.4.0</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>

<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>

<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>

<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
  • Create services.xml under WEB-INF/services/<ServiceClassName>/META-INF folder. 
  • Visit Axis2 Configs  for configuring the services.xml
Note: I am using Axis2 1.6.3 version for demo.

POJO based request and response for SOAP messages:

Follow the below given steps to create a POJO based service:
  •       Define a Service class. E.g. MyWebservices

public class MyWebservices {

}
  •  Create POJO classes for receiving request parameters and returning response. Here we will create POJO for authentication service.

//To receive the username and password from request
public class UserModel implements Serializable{
               private static final long serialVersionUID = -3529671170359212999L;
               private String userName;
               private String password;
              
               public String getUserName() {
                              return userName;
               }
              
               public void setUserName(final String userName) {
                              this.userName = userName;
               }

               public String getPassword() {
                              return password;
               }

               public void setPassword(final String password) {
                              this.password = password;
               }
                     }

//To return the response.
public class AuthResult implements Serializable{

               private static final long serialVersionUID = 3869694084982552728L;
               private String sessionId;
               private String responseMessage;
              
               public String getSessionId() {
                              return sessionId;
               }

               public void setSessionId(final String sessionId) {
                              this.sessionId = sessionId;
               }

               public String getResponseMessage() {
                              return responseMessage;
               }

               public void setResponseMessage(final String responseMessage) {
                              this.responseMessage = responseMessage;
               }
}

  •  Declare a service method inside service class and write the code to process the request and generate the required response.

public class MyWebservices {

    public AuthResult authenticateUserPojo(final UserModel userModel){
                              final String userName = userModel.getUserName();
                              final String pass = userModel.getPassword();
                              final AuthResult authResult = new AuthResult();
                              if(“admin”.equals(userName) && “admin”.equals(pass)) {
                                             authResult.setResponseMessage(“Success”);
                                             authResult.setSessionId("123xyz");
                              } else {
                                             authResult.setResponseMessage(“Failure”);
                              }
                              return authResult;
               }
                }
  •  Add the operation definition into services.xml (needed by framework, visit Axis2 Configs for more details).


<serviceGroup>
   <service name="MyWebservices" targetNamespace="http://webservice.abhinavmishra14.github.com">
.....
....
                             
   <operation name="authenticateUserPojo">
      <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
    </operation>
……
    </service>
</serviceGroup>

  • Generate the WSDL using java2wsdl tool (can be found in axis2 bundle) or write wsdl manually.
  • Build a war file and deploy to application server.
  • Use the wsdl file and create a SOAP UI Project for testing the services or generate client code using wsdl2java tool (can be found in axis2 bundle).

Home work:
1-     Explore about the type of message receivers
2-     Explore service configuration

RAW XML based request and response for SOAP messages:

Before start trying RAW xml based approach, let’s know a little bit about AXIOM.
AXIOM stands for Axis Object Model and refers to the XML model that is developed for Apache Axis2. It is a library within Axis2 framework which is used to deal with XML infoset. XML infoset refers to the information included inside the XML.

Key Features
  • Full XML Infoset compliant XML object model
  • STAX based builders with on-demand building and pull-through
  • XOP/MTOM support offering direct binary support
  • Convenient SOAP Infoset API on top of Axiom
  • Two implementations included (GET, POST)
  • Linked list based implementation
  • W3C DOM supporting implementation
  • Highly performant 
Visit here for detailed information on AXIOM: https://ws.apache.org/axiom/userguide/ch02.html

Know how to create an XML object model: https://ws.apache.org/axiom/userguide/ch02.html#list2

Know how to create an XML object model by parsing an XML file: https://ws.apache.org/axiom/userguide/ch02.html#list1

Know about OMElement (a key class used for preparing XML object model): https://ws.apache.org/axiom/apidocs/org/apache/axiom/om/OMElement.html

Follow the below given steps to create a RAW based service:
  •  Define a Service class. E.g. MyWebservices

public class MyWebservices {

}
  •  Declare a service method inside service class and write the code to process the request and generate the required response.

public class MyWebservices {

  public OMElement authenticateUser(final String userName, final String password) {
    final OMFactory messageFactory = OMAbstractFactory.getOMFactory();
   final OMElement result = messageFactory.createOMElement("resultOfAuthentication", null);
  final OMElement responseMessage =
                                  messageFactory.createOMElement("responseMessage", null);

         if("admin".equals(userName) && "admin".equals(password)) {
responseMessage.setText("Success");
final OMElement sessionId = messageFactory.createOMElement("sessionId", null);
sessionId.setText("123abc");
result.addChild(sessionId);
        } else {
responseMessage.setText("Failure");
         }
         result.addChild(responseMessage);
         return result;
    }
}
  •  Add the operation definition into services.xml (needed by framework, visit Axis2 Configs for more details).

<serviceGroup>
   <service name="MyWebservices" targetNamespace="http://webservice.abhinavmishra14.github.com">
.....
....
                             
   <operation name="authenticateUser">
      <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
    </operation>
……
    </service>
</serviceGroup>
  • Generate the WSDL using java2wsdl tool (can be found in axis2 bundle) or write wsdl manually.
  • Build a war file and deploy to application server.
  • Use the wsdl file and create a SOAP UI Project for testing the services or generate client code using wsdl2java tool (can be found in axis2 bundle).

Home work:
1-     Explore AXIOM library. Visit: http://axis.apache.org/axis2/c/core/docs/om_tutorial.html

RecommendationIt is recommended to always use the latest stable version of Axis2 framework. Current stable version is 1.6.3.  

You can refer to the demo project @ my GitHub repository: 


References:
1- https://axis.apache.org/axis2/java/core/docs/quickstartguide.html
2- http://axis.apache.org/axis2/c/core/docs/