Popular Posts

Saturday, October 25, 2008

Changing the default class loading mechanism of JBoss 4.2.* and WebLogic

Application servers use different class loading/delegation mechanisms. Therefore, we should understand them when deploying enterprise applications. In most cases, we need to override the default class loading behavior of application servers.
Suppose your web application wants to load classes from its own class loader first without delegating to parent. Then the following simple configurations will help you to override default delegation pattern in BEA WebLogic (version 8.* or 10) and JBOSS 4.2.*.

In WebLogic:

Set <prefer-web-inf-classes> to true in WEB-INF/weblogic.xml of your war.

Read WebLogic Server application classloading for more information.

In JBoss:

Set java2ParentDelegation to false in WEB-INF/jboss-web.xml as follows.

<loader-repository>
org.test:loader=archive-name
<loader-repository-config>
java2ParentDelegation=false
</loader-repository-config>
</loader-repository>

For more information about JBoss class loading, have a look at JBoss classloading configuration guide

Tuesday, October 21, 2008

How to use Maven2 WSDL2Code plugin in Axis2

Apache Axis2 ships with a lot of useful tools to make web service developer's life easier. Maven2 WSDL2Code plugin is one of them which can be used to generate server side skeletons or client stubs from a given WSDL using a maven pom.xml.
Lets see how this plugin can be used.

Pre-requistes:
Apache Maven2

Step1

Create a maven project using maven archetype template (You may ignore this step and use an existing project if you are familiar with maven)

mvn archetype:create -DgroupId=com.test -DartifactId=calculator

This will create a maven project structure as follows.



Step 2

Create a directory (i.e:- resources) at src\main and copy your WSDL file there.
Now, remove the existing contents of the auto-generated pom.xml (calculator\pom.xml) and add the following configuration.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>calculator</artifactId>
<version>1.0-SNAPSHOT</version>
<name>calculator</name>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-wsdl2code-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<goals>
<goal>wsdl2code</goal>
</goals>
</execution>
</executions>
<configuration>
<packageName>org.charitha</packageName>
<wsdlFile>src/main/resources/calculator.wsdl</wsdlFile>
<databindingName>adb</databindingName>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>

Note the highlighted elements in the above pom. First we added a new <plugin> to use wsdl2code goal. The WSDL2Code goal takes a set of input parameters as explained here.
In this example, we use 3 configuration parameters.
<packageName> - The generated source will be added to this package
<wsdlFile> - The location of the input wsdl file
<databindingName> - Databinding mechanism used for code generation

Also, we need to add a dependency to Axis2 jars.

Step 3

Go to the root directory of your project structure (i.e:- calculator directory where pom.xml exists) and run the following command.

mvn clean axis2-wsdl2code:wsdl2code

You could find the generated classes at target\generated-sources\axis2\wsdl2code directory.

Note: The sample wsdl used for the above example can be found at http://ww2.wso2.org/~charitha/calculator.wsdl

RESTful PHP Web Services by Samisa Abeysinghe



Samisa Abeysinghe
, the director of engineering at WSO2, attempts to explain the basic architectural concepts and step through examples of consuming and creating RESTful web services in PHP through his new book. This should be a vital reference for anyone interested in SOA.
You could find more details of this book from PACKT web.

Monday, October 13, 2008

Reading a property of Axis2 services.xml from service Implementation class

There have been questions raised in Axis2 user list about reading some properties defined in services.xml from service implementation class.
An easy way of doing that is as follows.

1. Suppose your services.xml is as follows and it has a parameter named, TestProperty.

<service name="ParameterService">
<messageReceivers>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</messageReceivers>
<parameter name="ServiceClass">org.test.MyParameterService</parameter>
<parameter name="TestProperty">This is a test property</parameter>

</service>

2. We need to read the value of "TestProperty" parameter from service implementation class.
It can be done using MessageContext as follows.

import org.apache.axis2.context.MessageContext;

public class MyParameterService {
public void readProperty(){
MessageContext mc = MessageContext.getCurrentMessageContext();
String prop = mc.getCurrentMessageContext().getAxisService().getParameter("TestProperty").getParameterElement().getText();
System.out.println(prop);
}

}

Now you can create a service archive with this class and copy it to AXIS2_HOME/repository/services directory. Then start axis2server.bat and go to http://localhost:8080
You will notice that the service will be deployed there. Then invoke the service by sending HTTP GET request as follows
http://localhost:8070/axis2/services/ParameterService/readProperty

