This blog is mainly about Java...

Wednesday, February 4, 2009

How to create and use a WebService with Axis 2 and Seam 2.x in JBoss 4.x

In this example, I will show how you can create a Webservice using Axis 2.
First of all, download the latest version of Axix 2 from http://ws.apache.org/axis2/

To create a WebService in Java EE 5 you can use the annotation @WebService.
We also annotate this class as a seam component so that we can incorporate it in our existing business logic.

This is our WebService:

package somepackage.webservice;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.persistence.EntityManager;

import org.jboss.seam.Component;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.security.Credentials;
import org.jboss.seam.security.Identity;

@Name("fooService")
@Stateless
@WebService(name = "FooService", serviceName = "FooService")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL, parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
public class FooService implements FooServiceLocal {

@In EntityManager entityManager;

@In Credentials credentials;

private boolean login(String username, String password) {
credentials.setUsername(username);
credentials.setPassword(password);
Identity.instance().login();
return Identity.instance().isLoggedIn();
}

private boolean logout() {
Identity.instance().logout();
return !Identity.instance().isLoggedIn();
}

@WebMethod
public List<FooCanonical> getFoo(@WebParam(name = "username")
String username, @WebParam(name = "password")
String password, @WebParam(name = "orgnumber")
String orgnumber) {
// orgnumber can be null!
if (username == null || password == null) {
return null;
}
//First thing we do is to login to ensure that the user has the correct username/password
//We are using basic seam login method
boolean isLoggedIn = login(username, password);

if (isLoggedIn) {

List<FooCanonical> returnList = new ArrayList<FooCanonical>();
//Do some stuff with the list
//Remember to log out
logout();
return returnList;
} else {
// Probably wrong username password
return null;
}
}

}


Next what we need to do, is create a way for this webservice to interact with JBoss through our SOAP definition. We do that by creating a xml file called
standard-jaxws-endpoint-config.xml

<jaxws-config xmlns="urn:jboss:jaxws-config:2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="urn:jboss:jaxws-config:2.0 jaxws-config_2.1.xsd">
<endpoint-config>
<config-name>Seam WebService Endpoint</config-name>
<pre-handler-chains>
<javaee:handler-chain>
<javaee:protocol-bindings>##SOAP11_HTTP</javaee:protocol-bindings>
<javaee:handler>
<javaee:handler-name>SOAP Request Handler</javaee:handler-name>
<javaee:handler-class>org.jboss.seam.webservice.SOAPRequestHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</pre-handler-chains>
</endpoint-config>
</jaxws-config>

And place this file in the $JBOSS_HOME/resources/META-INF directory.
Now you are done! Deploy your application and look in
http://localhost:8080/jbossws/services 
and see if your WebService is correctly deployed and the wsdl available.
This should look something like this:

Endpoint Namejboss.ws:context=foo-foo,endpoint=FooService
Endpoint Addresshttp://localhost:8080/foo-foo/FooService?wsdl

Next, we will use the Axis2 framework to create client stubs by using axis2-1.4.1 and the script wsdl2java. Navigate to $AXIS_HOME/bin and type in the following command:
./wsdl2java.sh -uri http://127.0.0.1:8080/foo_foo/FooService?wsdl -o build/client

This command will create an ant script under the directly build/client.
Now go to build/client and type ant after setting $AXIS_HOME. This will generate FooService-test-client.jar which we now can use to retrieve data from the WebService in the client. I recommend changing the name to something more appropriate.

In your client, you can call the getFoo WebMethod like this:

FooServiceStub stub;
GetFoo getFoo;

stub = new FooServiceStub();
getFoo = new FooServiceStub.GetFoo();
getFoo.setUsername("username");
getFoo.setPassword("password");
getFoo.setOrgnumber("1234");

FooServiceStub.GetFooE fooImpl = new FooServiceStub.GetFooE();
fooImpl.setGetFoo(getFoo);

//Retrieve the List as an array
FooCanonical[] get_return = stub.getFoo(fooImpl).getGetFooResponse().get_return();
//Do what you want with the array

Note that even if you return a List from the WebService, you will get it as an array. But it is quite easy to put it in a List in the client afterwards. Also remember that the username and password is sendt in clear text, so you might want to send it through https, so it is encrypted.

10 comments:

Anonymous said...

Do you know if it is possible to create a seam webserive in a non-ejb environment (WAR) using JBoss AS.

Best,

Aaron

Shervin Asgari said...

Sure. Its not different from normal webservices.

Have a look here:
http://docs.jboss.org/jbossas/jboss4guide/r2/html/ch12.html

Asker Ali M said...

Hi,
I was trying to implement the same with JBoss 5 ans Seam 2.2, with following details
Web service as follows


