Showing posts with label WSO2 Application Server. Show all posts
Showing posts with label WSO2 Application Server. Show all posts

Saturday, January 12, 2013

JSON pass-through in WSO2 ESB

JSON is a lightweight data exchange format used in many web applications. WSO2 ESB supports sending and receiving JSON messages out-of-the-box. Exposing a SOAP web service over JSON is explained under sample 440 in WSO2 ESB official documentation. This post is to summarize steps of invoking a pass-through proxy service which accepts JSON request, forwards it to a RESTful service and reply back with JSON response (JSON-in, JSON-out).

Pre-requisite:

  • Download and extract the binary distribution of WSO2 ESB-4.5.1
  • I will use WSO2 Application Server-5.0.1 to deploy RESTful backend web service. You can use any server as the backend. However, in order to follow the steps mentioned in this post, you should use WSO2 Application server.

Step 1:

First, we need to setup the backend web service.  We will deploy a JAX-RS based restful service which consumes and produces JSON messages. You can download this RESTful web service(jaxrs_basic.war) from here.

Step 2:

Start WSO2 Application Server, log in to management console and navigate to Manage --> Applications --> List.
You will notice the web applications which are deployed by default in WSO2 Application Server. Since we already have a JAX-RS web app with the name jaxrs_basic, delete the default jaxrs_basic web application.

Now, we can deploy our jaxrs_basic web application (Note that, jaxrs_basic is a modified version of default sample jax-rs web application which has been customized to consume and produce JSON messages).

Go to  Manage --> Applications -->Add --> JAX-WS/JAX-RS.
Upload JAX-WS/JAX-RS Applications page will be shown. Browse the downloaded jaxrs_basic.war and click on upload. New JAX-RS web service will be deployed in WSO2 Application Server.

Step 3:

The auto-generated WADL of the RESTful web service can be obtained by accessing http://<wso2_application_server_hostname>:<wso2_application_server_port>/jaxrs_basic/services/customers?_wadl
From there, you will identify the POST URL of 'customer' resource;

http://<wso2_application_server_hostname>:<wso2_application_server_port>/jaxrs_basic/services/customers/customerservice/customers

We will forward a message to the above URL from WSO2 ESB.

Step 4:

Now we have the backend web service, ready to process messages. Let's create a pass-through proxy service in ESB. Obviously, the endpoint URL will be the one mentioned above.


<proxy xmlns="http://ws.apache.org/ns/synapse" name="jsonproxy" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
<target>
<outSequence>
<send/>
</outSequence>
<endpoint>
<address uri="http://localhost:9764/jaxrs_basic/services/customers/customerservice/customers"/>
</endpoint>
</target>
<description></description>
</proxy>

Either using Pass Through Proxy template in WSO2 ESB management console or using file system, deploy the above proxy service.

Step 5:

Let's send a JSON request to our proxy service. I will use soapUI as usual since it is the best tool out there to invoke web services.