Look at the Axis2server console. You will see "This is a test property" message is printed there.

Sunday, October 12, 2008

How to make an OSGI bundle using maven bundle plugin

OSGI (Open systems Gateway Initiative) specification defines a complete and dynamic component model which can be remotely installed, started, updated, stopped and uninstalled without restarting JVM. I'm not going to discuss the specification details of OSGI. You can find a lot of information from www.osgi.org
The objective of this post is to create a simple OSGI bundle using Apache Felix maven bundle plugin.

Pre-requisites:
Apache Maven2

Step 1
First we need to create a simple java class and which must be included in a proper directory structure therefore we can use Maven2 to build the source.

Create the following directory structure in your file system.

Create the following interface.

package org.wso2;

public interface GreetingService {
public void sayGreeting(String s);
}

Create an Impl directory under wso2 and add the following class in there.

package org.wso2.Impl;

import org.wso2.GreetingService;

public class GreetingServiceImpl implements GreetingService {

public void sayGreeting(String s){
System.out.println("Welcome " +s);

}
}

Step 2

We have created an interface and its implementation. We have not done anything new for you so far.
Since we are going to create an OSGI bundle, we need to add a BundleActivator though it is not mandatory to have. Bundle Activator class is used to start and stop the bundle when it is installed on an OSGI framework such as Knopflerfish.
Lets create an implementation of BundleActivator at the same package where GreetingServiceImpl is placed.

package org.wso2.Impl;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.wso2.Impl.GreetingServiceImpl;

public class Activator implements BundleActivator {
public void start(BundleContext bundleContext) throws Exception {
GreetingServiceImpl greetingServiceImpl = new GreetingServiceImpl();
greetingServiceImpl.sayGreeting("Charitha");

}

public void stop(BundleContext bundleContext) throws Exception {

}
}

Step3
Now we can create the pom.xml to compile above classes and make an OSGI bundle (Basically we need to generate manifest headers in MANIFEST.MF of the generated bundle jar)
Here is the complete pom.xml. Note the highlighted section.

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>


<groupId>org</groupId>
<artifactId>wso2</artifactId>
<packaging>bundle</packaging>
<version>1.0</version>

<dependencies>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.osgi.core</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>

<name>Simple OSGI example</name>
<description>A bundle to demonstrate maven bundle plugin.</description>


<properties>
<bundle.namespace>${pom.groupId}.${pom.artifactId}</bundle.namespace>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>1.4.0</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Private-Package>${bundle.namespace},${bundle.namespace}.Impl</Private-Package>
<Export-Package>${bundle.namespace}</Export-Package>
<Bundle-Activator>${bundle.namespace}.Impl.Activator</Bundle-Activator>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

The <Export-Package> element tells the plugin which of the available packages to copy into the bundle and export. The <Private-Package> instruction indicates which of the available packages to copy into the bundle but not export. In other words, private packages are not exported by the bundle.
Here, we define our impl package, org.wso2.Impl as a private package.
These elements will be added as manifest headers in resulting bundle jar as we will see shortly.

Step 4
Save pom.xml at the root directory of the above folder tree. (e.g:- example directory) and run it with mvn clean install

Bundle will be created at the target directory. Open it and look at META-INF/MANIFEST.MF

Manifest-Version: 1.0

Built-By: Charitha

Created-By: Apache Maven Bundle Plugin

Bundle-Activator: org.wso2.Impl.Activator

Import-Package: org.osgi.framework;version="1.3",org.wso2

Bnd-LastModified: 1223869521406

Export-Package: org.wso2

Bundle-Version: 1.0

Bundle-Name: Simple OSGI example

Bundle-Description: A bundle to demonstrate maven bundle plugin.

Build-Jdk: 1.5.0_14

Private-Package: org.wso2.Impl

Bundle-ManifestVersion: 2

Bundle-SymbolicName: org.wso2

Tool: Bnd-0.0.238


Have a look at the Export-Package and Private-Package headers which were added to the manifest as we defined them in pom.xml.
Now our bundle is ready to deploy in an OSGI framework. We will see how this bundle can be deployed on Knopflerfish in a future blog post.

How to add a custom SOAP header to the request using AXIOM

Suppose you want to add the following SOAP header block to your web service request message.
<myNS:header xmlns:myNS="http://ws.org">
This is a custom soap header
</myNS:header >