@Name("timesheetService")
@Stateless
@WebService(name = "SubmittedTimesheetService", serviceName = "SubmittedTimesheetService")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL, parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
public class SubmittedTimesheet {
@WebMethod
public String calculateSomething(@WebParam(name = "username")
String username, @WebParam(name = "password")
String password) {
return username + password;
}
}


With respect to some another article i implemented Servlet inside web.xml as follows

SubmittedTimesheet
org.cgi.timesheet.model.SubmittedTimesheet


SubmittedTimesheet
/Timesheet

Now I am getting the proper WSDL file on URL localhost:8080/CGITimesheet/Timesheet?WSDL.

Now I have created the Stub using AXIS2 1.6 version.

The Issue I am facing is while I am running the client, I am getting the following error.
=============
org.apache.axis2.AxisFault: First Element must contain the local name, Envelope , but found html
at org.apache.axis2.AxisFault.makeFault(AxisFault.java:430)
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:123)
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:67)
at org.apache.axis2.description.OutInAxisOperationClient.handleResponse(OutInAxisOperation.java:354)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:421)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)
at org.cgi.timesheet.model.SubmittedTimesheetServiceStub.calculateSomething(SubmittedTimesheetServiceStub.java:182)
at org.cgi.timesheet.model.CallWS.main(CallWS.java:20)
Caused by: org.apache.axiom.soap.SOAPProcessingException: First Element must contain the local name, Envelope , but found html
at org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder.constructNode(StAXSOAPModelBuilder.java:305)
at org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder.createOMElement(StAXSOAPModelBuilder.java:252)
at org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder.createNextOMElement(StAXSOAPModelBuilder.java:234)
at org.apache.axiom.om.impl.builder.StAXOMBuilder.next(StAXOMBuilder.java:249)
at org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder.getSOAPEnvelope(StAXSOAPModelBuilder.java:204)
at org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder.(StAXSOAPModelBuilder.java:154)
at org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder.(StAXSOAPModelBuilder.java:140)
at org.apache.axis2.builder.BuilderUtil.getSOAPBuilder(BuilderUtil.java:686)
at org.apache.axis2.transport.TransportUtils.createDocumentElement(TransportUtils.java:197)
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:145)
at org.apache.axis2.transport.TransportUtils.createSOAPMessage(TransportUtils.java:108)
=================

Please help me on the same.

Note :
I havent created standard-jaxws-endpoint-config.xml file , But my WSDL is working fine.

Shervin Asgari said...

This is really not the place for me to help you, on my blog. However it looks like Axis gets html instead xml.

I suggest you use a forum to get help on your issue, either stackoverflow.com or Axis user forum.

Regards

özge said...

I have a web service login method like that:
public boolean login(String username, String password)
{
System.out.println("logine gelen username: "+username);
System.out.println("logine gelen password: "+password);
Identity.instance().getCredentials().setUsername(username);
Identity.instance().getCredentials().setPassword(password);
System.out.println("Identity.instance().getCredentials().getUsername() "+Identity.instance().getCredentials().getUsername());
System.out.println("Identity.instance().getCredentials().getPassword() "+Identity.instance().getCredentials().getPassword());
Identity.instance().login();
System.out.println("Identity.instance() "+Identity.instance());
System.out.println("Identity.instance().getUsername() "+Identity.instance().getUsername());
System.out.println("Identity.instance().isLoggedIn(): "+Identity.instance().isLoggedIn());
if (Identity.instance().isLoggedIn()==true)
return true;
return false;
}

but i cannot login because Identity.instance().login(); does not work for me. Do you have any suggestions?
Thanks
Regards,

Özge

Shervin Asgari said...

The code should work. What is the error message, if any? Do you know that normal authentication works?

özge said...

I do not have an error message,I just start the jboss server successfully and when I test client side of the project,
System.out.println("Identity.instance().isLoggedIn(): "+Identity.instance().isLoggedIn());

gives me false value.
I use seam authentication, in components.xml I have



















Thank you for reply..

Shervin Asgari said...

Then its most likely a problem with your seam setup.

What you should do is create the seam project using seam-gen. It ensures you get everything correctly, and it is quite fast and easy to setup.

Read more about it in the documentation

tom said...

Is it possible to say more about creating the client? If I use your code, the classes will not compile because referenced classes are not available. Are there axis classes which we have to include in our deployed jars and classpath?

Shervin Asgari said...

I am not sure what you mean. But you generate clients using this command: ./wsdl2java.sh -uri http://127.0.0.1:8080/foo_foo/FooService?wsdl -o build/client

This will create a client for you in the build/client directory from where you type the command.

Labels