Showing posts with label WebServices. Show all posts
Showing posts with label WebServices. Show all posts

Tuesday, June 12, 2012

RESTEasy Tutorial Part 3 - Exception Handling


RESTEasy Tutorial Series

RESTEasy Tutorial Part-1: Basics

RESTEasy Tutorial Part-2: Spring Integration

RESTEasy Tutorial Part 3 - Exception Handling

Exception Handling is an obvious requirement while developing software application. If any error occured while processing user request we should show the user an error page with details like brief exception message, error code(optional), hints to correct the input and retry(optional) and actual root cause(optional). This is applicable to RESTful web services also.

But putting try-catch-finally blocks all around the code is not a good practice. We should design/code in such a way that if there is any unrecoverable error occured then the code should throw that exception and there should an exception handler to catch those exceptions and extract the error details and give a proper error response to the client with all the error details.

RESTEasy provides such ExceptionHandler mechanism which simplifies the ExceptionHandling process.

In this part I will show you how we can use RESTEasy's ExceptionHandlers to handle Exceptions.

Step#1: Create Application Specific Exceptions.
Step#2: Create ExceptionHandlers by implementing ExceptionMapper interface.

Step#3: Update UserResource.getUserXMLById() method to validate user input and throw respective exceptions.

Step#4: Test the UserResource.getUserXMLById() service method by issueing following requests.



Important things to note:
As Spring is creating the necessary objects we should let Spring know about @Provider classes to get them registered with RESTEasy. We can do this in two ways.

a)Annotate Provider classes with @Component

b)Using component-scan's include-filter.

<context:component-scan base-package="com.sivalabs.springdemo">
         <context:include-filter expression="javax.ws.rs.ext.Provider" type="annotation"/>
</context:component-scan>

Wednesday, June 6, 2012

RESTEasy Tutorial Part-2: Spring Integration


RESTEasy Tutorial Series

RESTEasy Tutorial Part-1: Basics

RESTEasy Tutorial Part-2: Spring Integration

RESTEasy Tutorial Part 3 - Exception Handling


RESTEasy provides support for Spring integration which enables us to expose Spring beans as RESTful WebServices.

Step#1: Configure RESTEasy+Spring dependencies using Maven.



Step#2: Configure RESTEasy+Spring in web.xml



Step#3: Create a Spring Service class UserService and update UserResource to use UserService bean.


Step#4: Same JUnit TestCase to test the REST Webservice described in Part-1.

Important Things to Keep in mind:
1. org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap Listener should be registered before any other listener.