There are different approaches to add user defined headers to the request soap messages. Lets see how it could be done using AXIOM in simpler way.
In this example we are going to invoke Axi2 default version service with adding a custom soap header in to the request.

Pre-requisites
Download and install Apache Axis2
Install Apache Tcpmon

Step 1

Start Axis2 server by running AXIS2_HOME/bin/axis2server.bat{sh}
Go to http://localhost:8080. You will see that the default version service is deployed there.

Step 2

Now, we need to generate client stubs. Go to AXIS2_HOME/bin and run wsdl2java.bat{sh} with the following parameters.
WSDL2Java -uri http://localhost:8080/axis2/services/Version?wsdl -o out -uw

The client stubs will be generated in a directory called "out".

Now, write a client importing the generated stub classes as follows(You can easily create a project in Eclipse using the generated Build.xml)

import java.rmi.RemoteException;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
import sample.axisversion.ExceptionException0;
import sample.axisversion.VersionStub;


public class CustomSoapHeaderClient {

public static void main(String[] args) throws AxisFault{

String url = "http://localhost:8090/axis2/services/Version";
VersionStub stub = new VersionStub(url);

OMFactory omFactory =OMAbstractFactory.getOMFactory();
OMNamespace omNamespace = omFactory.createOMNamespace("http://ws.org", "myNS");
OMElement header = omFactory.createOMElement("header", omNamespace);
header.setText("This is a custom soap header");
stub._getServiceClient().addHeader(header);

try {
System.out.println(stub.getVersion());
} catch (RemoteException e) {
e.printStackTrace();
} catch (ExceptionException0 e) {
e.printStackTrace();
}
}


}

Note the highlighted code which creates the custom soap header.

Step 3

We can visualize the soap request using Tcpmon. Therefore open tcpmon and configure listen port in 8090 and target port 8080.
Compile and run the above client. You will see the following message in request pane of Tcpmon.

<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Header>
<myNS:header xmlns:myNS="http://ws.org">This is a custom soap header</myNS:header>


Monday, October 6, 2008

SOAP over JMS with Axis2

Axis2 provides a JMS transport implementation which can be used to send SOAP messages over JMS. This post will help you to -
  • Configure JMS transport in Axis2
  • Generate Axis2 client
  • Invoke default version service by sending request SOAP message over JMS
  • Monitoring messages via JConsole
I assume Apache ActiveMQ is used as our JMS implementation. However, you are free to use any other stack.

Pre-requisites
1. Install the latest version of Apache Axis2 binary distribution
2. Install Apache ActiveMQ 5.0.0

Step 1
First, we need to start ActiveMQ message broker. Go to ActiveMQ_Install_dir/bin and run activemq.bat



Step 2
In order to configure the JMSListener in axis2.xml, uncomment the following section.
<transportReceiver name="jms" class="org.apache.axis2.transport.jms.JMSListener">
<parameter name="myTopicConnectionFactory">
<parameter name="java.naming.factory.initial">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter>
<parameter name="java.naming.provider.url">tcp://localhost:61616 </parameter>
<parameter name="transport.jms.ConnectionFactoryJNDIName">TopicConnectionFactory </parameter>
</parameter>

<parameter name="myQueueConnectionFactory">
<parameter name="java.naming.factory.initial">org.apache.activemq.jndi.ActiveMQInitialContextFactory </parameter>
<parameter name="java.naming.provider.url">tcp://localhost:61616 </parameter>
<parameter name="transport.jms.ConnectionFactoryJNDIName">QueueConnectionFactory </parameter>
</parameter>

<parameter name="default">
<parameter name="java.naming.factory.initial">org.apache.activemq.jndi.ActiveMQInitialContextFactory </parameter>
<parameter name="java.naming.provider.url">tcp://localhost:61616 </parameter>
<parameter name="transport.jms.ConnectionFactoryJNDIName">QueueConnectionFactory </parameter>
</parameter>
</transportReceiver>

Also, uncomment the transport Sender which is in the Transport-outs section of axis2.xml.

<transportSender name="jms" class="org.apache.axis2.transport.jms.JMSSender"/>

Step3
The following ActiveMQ libraries must be copied to the Axis2 lib directory (AXIS2_HOME/lib).
  • activeio-core-3.1-SNAPSHOT.jar (ActiveMQ_Install_dir\lib\optional)
  • activemq-core-5.0.0.jar (ActiveMQ_Install_dir\lib\)
  • geronimo-j2ee-management_1.0_spec-1.0.jar (ActiveMQ_Install_dir\lib\)
  • geronimo-jms_1.1_spec-1.0.jar (ActiveMQ_Install_dir\lib\)
