Thursday, 10 May 2007

Adding Axis2 webservice programmatically at runtime

I just tried out Axis2 (in version 1.1.1).

But I wanted to embed the AxisEngine into my own web application instead of building an aar and deploying it into the axis2 default web application. One possible way would have been to use the same web application directory layout as used in the axis2 default web app and put a service archive into the WEB-INF/services directory or to package my web application war having the exploded service archive in the WEB-INF/services. Both solutions would have complicated the build process.

So I wanted to add services programmatically at runtime. Perhaps using some annotations on classes which mark them as webservices.

I found code like that:

service = AxisService.createService(
MyServiceImpl.class.getName(),
axisConfiguration,
RPCMessageReceiver.class);
service.setName("MyService");
axisConfiguration.addService(service);
axisConfiguration.startService(service.getName());


But the problem was to get the AxisConfiguration. The solution was simple to extend the AxisServlet which has a reference to the configuration. So MyAxisServlet overrode the init method in the following way...


public void init(ServletConfig config) throws ServletException
{
super.init(config);

AxisService service;
try {
service = AxisService.createService(
MyServiceImpl.class.getName(),
axisConfiguration,
RPCMessageReceiver.class);
service.setName("MyService");

axisConfiguration.addService(service);
axisConfiguration.startService(service.getName());
} catch (AxisFault e) {
e.printStackTrace();
}
}


...and substituted the default AxisServlet in the web.xml with MyAxisServlet ...and it worked.

At the moment I don't know if I made everything right but I had a webservice running.

The next step was then to change the init method to search all classes having an annotation @Webservice and add them in the same way as above. Name, scope and targetNamespace were set with annotation attributes.

So I have my classes annotated and added automatically to the AxisEngine. When I add another webservice class to my web app the only thing to do is to add the annotation. And I don't need a special build process to build the archive or package my war file.

6 comments:

Die Preetzer Abelings said...

It's already said and done: there is another article about embedding services in a web application at
http://www.wso2.org/library/90
and
http://www.wso2.org/library/83

Alexei Isac said...

Hi Hacim,

Thank you for the great article.
I tried following your example by creating a servlet on Tomcat. I created a Dynamic Web Project in eclipse and added a servlet. I modified the code to inherit from AxisServet. When I debug, it enters the init and everything seems to execute without generating any exceptions.

Howvever, I cant seem to to get the WSDL.

I was expecting the WSDL generation to happen when I execute

http://localhost:8080/Axis2/services/FPWSImpl?wsdl
Any idea what is wrong ?

Enclosed is my code

//-------------Begin-------------
public class AxisXServlet extends org.apache.axis2.transport.http.AxisServlet {
static final long serialVersionUID = 1L;

/* (non-Java-doc)
* @see javax.servlet.http.HttpServlet#HttpServlet()
*/
public AxisXServlet() {
super();
}

/* (non-Javadoc)
* @see javax.servlet.GenericServlet#init()
*/
public void init(ServletConfig config) throws ServletException
{
super.init(config);

AxisService service;
try {
service = AxisService.createService(
FPWSImpl.class.getName(),
axisConfiguration);
//RPCMessageReceiver.class);
//service.setName();
String strName = service.getName();
axisConfiguration.addService(service);
axisConfiguration.startService(service.getName());
} catch (AxisFault e) {
e.printStackTrace();
}
}
}

Die Preetzer Abelings said...

Hi Alexei,

did you check the log of your servlet container? Perhaps you are missing some library.

I made an example project for this which is available via anonymous svn from
http://subversion.banapple.de/public/runtime-axis/

You will need Maven2 to start the example. Just check it out and try

# mvn jetty:run

Then you can try to get the WSDL from the url

http://localhost:8080/runtime-axis/services/EchoService?wsdl

Best regards
Achim

A Person said...

Could you share the code to automatically detected classes with the @WebServices annotation?

Die Preetzer Abelings said...

Shame on me, but I lost the code.
I even forgot what I made.

I think it was a rather simple solution which was far from being able to scan all files on the classpath (this is not possible, I think).
It was probably only able to scan the directory entries in the classpath, recursively descend into the directories to find class files and check these classes using reflection.

This approach probably did not work in a servlet container. It is therefore useless.

Sorry, for making you hopes.

Alexei Isac said...

Hacim,

Your Solution of using Axis is awesome in a situation like mine where I have an existing webapp that needs to expose and modify some business objects to other remote applications.

Once I fixed by Web.xml, things started working like magic =)

Thanks for the awesome post.

-A