2. You should configure resteasy.servlet.mapping.prefix <context-param> if the HttpServletDispatcher servlet url-pattern is anything other than /*

3. While using Spring integration set resteasy.scan to false or don't configure resteasy.scan parameter at all.
    Otherwise you may get REST Resource instances(UserResource) from RestEasy instead of Spring container. While running JUnit Tests I observed this random behavior.

4. You should register REST Resource as Spring bean by annotating with @Component or @Service.

RESTEasy Tutorial Part-1: Basics


RESTEasy Tutorial Series

RESTEasy Tutorial Part-1: Basics

RESTEasy Tutorial Part-2: Spring Integration

RESTEasy Tutorial Part 3 - Exception Handling


RESTEasy is a JAX-RS implementation from JBoss/RedHat and is in-built in JBoss 6 onwards.
Here I am going to show you how to develop a Simple RESTful Web Services application using RESTEasy and JBossAS7.1.1.FINAL.

Step#1: Configure RESTEasy dependencies using Maven.




Step#2: Configure RESTEasy in web.xml



Step#3: Create User domain class, MockUserTable class to store User objects in-memory for testing purpose and UserResource class to expose CRUD operations on User as RESTful webservices.




Step#6: JUnit TestCase to test the REST Webservice.




Step#7: To test the REST service we can use the REST Client Tool. 
You can download REST Client Tool at http://code.google.com/a/eclipselabs.org/p/restclient-tool/


Important Things to Keep in mind:
1. org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap Listener should be registered before any other listener.

2. You should configure resteasy.servlet.mapping.prefix <context-param> if the HttpServletDispatcher servlet url-pattern is anything other than /*


3. Keep visiting my blog :-)





Friday, September 30, 2011

Deploying JAX-WS WebService on Tomcat-6

Now we are going to see how to deploy JAX-WS WebService on Tomcat Server.
We are going to deploy The AuthenticationService developed in http://sivalabs.blogspot.com/2011/09/developing-webservices-using-jax-ws.html on apache-tomcat-6.0.32.

To deploy our AuthenticationService we need to add the following configuration.

1.web.xml

<web-app>
 <listener>
  <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
 </listener>
 
 <servlet>
  <servlet-name>authenticationService</servlet-name>
  <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>authenticationService</servlet-name>
  <url-pattern>/services/AuthenticationService</url-pattern>
 </servlet-mapping>
</web-app> 

2. Create a new file WEB-INF/sun-jax-ws.xml

<?xml version="1.0" encoding="UTF-8"?>
<endpoints
  xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
  version="2.0">
  
  <endpoint
      name="AuthenticationService"
      implementation="com.sivalabs.caas.services.AuthenticationServiceImpl"
      url-pattern="/services/AuthenticationService"/>
      
</endpoints>

3. Download the JAX-WS Reference Implementation from http://jax-ws.java.net/
Copy all the jar files from jaxws-ri/lib folder to WEB-INF/lib.


Now deploy the application on Tomcat server.
You don't need to publish the Service by our-self as we did using EndpointPublisher.
Once the tomcat is up and running see the generated wsdl at http://localhost:8080/CAAS/services/AuthenticationService?wsdl.

Now if you test the AuthenticationService using standalone client it will work fine.
public static void testAuthenticationService()throws Exception
{
  URL wsdlUrl = new URL("http://localhost:8080/CAAS/services/AuthenticationService?wsdl");
  QName qName = new QName("http://sivalabs.blogspot.com/services/AuthenticationService", "AuthenticationService");
  Service service = Service.create(wsdlUrl,qName);
  AuthenticationService port = service.getPort(AuthenticationService.class);
  Credentials credentials=new Credentials();
  credentials.setUserName("admin");
  credentials.setPassword("admin");
  AuthenticationStatus authenticationStatus = port.authenticate(credentials);
  System.out.println(authenticationStatus.getStatusMessage());
}

But if you try to test with the wsimport tool generated client code make sure that you dont have jax-ws-ri jars in Client classpath.
Otherwise you will get the below error:

Exception in thread "main" java.lang.NoSuchMethodError: javax.xml.ws.WebFault.messageName()Ljava/lang/String;
 at com.sun.xml.ws.model.RuntimeModeler.processExceptions(RuntimeModeler.java:1162)
 at com.sun.xml.ws.model.RuntimeModeler.processDocWrappedMethod(RuntimeModeler.java:898)

Thursday, September 29, 2011

Developing WebServices using JAX-WS

Let us assume an enterprise is maintaining user authentication details in a centralized system. We need to create an AuthenticationService which will take credentials, validate them and return the status. The rest of the applications will use the AuthenticationService to authenticate the Users.

Create AuthenticationService interface as follows:

package com.sivalabs.caas.services;

import javax.jws.WebService;

import com.sivalabs.caas.domain.AuthenticationStatus;
import com.sivalabs.caas.domain.Credentials;
import com.sivalabs.caas.exceptions.AuthenticationServiceException;

@WebService
public interface AuthenticationService
{
public AuthenticationStatus authenticate(Credentials credentials) throws AuthenticationServiceException;
}



package com.sivalabs.caas.domain;

/**
 * @author siva
 *
 */
public class Credentials 
{
 private String userName;
 private String password;
 public Credentials() 
{
 }
 public Credentials(String userName, String password) {
  super();
  this.userName = userName;
  this.password = password;
 }
 //setters and getters
 
}


package com.sivalabs.caas.domain;

/**
 * @author siva
 *
 */
public class AuthenticationStatus
{
 private String statusMessage;
 private boolean success;
 //setters and getters
 
}


package com.sivalabs.caas.exceptions;

/**
 * @author siva
 *
 */
public class AuthenticationServiceException extends RuntimeException
{
 
 private static final long serialVersionUID = 1L;
 public AuthenticationServiceException()
 {
 }
 public AuthenticationServiceException(String msg)
 {
  super(msg);
 }
}



Now let us implement the AuthenticationService.

package com.sivalabs.caas.services;

import java.util.HashMap;
import java.util.Map;

import javax.jws.WebService;

import com.sivalabs.caas.domain.AuthenticationStatus;
import com.sivalabs.caas.domain.Credentials;
import com.sivalabs.caas.exceptions.AuthenticationServiceException;

/**
 * @author siva
 *
 */
@WebService(endpointInterface="com.sivalabs.caas.services.AuthenticationService",
   serviceName="AuthenticationService", 
   targetNamespace="http://sivalabs.blogspot.com/services/AuthenticationService")
public class AuthenticationServiceImpl implements AuthenticationService
{
 private static final Map<string, string> CREDENTIALS = new HashMap<string, string>();
 static
 {
  CREDENTIALS.put("admin", "admin");
  CREDENTIALS.put("test", "test");  
 }
 