Step 4
Start Axis2server and go to http://localhost:8080
Then select the default version service.
The WSDL of the Version service will be displayed. You will notice the following port.

<wsdl:port name="VersionJmsSoap11Endpoint" binding="ns:VersionSoap11Binding">
<soap:address location="jms:/Version?transport.jms.ConnectionFactoryJNDIName=QueueConnectionFactory&java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory&java.naming.provider.url=tcp://localhost:61616"/>
</wsdl:port>

This implies that the Version service is now exposed over JMS transport as well. Lets write a client and send SOAP requests through JMS.

Step 5

Generate Client stubs with the following command.
AXIS2_HOME/bin/WSDL2Java -uri http://localhost:8070/axis2/services/Version?wsdl -o out -uw

The client stubs will be generated in a directory called "out".

Now, write a client importing the generated stub classes as follows(You can easily create a project in Eclipse using the generated Build.xml)

import java.rmi.RemoteException;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import sample.axisversion.ExceptionException0;
import sample.axisversion.VersionStub;


public class JMSClient {

public static void main(String[] args) throws AxisFault{
ConfigurationContext cc = ConfigurationContextFactory.createConfigurationContextFromFileSystem(null,"D:\\axis2\\axis2-client\\conf\\axis2.xml");
String url = "jms:/Version?transport.jms.ConnectionFactoryJNDIName=QueueConnectionFactory&java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory&java.naming.provider.url=tcp://localhost:61616";
VersionStub stub = new VersionStub(cc,url);

try {
System.out.println(stub.getVersion());
} catch (RemoteException e) {
e.printStackTrace();
} catch (ExceptionException0 e) {
e.printStackTrace();
}
}

}

We need to enable JMS in client side too. Therefore, create a client repository (Just create a directory and copy the axis2.xml in there). Make sure to enable JMS transportReceiver and TransportSender in client's axis2.xml.

Step 6

Run the client. You will get the response back with axis2 version.
Now we need to look at the messages transmitted through JMS channel. Open a command prompt and type 'jconsole' and hit enter.
Connect to ActiveMQ agent.
Click on MBeans and select org.apache.activemq mbean.
Select localhost --> Queue

Run the client few times and note the queue size.

How to deploy JSR181 annotated class in Apache Axis2

JAX-WS (Java API for XML Web Services) provides support for annotating Java classes with metadata to indicate that the Java class is a Web service. With the annotations, you can expose java classes as web services with minimum effort.
Apache Axis2 ships with JAX-WS support since its 1.4 release. This post explains the simplest possible scenario of JAX-WS support, how you can deploy an annotated class in Axis2.

Pre-requisites
Apache Axis2-1.4 or later
JDK1.5 or above

Step 1
Write an annotated class as follows.

package org.apache.axis2;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public class Calculator {
@WebMethod
public double Add(double x, double y){
return x+y;
}
}

Here, the @WebService annotation tells the server runtime to expose all public methods on the above class as a Web service. Also, with the @WebMethod annotation, you can specifically denotes the methods which are exposed in the web service.

Step 2
Package the above class as a JAR (i.e:- Calculator.jar).
You need to create a directory in Axis2 binary distribution where the annotated jars are placed.
Therefore go to AXIS2_HOME/repository (AXIS2_HOME is where you extracted the binary distro) and create a new directory called, servicejars.

cd AXIS2_HOME/repository
mkdir servicejars

Step 3
Copy the annotated jar file to the servicejars directory. Then, start Axis2server (AXIS2_HOME/bin/axis2server.bat{sh})

Step 4
Go to http://localhost:8080
You will see that the calculator class will be exposed as a web service. Click on the service name.
You will be directed to the following URL and the WSDL of the service can be viewed there.
http://localhost:8080/axis2/services/CalculatorService.CalculatorPort?wsdl

Step 5
Service Deployement is over by now. Lets invoke this service using a client. I will use SOAPUI for the demonstration, you may choose any of the available mechanisms.

Open SOAPUI and start to create a new WSDL project.
Enter the above WSDL path(http://localhost:8080/axis2/services/CalculatorService.CalculatorPort?wsdl) as the initial WSDL.
Select the request, provide inputs and submit. You will get the expected results back.



You can find more information about Axis2 JAX-WS API from here.