Open soapUI project and add a HTTP request test step to any existing test suite. Change the default method as POST. Enter the proxy service endpoint URL (http://<esb_host_name>:8280/services/jsonproxy) as the Request URL.
Set the media type as application/json and add the following JSON request to POST body text area.

{
"Customer": { "name": "charitha" }
}

Finally, your soapUI request editor will look like the following.

















Submit the request. You will get a JSON response back as shown below. WSO2 ESB will seamlessly forward JSON request to RESTful web service and forward the JSON response to soapUI.

HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
Server: WSO2 Carbon Server
Date: Sat, 12 Jan 2013 13:34:31 GMT
Transfer-Encoding: chunked

{"Customer":{"id":"125","name":"charitha"}}


NOTE:
In the previous versions of ESB (4.0.3 etc), you should add JSON message builders and formatters to ESB_HOME/repository/conf/axis2.xml in order to enable JSON message processing capabilities in ESB. (See http://docs.wso2.org/wiki/display/ESB403/ESB+and+JSON)
However, these builder and formatters are enabled by default in WSO2 ESB version 4.5.1 and later.  In addition to that, you may need to set the following property in IN and OUT paths of proxy services and sequences in previous ESB versions.

<property name="messageType" value="application/json" scope="axis2" />


Thursday, September 20, 2012

How to secure a SOAP web service in WSO2 Application Server and invoke it using HTTP basic authentication with soapUI

In a previous blog post, I explained the steps to deploy a web service in Apache Axis2, secure it with HTTP basic authentication and invoke it using Apache Jmeter.  In this post, we will repeat the same using different set of tools and frameworks which are comparatively easy-to-use and user-friendly.
We will secure a simple SOAP based web service which is hosted in WSO2 Application Server, configure an authentication security policy and invoke the service using HTTP basic auth through soapUI.

Pre-Requisites: 
Download and install WSO2 Application Server-5.0.0 
Download and install soapUI 4.0.1 or later version

Step 1:

Start WSO2 Application Server by running wso2server.sh startup script. Access the management console url (https://localhost:9443/carbon) and log in with the default administrator credentials (username=admin, password=admin)

Step 2:
Go to the Deployed Services page and you will find "HelloService" is deployed by default. Click on the service and go the the service dashboard. Click on Security to configure a security policy for the service. You will find the default set of security policies in the Security for the service page. In order to protect the service with HTTP basic authentication, we can configure Usernametoken security scenario. Username token security policy secures the service using username and password. Select UsernameToken security scenario and click on Next. Select admin as the user group which need to be authenticated. Click Finish to complete the security policy configuration.

Step 3:
Now, if you check the WSDL of the web service, you will see a WS-Security policy is added to the WSDL. Therefore, if you send a SOAP request, it must include the necessary WS-Security headers.
You can read one of my previous blog posts to see how you can send a secure SOAP request to a service using soapUI.
The beauty of WSO2 Application Server is, it allows you to send a HTTP GET request with basic authentication headers to the same web service. Let's see how we can send a HTTP GET request to invoke the above HelloService which has been secured with Username Token security policy.

Step 4:
Open soapUI.   Click on File --> New soapUI Project. Enter a name for the project. Select Create Web TestCase option (We are not going to deal with any SOAP messages, therefore we do not want to create usual soapUI project using a WSDL). This will open Add Web TestCase dialog. Enter the following URL as the web address.
Web address = https://localhost:9443/services/HelloService/greet?name=soapUI

Note that, this is the url of the GET request which we are going to submit.











Step 5:

Once you click on OK in the above dialog, soapUI will open an HTTP request editor with the above request URL. Click on Request tab to move into the request editor if you ended up in the response tab.
Click on Aut tab where you can specify user credentials. Enter the following credentials of admin user which we used to secure HelloService at the step 2.

Username=admin
Password=admin


















Step 6:

Before invoking the service, make sure Authenticate Preemptively option is selected at the HTTP Settings of soapUI Preferences dialog (File --> Preferences --> HTTP Settings --> Authenticate Preemptively).
Now, submit the request. You will see the following in the raw view of request.


GET https://localhost:9443/services/HelloService/greet?name=soapUI HTTP/1.1
Accept-Encoding: gzip,deflate
Authorization: Basic YWRtaW46YWRtaW4=
User-Agent: Jakarta Commons-HttpClient/3.1
Host: localhost:9443

And, the response will be similar to the following.


HTTP/1.1 200 OK
Content-Type: application/xml;charset=UTF-8
Transfer-Encoding: chunked
Content-Encoding: gzip
Vary: Accept-Encoding
Date: Thu, 20 Sep 2012 08:38:31 GMT
Server: WSO2 Carbon Server

Hello World, soapUI !!!


Thursday, September 13, 2012

Setting up minimum deployment of WSO2 product cluster with management/worker separation

The latest version of WSO2 Carbon (Carbon-4.0.0) platform (WSO2 ESB-4.5.0, WSO2 Application Server-5.0.0, WSO2 Governance Registry - 4.5.0 etc) supports a new deployment model which allows you to setup product clusters with separated worker and management nodes. In a worker/manager separated cluster setup, the management node(s) is used to deploy and configure the deployment artifacts where as the worker nodes are used to serve the requests received by clients.
I'm not going to spend much time on a detailed explanation about this new deployment approach since my objective is to take you through the minimum worker/manager deployment setup of WSO2 Application Server cluster as quickly as possible. You can find more about the theoretical aspects of this new deployment model in Afkham Azeez's blog.

Deployment diagram



















We are going to setup the minimum cluster setup in our local machines. Thus, we will use 3 product instances as follows.

Load Balancer - used to load balance the requests between Application Server cluster nodes.
WSO2 Application Server management node - all deployments and configurations are performed through this node.
WSO2 Application Server worker node - Application server requests are served by this node.

Pre-requisites:

Download the latest version (5.0.0) of WSO2 Application Server from here.
Download the latest version(2.0.0) of WSO2 Elastic Load Balancer from here.

Setting up WSO2 Elastic Load Balancer


Step 1:
Extract wso2elb-2.0.0.zip into a directory in your local file system. Let the extracted directory be WSO2_LB_HOME

Step 2:
Go to WSO2_LB_HOME/repository/conf and edit the loadbalancer.conf as follows.

appserver {
domains {
CharithaASdomain {
hosts mgt.charitha.appserver.wso2.com;
sub_domain mgt;
tenant_range *;

}
CharithaASdomain {
hosts charitha.appserver.wso2.com;
sub_domain worker;
tenant_range *;
}

}
}

As you can see above, we have defined two cluster sub domains, mgt and worker under a single clustering domain which is named as "CharithaASdomain".
Both these sub domains consists of one WSO2 Application server instance in each. mgt sub domain includes the management node of our cluster and the worker sub domain consists of a worker node. (See the deployment diagram above).
The two WSO2 Application Server instances (in our case cluster sub domains, because each sub domain has only one instance) can be setup in two physical servers, 2 VM instances or a single machine. In our example, we will set everything up in our local machine. In order to identify the two nodes uniquely, we will define hostnames for both. Therefore, mgt subdomain will be identified using mgt.charitha.appserver.wso2.com and the worker subdomain will be identified by  charitha.appserver.wso2.com
Since we are running everything in local machine, let's update the /etc/hosts file to match up with the hostnames we use.

127.0.0.1 mgt.charitha.appserver.wso2.com
127.0.0.1 charitha.appserver.wso2.com

Step 3: 
Uncomment localMemberHost element in WSO2_LB_HOME/repository/conf/axis2/axis2.xml and specify the IP address (or host name) which you are going to advertise to the members of the cluster.

<parameter name="localMemberHost">127.0.0.1</parameter>

Save loadbalancer.conf, axis2.xml and /etc/hosts files.

The above are the only configurations which need to be done in WSO2 LB. You do not have to configure anything in other configuration files in the minimum deployment setup.
Now, start WSO2 Load Balancer by running wso2server.sh script which can be found at WSO2_LB_HOME/bin. You will see the following logs at server startup.

[2012-09-13 20:04:08,407]  INFO - TribesClusteringAgent Managing group application domain:CharithaASdomain, sub-domain:mgt using agent class org.wso2.carbon.lb.endpoint.SubDomainAwareGroupManagementAgent
[2012-09-13 20:04:08,408] INFO - TribesClusteringAgent Managing group application domain:CharithaASdomain, sub-domain:worker using agent class org.wso2.carbon.lb.endpoint.SubDomainAwareGroupManagementAgent
[2012-09-13 20:04:08,410] INFO - ServerManager Server ready for processing...
[2012-09-13 20:04:08,483] INFO - AutoscalerTaskServiceComponent Autoscaling is disabled.
[2012-09-13 20:04:08,537] INFO - PassThroughHttpSSLListener Starting Pass-through HTTPS Listener...
[2012-09-13 20:04:08,550] INFO - PassThroughHttpSSLListener Pass-through HTTPS Listener started on port : 8243
[2012-09-13 20:04:08,550] INFO - PassThroughHttpListener Starting Pass-through HTTP Listener...
[2012-09-13 20:04:08,555] INFO - PassThroughHttpListener Pass-through HTTP Listener started on port : 8280
[2012-09-13 20:04:08,557] INFO - TribesClusteringAgent Initializing cluster...
[2012-09-13 20:04:08,583] INFO - TribesClusteringAgent Cluster domain: wso2.as.lb.domain
[2012-09-13 20:04:08,587] INFO - TribesClusteringAgent Using wka based membership management scheme
[2012-09-13 20:04:08,599] INFO - WkaBasedMembershipScheme Receiver Server Socket bound to:/127.0.0.1:4000
[2012-09-13 20:04:08,699] INFO - WkaBasedMembershipScheme Receiver Server Socket bound to:/127.0.0.1:4000
[2012-09-13 20:04:08,846] INFO - TribesClusteringAgent Local Member 127.0.0.1:4000(wso2.as.lb.domain)
[2012-09-13 20:04:08,847] INFO - TribesUtil No members in current cluster
[2012-09-13 20:04:08,849] INFO - TribesClusteringAgent Cluster initialization completed.
[2012-09-13 20:04:09,412] INFO - StartupFinalizerServiceComponent WSO2 Carbon started in 14 sec

Let's proceed with configuring WSO2 Application Server management node.

Setting up WSO2 Application Server Management Node


Step 1:

Extract wso2as-5.0.0.zip into a directory in your local file system. Let the extracted directory be WSO2_AS_MGR_HOME.

Step 2 (axis2.xml configuration):

First, we need to enable clustering at axis2 level in order for management node to communicate with load balancer and the worker nodes. Open  WSO2_AS_MGR_HOME/repository/conf/axis2/axis2.xml and update the clustering configuration as shown below.

<clustering class="org.apache.axis2.clustering.tribes.TribesClusteringAgent" enable="true">

<parameter name="membershipScheme">wka</parameter>

Specify the cluster domain. Note that, this must be the same which we defined in loadbalancer.conf

<parameter name="domain">CharithaASdomain</parameter>

<parameter name="localMemberHost">mgt.charitha.appserver.wso2.com</parameter>

<parameter name="localMemberPort">4250</parameter>

We will add a new property "subDomain" and set it to "mgt" to denote that this node belongs to mgt subdomain of the cluster as we defined in loadbalancer.conf.
  <parameter name="properties">
<property name="backendServerURL" value="https://${hostName}:${httpsPort}/services/"/>
<property name="mgtConsoleURL" value="https://${hostName}:${httpsPort}/"/>
<property name="subDomain" value="mgt"/>

</parameter>

Now, add load balancer IP or host name (in our case, we will refer to the load balancer using 127.0.0.1 and the local member port (4000) as defined in the axis2.xml of WSO2 LB) as a well-known member.
<members>
<member>
<hostName>127.0.0.1</hostName>
<port>4000</port>
</member>
</members>

Step 3 - catalina-server.xml configuration:
WSO2 Application Server management node is fronted by Load Balancer. Therefore, we need to configure the proxy ports which are associated with HTTP and HTTPS connectors. These proxy ports are the corresponding transport receiver ports opened by WSO2 LB (configured in transport listeners section in axis2.xml).
Open WSO2_AS_MGR_HOME/repository/conf/tomcat/catalina-server.xml and add the proxyPort attribute for both HTTP and HTTPS connectors as shown below.

<Connector  protocol="org.apache.coyote.http11.Http11NioProtocol"
port="9763"
proxyPort="8280"

 <Connector  protocol="org.apache.coyote.http11.Http11NioProtocol"
port="9443"
proxyPort="8243"

Step 4 - carbon.xml configuration:

Since we run multiple WSO2 Carbon based products in same host, we must avoid the possible port conflicts. Therefore, edit the following element in WSO2_AS_MGR_HOME/repository/conf/carbon.xml by assigning port offset 1 to the Application Server management node.

<Offset>1</Offset>

Update mgtHostName and HostName elements in carbon.xml as shown below.

<HostName>charitha.appserver.wso2.com</HostName>

<MgtHostName>mgt.charitha.appserver.wso2.com</MgtHostName>

We must do one more configuration change in carbon.xml before moving to the next step. As we discussed at the beginning, Application Server management node is used for deploying artifacts such as web applications and web services. The deployed artifacts in management node must be synchronized automatically to the worker nodes in cluster. This deployment synchronization mechanism is pretty straight-forward in WSO2 Carbon based products.  The default SVN based deployment synchronizer can be used to auto-commit the deployment artifacts to a pre-configured SVN repository. Then, the worker nodes can be configured to automatically check-out the artifacts from the same SVN location.

Let's configure SVN based deployment synchronizer in carbon.xml of management node.
<DeploymentSynchronizer>
<Enabled>true</Enabled>
<AutoCommit>true</AutoCommit>
<AutoCheckout>true</AutoCheckout>
<RepositoryType>svn</RepositoryType>
<SvnUrl>http://10.100.3.115/svn/repos/as</SvnUrl>
<SvnUser>wso2</SvnUser>
<SvnPassword>wso2123</SvnPassword>
<SvnUrlAppendTenantId>true</SvnUrlAppendTenantId>
</DeploymentSynchronizer>

Make sure to replace the SvnUrl, SvnUser and SvnPassword according to your SVN repository.

Step 5: Starting the management node of WSO2 Application Server cluster

Go to WSO2_AS_MGR_HOME/bin and run wso2server.sh to start the server. During the server startup, you should see cluster initialization messages similar to the following.

[2012-09-13 23:04:25,820]  INFO {org.apache.axis2.clustering.tribes.TribesClusteringAgent} -  Initializing cluster...
[2012-09-13 23:04:25,840] INFO {org.apache.axis2.clustering.tribes.TribesClusteringAgent} - Cluster domain: CharithaASdomain
[2012-09-13 23:04:25,843] INFO {org.apache.axis2.clustering.tribes.TribesClusteringAgent} - Using wka based membership management scheme
[2012-09-13 23:04:25,852] INFO {org.apache.axis2.clustering.tribes.WkaBasedMembershipScheme} - Receiver Server Socket bound to:/127.0.0.1:4250
[2012-09-13 23:04:25,960] INFO {org.apache.axis2.clustering.tribes.WkaBasedMembershipScheme} - Added static member 127.0.0.1:4000(CharithaASdomain)


At the same time, look at the logs of Load Balancer.

[2012-09-13 23:04:41,012]  INFO - RpcMembershipRequestHandler Received JOIN message from 127.0.0.1:4250(CharithaASdomain)
[2012-09-13 23:04:41,012] INFO - MembershipManager Application member 127.0.0.1:4250(CharithaASdomain) joined group CharithaASdomain
[2012-09-13 23:04:41,013] INFO - ClusterManagementMode Member 127.0.0.1:4250(CharithaASdomain) joined cluster
[2012-09-13 23:04:52,016] INFO - DefaultGroupManagementAgent Application member Host:127.0.0.1, Port: 4250, HTTP:9764, HTTPS:9444, Domain: CharithaASdomain, Sub-domain:mgt, Active:true joined application cluster

By looking at the above logs, we can conclude that Application Server management node has successfully joined cluster and ready to receive requests through the load balancer.
Now, we can log in to the management console of the Application Server management node. Access https://mgt.charitha.appserver.wso2.com:8243/carbon/ and log in to the management console with the default administrator credentials (admin/admin). Go to the "Deployed Services" page and click on WSDL1.1 link of the HelloService. You will get an HTTP 500 error since the server looks for the URL, http://charitha.appserver.wso2.com:8280/services/HelloService?wsdl, which is not yet available. As you can see from this URL, though the service is deployed in the management node, all requests are served by the worker nodes. charitha.appserver.wso2.com is the hostname which we have given for the worker node and we have not started the worker node yet.


Setting up WSO2 Application Server Worker node


Since we have completed setting up the management node, worker node configuration is quite straight-forward. Let's configure the worker node in our local machines.

Step 1:
We are not going to extract another fresh version of wso2as-5.0.0.zip. Instead, make a copy of the management node into a different directory, so that we can reuse most of the settings which we used above. Rename the directory as wso2as-5.0.0-worker. Let this directory be WSO2_AS_WORKER_HOME.

Step 2 - axis2.xml configuration:
In addition to the changes which we did in axis2.xml of the management node, there are few modifications need to be done for worker. First, we update localMemberPort element since we launch two instances of cluster nodes in the same machine. Open WSO2_AS_WORKER_HOME/repository/conf/axis2/axis2.xml and edit the following element.

<parameter name="localMemberPort">4251</parameter>

Application Server worker node belongs to the "worker" sub domain of the cluster domain as we have configured in loadbalancer.conf of WSO2 Load Balancer. As we did with the management node, we can add a new property, "subDomain" as follows to represent this.

<parameter name="properties">
<property name="backendServerURL" value="https://${hostName}:${httpsPort}/services/"/>
<property name="mgtConsoleURL" value="https://${hostName}:${httpsPort}/"/>
<property name="subDomain" value="worker"/>
</parameter>

Step 3: carbon.xml configuration:

First, we should specify a new port offset for the worker node. Edit WSO2_AS_WORKER_HOME/repository/conf/carbon.xml and update the portOffset value as follows.

 <Offset>2</Offset>

Also, update the HostName element as shown below. We do not need to specify MgtHostName element since this node is designated as the worker node in Application Server cluster.

<HostName>charitha.appserver.wso2.com</HostName>

Now, we need to configure the SVN based deployment synchronizer to automatically check-out deployment artifacts from a common SVN repository. The worker nodes of a cluster SHOULD NOT commit (write) artifacts hence we must disable AutoCommit property in the deployment synchronizer configuration as shown below.

<DeploymentSynchronizer>
<Enabled>true</Enabled>
<AutoCommit>false</AutoCommit>
<AutoCheckout>true</AutoCheckout>
<RepositoryType>svn</RepositoryType>
<SvnUrl>http://10.100.3.115/svn/repos/as</SvnUrl>
<SvnUser>wso2</SvnUser>
<SvnPassword>wso2123</SvnPassword>
<SvnUrlAppendTenantId>true</SvnUrlAppendTenantId>
</DeploymentSynchronizer>

Step 4: Start WSO2 Application Server Worker node

We are ready to start the worker node of our cluster. Go to WSO2_AS_WORKER_HOME/bin and start the server as follows. Note that, the workerNode system property must be set to true when starting the workers in a cluster.

sh wso2server.sh -DworkerNode=true

Once the worker node joins the cluster, you will see the following messages in WSO2 Load Balancer logs.
[2012-09-14 06:32:41,050]  INFO - RpcMembershipRequestHandler Received JOIN message from 127.0.0.1:4251(CharithaASdomain)
[2012-09-14 06:32:41,051] INFO - MembershipManager Application member 127.0.0.1:4251(CharithaASdomain) joined group CharithaASdomain
[2012-09-14 06:32:44,387] INFO - ClusterManagementMode Member 127.0.0.1:4251(CharithaASdomain) joined cluster
[2012-09-14 06:32:52,052] INFO - DefaultGroupManagementAgent Application member Host:127.0.0.1, Port: 4251, HTTP:9765, HTTPS:9445, Domain: CharithaASdomain, Sub-domain:worker, Active:true joined application cluster

Testing the cluster

There are many ways to test our cluster deployment. Let's follow the simplest path. 

- Log in to the management console of Application Server management node 
- Deploy a new Axis2 Web service (Go to Manage --> Axis2 Services --> Add --> AAR service)
- Once the service is deployed in the management node go to the services list and click on Tryit
- Invoke the service

You will notice that the requests are served by the worker node of the cluster. If you click on WSDL1.1 link of any service, the WSDL will be served by the worker (http://charitha.appserver.wso2.com:8280/services/HelloService?wsdl)

Let me know if you come across any issues when setting up the cluster. 

Saturday, January 21, 2012

Truly RESTful Services using Apache Wink and WSO2 Application Server









Apache Wink is a complete implementation of JAX-RS v-1.1 specification. JAX-RS is a java API which supports creating web services in RESTful manner.

WSO2 Application Server is the enterprise-ready, scalable web services and web app hosting platform powered by Apache Axis2 and Apache Tomcat.

In this post, we are going to create a RESTful web service using Apache wink libraries and deploy it in WSO2 Application Server. If we summarize the steps that we are going to do in this example;

1. Create a JDBC data source (mySQL)

2. Create the web service with JAX-RS annotations which makes use of the above database

3. Create a web application (war) with apache wink libraries

4. Deploy the web app in WSO2 Application Server



WSO2 provides application developers with a complete middleware platform in cloud. Therefore, we makes use of WSO2 StratosLive PaaS (Platform as a Service) as our development platform. In other words, we are NOT even going to install mySQL or WSO2 Application server in our machines to try this sample out. We will create the database in cloud and host web application in the cloud.



Without discussing further. lets start our journey.



Step 1



We are going to create a primitive customer registration application which consists of a mySQL database with one table called customer. We need to create the DB schema.

WSO2 Stratos middleware platform in cloud allows us to have our own data storage in cloud within seconds. As I explained in this post, all we have to do is;

- Register a new tenant

- Log into https://stratoslive.wso2.com

- Access DataServices Server

- Create a database and a table



CREATE TABLE CUSTOMER_T(customerID int, customerName varchar(100), customerAge int, customerAddress varchar(200));



Once the database and table is created, note the DB connection URL. In my case, it is,

jdbc:mysql://rss1.stratoslive.wso2.com/wink_superqa_com



Step 2



Now, our application data source is ready for use. As I have explained before, we are going to create a customer registration web service which includes all CRUD operations associated with above DB schema. In other words, we can add, delete, read and update customers using the web service. We will implement our webservice in completely RESTful manner so that we makes use of HTTP verbs to invoke service.

Therefore, lets create the Customer bean first. Open your favorite Java IDE and add Customer class with the following properties and associated getters and setters. The complete class can be found at https://wso2.org/repos/wso2/trunk/commons/qa/qa-artifacts/app-server/rest/jaxrs-sample/src/com/beans/Customer.java



public class Customer {

private int customerID;

private String customerName;

private String customerAddress;

private int customerAge;





Step 3



We will use a separate class to handle all communication with the database which we created above. Lets name the class as Storage.java and implement all CRUD operations.



public class Storage {



Connection connection = null;

Statement statement = null;

ResultSet rs = null;



private Connection getConnection() {

String driverName = "com.mysql.jdbc.Driver";

String conectionURI = "jdbc:mysql://rss1.stratoslive.wso2.com/wink_superqa_com";

String userName = "ck_l96225fe";

String password = "ck";





try {

Class.forName(driverName);

try {

connection = DriverManager.getConnection(conectionURI, userName, password);

} catch (SQLException e) {

e.printStackTrace();

}

try {

connection.setAutoCommit(true);

} catch (SQLException e) {

e.printStackTrace();

}



} catch (ClassNotFoundException e) {

e.printStackTrace();

}



return connection;

}



//CREATE operation

public void addCustomer(Customer customer) {





try {

connection = getConnection();

statement = connection.createStatement();



String sqlStatement = "INSERT INTO CUSTOMER_T VALUES (" + customer.getCustomerID()

+ ",'" + customer.getCustomerName() + "', " + customer.getCustomerAge() + ",'" + customer.getCustomerAddress() + "')";

statement.execute(sqlStatement);



} catch (SQLException e) {



} finally {

if (statement != null) {

try {

statement.close();

} catch (SQLException e) {

e.printStackTrace();

}

}



if (connection != null) {

try {

connection.close();

} catch (SQLException e) {



e.printStackTrace();

}

}

}





}



Similarly, add the other methods to UPDATE, DELETE and READ operations. The complete Storage.java class can be found here.



Step 4



Now, we can implement our web service. We are going to use JAX-RS annotations to make our web service completely RESTful. Download Apache wink distribution from here and add WINK_HOME/dist and WINK_HOME/lib to class path of your IDE.

We will have four methods to demonstrate the basic HTTP methods.



  • addCustomer() method is used to add a new customer to the system. We use a HTTP POST request to send the customer details to the web service method.
  • getCustomerName() is just a HTTP GET operation which reads the CUSTOMER_T table and send back the name of the customer associated with given customer ID.
  • updateCustomer() method updates the customer address of the given customer
  • deleteCustomer() method removes a customer record from the table
In JAX-RS, we can define the root resource with @Path annotation as shown below. So, when you send a HTTP request to /qa, it will be directed to the associated class.



@Path("/qa")

public class CustomerService {}



Now, we need to implement the methods associated with CRUD operations. First lets look at addCustomer method. As we defined the root resource at the class declaration level, we can define subresource methods to handle the common HTTP methods. Here, addCustomer is a subresource method and we annotate it with @POST to direct POST requests which are targeted to '/qa' root resource. @Path annotation at the sub resource level resolves the URL path which is targeted to the method. In otherwords, if the request URL is, /qa/customer and the HTTP method is POST, the request is dispatched to addCustomer() method.



@POST

@Consumes("application/x-www-form-urlencoded")

@Path("/customer")

public void addCustomer(@FormParam("customerid") int customerID, @FormParam("customername") String customerName, @FormParam("customerage") int customerAge, @FormParam("customeraddress") String customerAddress){



Storage storage = new Storage();

Customer customer = new Customer();

customer.setCustomerID(customerID);

customer.setCustomerName(customerName);

customer.setCustomerAge(customerAge);

customer.setCustomerAddress(customerAddress);

storage.addCustomer(customer);





}





Also, make a note of the @Consumes annotation, here we define the Content-Type which must be included in the HTTP POST request. In our example, if a POST request to '/qa/customer' is issued with "application/x-www-form-urlencoded" Content-Type, the addCustomer() method will be invoked. If we send any other content in the POST request, this method will not get invoked.



We also use annotated parameters to pass some additional information with a request. For example we can use query parameters, path parameters etc and process them accordingly. In our example, we use @FormParm parameter to extract parameter values from the form posts.



Similarly, we can implement the other methods in our service implementation class.



@GET

@Path("/customer/{customerid}")

@Produces("text/plain")

public String getCustomerName(@PathParam("customerid") int customerID) {

Storage storage = new Storage();

Customer customer = null;

try {

customer = storage.getCustomerDetails(customerID);

} catch (SQLException e) {

e.printStackTrace();

}

return customer.getCustomerName();

}





@PUT

@Consumes("application/x-www-form-urlencoded")

@Path("/customer")

public void updateCustomer(@FormParam("customername") String customerName, @FormParam("customeraddress") String customerAddress){



Storage storage = new Storage();

storage.updateCustomer(customerName, customerAddress);





}



@DELETE

@Path("/customer/{customerid}")



public void deleteUser(@PathParam("customerid") int customerID) {



Storage storage = new Storage();

storage.deleteCustomer(customerID);



}





Step 5



We have completed the implementation of our web service class with JAX-RS annotations. Apache wink needs us to create a sub-class of javax.ws.rs.core.Application if we deploy deploy our application on non-JAX-RS aware containers. At the time of writing, WSO2 Application Server is not JAX-RS aware hence we need to create this particular subclass. This class basically returns the root resource(s).



public class CustomerResourceApplication extends Application {



@Override

public Set> getClasses() {

Set> classes = new HashSet>();

classes.add(CustomerService.class);



return classes;



}

}





Step 6



Next, we need to create the web.xml file for our web application. In addition to the standard constructs in web.xml, we should define that the Apache wink JAX-RS servlet should be initialized with an instance of the above CustomerResourceApplication.



We also define that the requests begin with '/rest/' will be handled by Apache Wink JAX-RS servlet.



<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE web-app PUBLIC

"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>

<display-name>Restful service Test Web Application</display-name>

<servlet>

<servlet-name>CustomerServlet</servlet-name>

<servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class>

<init-param>

<param-name>javax.ws.rs.Application</param-name>

<param-value>com.sample.CustomerResourceApplication</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>CustomerServlet</servlet-name>

<url-pattern>/rest/*</url-pattern>

</servlet-mapping>

</web-app>





Step 7



We are done with our web application now. Create a war with the above classes as well as apache wink libraries. Make sure to place all jars included in WINK_HOME/dist and WINK_HOME/lib in WEB-INF/lib of the web application. You can use the ant build script given here to do all these stuff.



Step 8



Once the web application (CustomerService.war) is ready, log in to https://appserver.stratoslive.wso2.com with your tenant credentials and upload the web application. (Please read my blog post on Apache Tomcat As a Service if you want to know how WSO2 application Server can be used in web app deployment)



Step 9



Finally, we can invoke each of the operations of our web service in truly RESTful manner using a client application such as curl.



HTTP POST:

curl --data "customerid=1&amp;customername=charitha&amp;customerage=33&amp;customeraddress=piliyandala" -X POST -H "Content-Type: application/x-www-form-urlencoded"http://appserver.stratoslive.wso2.com/t/superqa.com/webapps/CustomerService/rest/qa/customer





HTTP GET:

curl -X GET http://appserver.stratoslive.wso2.com/t/superqa.com/webapps/CustomerService/rest/qa/customer/1





HTTP PUT:

curl --data "customername=charitha&amp;customeraddress=colombo" -X PUT -H "Content-Type: application/x-www-form-urlencoded" http://appserver.stratoslive.wso2.com/t/superqa.com/webapps/CustomerService/rest/qa/customer



HTTP DELETE:

curl -X DELETE http://appserver.stratoslive.wso2.com/t/superqa.com/webapps/CustomerService/rest/qa/customer/1

Tuesday, April 12, 2011

How to send JSON messages to web services deployed on WSO2 Application Server

JSON (JavaScript Object Notation) is an open and text-based data exchange format, that provides a standardized data exchange format better suited for Ajax style web applications. You can find more information about JSON from www.json.org
WSO2 SOA middleware platform supports sending and receiving JSON messages.
This post takes you through the steps to deploy a simple web service in WSO2 Application Server and write a client using Axis2 ServiceClient API to invoke the service by sending JSON message.

Pre-requisites:
Download and install WSO2 Application Server 4.0.0 or later

Step 1
We are using a simple web service, which echo's user input as follows.

public class EchoService {

public OMElement echo(OMElement element) {
return element;
}
}

You can download the service archive (EchoService.aar) from here and deploy on WSO2 Application Server.

Step 2

Have a look at CARBON_HOME/repository/conf/axis2.xml (CARBON_HOME is the root directory of WSO2 Application Server). You will notice that the JSON specific message builders and formatters are enabled by default.

<!--JSON Message Formatters-->
<messageFormatter contentType="application/json"
class="org.apache.axis2.json.JSONMessageFormatter"/>
<messageFormatter contentType="application/json/badgerfish"
class="org.apache.axis2.json.JSONBadgerfishMessageFormatter"/>
<messageFormatter contentType="text/javascript"
class="org.apache.axis2.json.JSONMessageFormatter"/>

<!--JSON Message Builders-->
<messageBuilder contentType="application/json"
class="org.apache.axis2.json.JSONOMBuilder"/>
<messageBuilder contentType="application/json/badgerfish"
class="org.apache.axis2.json.JSONBadgerfishOMBuilder"/>
<messageBuilder contentType="text/javascript"
class="org.apache.axis2.json.JSONOMBuilder"/>

WSO2 Application Server accepts any JSON message with the content type application/json, application/json/badgerfish or text/javascript. In this example, we will use a message with the content-type, application/json

Step 3

Now, If you invoke the service using the Tryit utility associated with EchoService and trace the message, you will notice the payload of the SOAP message as follows.

<p:echo xmlns:p="http://service.carbon.wso2.org">
<echo xmlns="http://service.carbon.wso2.org" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">charitha</echo>
</p:echo>

Basically, the message payload will be similar to the following.

<echo>
<value>charitha</value>
</echo>

Step 4

Now, we are going to send the above payload as a JSON message. The JSON format of the above message payload will be as follows.

{"echo":{"value":"charitha"}}

Add the following class to your java project. Compile it using the libraries included in CARBON_HOME/repository/component/plugins directory. You may also need to add CARBON_HOME/lib/endorsed into your class path.

package org.wso2.carbon.service;

import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.methods.StringRequestEntity;

public class JSONClient {

public static void main(String[] args) throws Exception {
String strURL = "http://localhost:8281/services/JSONProxy/"; PostMethod post = new PostMethod(strURL); RequestEntity entity = new StringRequestEntity("{\"echo\":{\"value\":\"charitha\"}}","application/json", "UTF-8"); post.setRequestEntity(entity); HttpClient httpclient = new HttpClient(); try { int result = httpclient.executeMethod(post); System.out.println("Response status code: " + result); System.out.println("Response body: "); System.out.println(post.getResponseBodyAsString()); } finally { post.releaseConnection(); } }
}

You could use the same axis2.xml located at CARBON_HOME/repository/conf as the client axis2.xml when creating ConfigurationContext

If you forward the message to tcpmon and trace it, you will see the request as follows.

POST /services/EchoService HTTP/1.1
Content-Type: application/json; charset=UTF-8
User-Agent: WSO2 WSAS-3.2.0
Host: 127.0.0.1:9764
Transfer-Encoding: chunked

1d
{"echo":{"value":"charitha"}}
0

Tuesday, January 25, 2011

How to enable child-first class loading in WSO2 Application Server or Axis2

By default, WSO2 Application Server (or Axis2) uses parent-first class loading mechanism.
If you deploy an AAR service, which can load classes from the following locations.


  • CARBON_HOME/lib (CARBON_HOME is the location where you installed WSO2 Application Server)
  • CARBON_HOME/repository/deployment/server/axis2services/lib
  • AAR service/lib (lib directory under your service archive)


If your service implementation class has a package import for a class, which is available in both CARBON_HOME/repository/deployment/server/axis2services/lib and the lib directory under service archive, the class placed under CARBON_HOME/repository/deployment/server/axis2services/lib will get loaded.
Which means, the parent class always get loaded first.
The class loading sequence is CARBON_HOME/lib ---> CARBON_HOME/repository/deployment/server/axis2services/lib -----> AAR service/lib


Sometimes, we want to load the class from service archive lib first without loading the class which is available either one of above parent locations. In other words, child-first class loading will be required for some instances.
child-first class loading can be enabled simply by adding the following parameter in to services.xml in your service archive.


<parameter name="EnableChildFirstClassLoading">true</parameter>


If you set this parameter in axis2.xml of your WSO2 Application Server (or Axis2) instance, all services will use child-first class loading mechanism.


Wednesday, January 19, 2011

WS-Addressing with SOAPUI

WS-Addressing is a standard way of including message routing data within SOAP headers without relying on transport specific routing properties. If you are talking to a web service which expects WS-Addressing information in request SOAP messages, you could either follow a programmatic approach to write a client and insert WS-A headers manually or use a commercial or free web service client tool. SOAPUI is the simplest tool which can be used to insert WS-Addressing headers in to request SOAP messages.
In this blog post, we will;
  • Talk to a WS-Addressing enabled service which is hosted in WSO2 Application Server using SOAPUI
  • Assert response SOAP message to validate WS-A headers
Pre-requisites:

1. Download and install the free version of SOAPUI 3.0.1 or later
2. Download and install WSO2 Application Server 4.0

Step 1

We are going to invoke the default HelloService which is shipped with WSO2 Application Server. Go to WSO2_APPSERVER/home/bin and start the server by running wso2server.sh{bat}
Access management console with https://localhost:9443/carbon and log in using the default administrator credentials (username=admin, password=admin)
Navigate to Manage --> Services --> List in the left menu and select "HelloService"
You will be directed to the dashboard of HelloService. Click on Modules link.



You will notice that "addressing-3.1.0" is listed under "Globel Level". By default WS-Addressing is enabled for all the services hosted in WSO2 Application Server. Therefore, you do not have to configure anything at the server side to enable WS-Addressing.

Step 2

Now, we will create a new SOAPUI project referring to http://localhost:9763/services/HelloService?wsdl as follows. Make sure to select "Create Test Suite" check box as well.



After creating the project, select greet request under HelloServiceSoap11Binding TestSuite



If you click on run just by providing input string, you will notice that WS-A headers will not be included in the request SOAP message which can be observed if you toggle "Raw" option.

Step 3

Lets add WS-A headers in to the request SOAP message. Select greet request and click on WS-A option and select the following properties.

Enable WS-A addressing

Add default wsa:Action


Add default wsa:To


Randomly generated message ID




Keep the rest of the default values and click on run. You will notice the following WS-A headers in the request message if you look at the raw message in SOAPUI.

<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Action>urn:greet</wsa:Action>
<wsa:MessageID>uuid:1fa996ca-755b-486c-a2ed-aa14bbf663a3</wsa:MessageID>
<wsa:To>http://localhost:9763/services/HelloService.HelloServiceHttpSoap11Endpoint/</wsa:To>
</soapenv:Header>

Also, the response headers will be similar to the following.

<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Action>urn:greetResponse</wsa:Action>
<wsa:RelatesTo>uuid:1fa996ca-755b-486c-a2ed-aa14bbf663a3</wsa:RelatesTo>
</soapenv:Header>

Simple.. isn't it? we just invoked a service with WS-Addressing headers using SOAPUI.

Here, we manually verified that the response message includes the correct WS-A headers. We looked at the response message and verified each header. If you maintain an automated test suite to verify your web service interactions, the above procedure cannot not be considered as over until you add an assertion so that the test automatically reports the correctness or failures of response/request messages.

Step 4

Now, we will add an assertion to validate response headers. In this example, we are going to add an XPath match assertion to check whether the wsa:Action header of the response equals to urn:greetResponse

Click on Assertions option and select "Add an assertion to this item" icon. Then select, XPAth Match as the assertion.



Next, you should specify the XPath expression and expected result as follows. First, click on Declare button which will automatically define the namespaces. Specify //wsa:Action as the xpath. Also, specify urn:greetResponse as the expected result.



Run the test again. You will notice that the test will be marked in green denoting that the test is successful.

Tuesday, December 14, 2010

WSO2 Application Server - Run web applications and web services on the same server

Today WSO2 released its newest product (rather a renamed version of WSO2 web services application server - WSAS, with a lot of improvements), WSO2 Application Server - 4.0.0
WSO2 Application server is an unified platform to host web services and web applications together. This completely open-source product is based on world's most popular web application server, Apache Tomcat and No:1 web service engine, Apache Axis2.

WSO2 Application Server is part of WSO2 Carbon platform hence it brings the power of highly flexible component model hence your web applications can utilize the features provided by carbon platform. For example, web applications can be authorized using WSO2 identity and user management components. As the other WSO2 products, WSO2 application server comes with a rich graphical management console which allows you to manage your web applications very easy and effective manner.

Lets have a glance at WSO2 Application Server......

Step 1
Download WSO2 Application Server-4.0.0 binary distribution from wso2 oxygen tank
Extract the downloaded binary. We will refer to the downloaded directory as CARBON_HOME

Step 2

Go to CARBON_HOME/bin directory and run wso2server.sh {bat}
Once the server is started, access management console using https://localhost:9443/carbon
Log in to management console using the admin credentials (username= admin, password=admin)



Step 3

At the main menu, you will find, Manage --> Web Application option. You can upload new web apps or view the existing web applications in there.
Click on Manage --> Web Applications --> Add
You will be directed to web app uploading screen where you can upload any war file.



Browse for a web application archive (war) in your file system and click on upload. You will be prompted with the confirmation message if the deployment is successful.

Step 4

Once the web app deployment is done, it will be listed in Running Web Applications page as shown below.



If you click on web application context in the web app list, you will be directed to web app dashboard as follows. You can carry out multiple operations on the deployed web app within this dashboard. For example, you can reload web app, expire all sessions etc..



Step 5

As I described at the beginning, you can deploy various kind of web services together with web applications using WSO2 Application Server. You will find Manage --> Services menu option at the left navigation pane in management console, there you will see Axis2 Servces, Jar Services, Spring Services and JAX-WS service deployment options as shown below.



Download WSO2 Application Server-4.0.0 today and try this out your self.