 @Override
 public AuthenticationStatus authenticate(Credentials credentials) throws AuthenticationServiceException
 {
  if(credentials == null)
  {
   throw new AuthenticationServiceException("Credentials is null");
  }
  AuthenticationStatus authenticationStatus = new AuthenticationStatus();
  String userName = credentials.getUserName();
  String password = credentials.getPassword();
  
  if(userName==null || userName.trim().length()==0 || password==null || password.trim().length()==0)
  {
   authenticationStatus.setStatusMessage("UserName and Password should not be blank");
   authenticationStatus.setSuccess(false);
  }
  else
  {
   if(CREDENTIALS.containsKey(userName) && password.equals(CREDENTIALS.get(userName)))
   {
    authenticationStatus.setStatusMessage("Valid UserName and Password");
    authenticationStatus.setSuccess(true);
   }
   else
   {
    authenticationStatus.setStatusMessage("Invalid UserName and Password");
    authenticationStatus.setSuccess(false);
   }
  }
  return authenticationStatus;
 }
}

Here for simplicity we are checking the credentials against the static data stored in HashMap. In real applications this check will be done against database.

Now we are going to publish the WebService.

package com.sivalabs.caas.publisher;

import javax.xml.ws.Endpoint;

import com.sivalabs.caas.services.AuthenticationServiceImpl;

public class EndpointPublisher
{
 public static void main(String[] args)
 {
  Endpoint.publish("http://localhost:8080/CAAS/services/AuthenticationService", new AuthenticationServiceImpl());
 }

}
Run this standalone class to publish the AuthenticationService.

To check whether the Service published successfully point the browser to URL http://localhost:8080/CAAS/services/AuthenticationService?wsdl. If the service published successfully you will see the WSDL content.


Now let us create a Standalone test client to test the webservice.

package com.sivalabs.caas.client;

import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;

import com.sivalabs.caas.domain.AuthenticationStatus;
import com.sivalabs.caas.domain.Credentials;
import com.sivalabs.caas.services.AuthenticationService;

/**
 * @author siva
 *
 */
public class StandaloneClient
{

 public static void main(String[] args) throws Exception
 {
  URL wsdlUrl = new URL("http://localhost:8080/CAAS/services/AuthenticationService?wsdl");
  QName qName = new QName("http://sivalabs.blogspot.com/services/AuthenticationService", "AuthenticationService");
  Service service = Service.create(wsdlUrl,qName);
  AuthenticationService port = service.getPort(AuthenticationService.class);
  Credentials credentials=new Credentials();
  credentials.setUserName("admin1");
  credentials.setPassword("admin");
  AuthenticationStatus authenticationStatus = port.authenticate(credentials);
  System.out.println(authenticationStatus.getStatusMessage());
  
  credentials.setUserName("admin");
  credentials.setPassword("admin");
  authenticationStatus = port.authenticate(credentials);
  System.out.println(authenticationStatus.getStatusMessage());
 }

}
Instead of writing StandaloneClient by our-self we can generate the Client using wsimport commandline tool.
wsimport tool is there in JDK/bin directory.
Go to your project src directory and execute the following command.
wsimport -keep -p com.sivalabs.caas.client http://localhost:8080/CAAS/services/AuthenticationService?wsdl

It will generate the following java and class files in com.sivalabs.caas.client package.

Authenticate.java
AuthenticateResponse.java
AuthenticationService_Service.java
AuthenticationService.java
AuthenticationServiceException_Exception.java
AuthenticationServiceException.java
AuthenticationStatus.java
Credentials.java
ObjectFactory.java
package-info.java

Now you can use the generated Java files to test the Service.

public static void main(String[] args) throws Exception
{
  AuthenticationService_Service service = new AuthenticationService_Service();
  com.sivalabs.caas.client.AuthenticationService authenticationServiceImplPort = service.getAuthenticationServiceImplPort();
  com.sivalabs.caas.client.Credentials credentials = new com.sivalabs.caas.client.Credentials();
  
  credentials.setUserName("admin1");
  credentials.setPassword("admin");
  com.sivalabs.caas.client.AuthenticationStatus authenticationStatus = authenticationServiceImplPort.authenticate(credentials);
  System.out.println(authenticationStatus.getStatusMessage());
  
  credentials.setUserName("admin");
  credentials.setPassword("admin");
  authenticationStatus = authenticationServiceImplPort.authenticate(credentials);
  System.out.println(authenticationStatus.getStatusMessage());
}

In next article I will show how to deploy this AuthenticationService in Tomcat.