-->
Affichage des articles dont le libellé est Interceptor. Afficher tous les articles
Affichage des articles dont le libellé est Interceptor. Afficher tous les articles

mercredi 21 janvier 2015

CXF3 and Spring 4 : Using Interceptor ...

Introduction :

I continue with the exploration of the CXF framework and present my feedback with web services. With this present article, I will introduce interceptors and i will give an example among several use cases: I begin with introducing the example to more understand : if we want to handle all exceptions and not to return to the user a technical stack trace that can never understand, so instead we can return a customizable messages with any thrown exception. In this case, we must use CXF interceptors.

Let's code now:

As always I rely on my old article and I use the same sources. We will start by creating exceptions and first we will create an Enum for errors list :
package fr.mjhazbri.webservices.exception;
/**
 * 
 * @author jhazbri
 *
 */
public enum ExceptionErrorCode {

 GENERAL_ERROR("GENERAL_ERROR"), 
 VALIDATION_ERROR("VALIDATION_ERROR"), 
 CONNECTION_ERROR("CONNECTION_ERROR"), 
 INTERNAL_ERROR("INTERNAL_ERROR"), 
 UPLOAD_ERROR("UPLOAD_ERROR"), 
 STORAGE_ERROR("STORAGE_ERROR"), 
 UNKOWN_ERROR("UNKOWN_ERROR");

 private String value;

 /**
  * @return the value
  */
 public String getValue() {
  return value;
 }

 /**
  * @param value
  */
 private ExceptionErrorCode(String value) {
  this.value = value;
 }
}

Then we will create an exception called BusinessException to handle all errors:

/**
 * 
 */
package fr.mjhazbri.webservices.exception;

/**
 * @author jhazbri
 * 
 */
public class BusinessException extends Exception {

 private static final long serialVersionUID = 6379178121998659740L;
 private ExceptionErrorCode errorCode;

 public BusinessException(String message, Throwable cause,ExceptionErrorCode errorCode) 
 {
  super(message, cause);
  this.setErrorCode(errorCode);
 }

 public BusinessException(String message, ExceptionErrorCode errorCode) 
 {
  super(message);
  this.setErrorCode(errorCode);
 }

 public BusinessException(Throwable cause, ExceptionErrorCode errorCode) 
 {
  super(cause);
  this.setErrorCode(errorCode);
 }

 /**
  * @return the errorCode
  */
 public ExceptionErrorCode getErrorCode() 
 {
  return errorCode;
 }

 /**
  * @param errorCode
  *            the errorCode to set
  */
 public void setErrorCode(ExceptionErrorCode errorCode) 
 {
  this.errorCode = errorCode;
 }

 public String getCodeValue() 
 {
  if (errorCode == null)
   return "-1";
  else
   return errorCode.getValue();
 }
}


Now a ExceptionManager interface to manage and manufacture BusinessException:

/**
 * 
 */
package fr.mjhazbri.webservices.exception.api;

import fr.mjhazbri.webservices.exception.BusinessException;
import fr.mjhazbri.webservices.exception.ExceptionErrorCode;

/**
 * @author jhazbri
 *
 */
public interface ExceptionManager {
 BusinessException buildBusinessException (ExceptionErrorCode errorCode); 
 String getMessageByErrorCode (ExceptionErrorCode exceptionErrorCode); 
}


An implementation for this interface is ExceptionManagerImpl and load the properties file messages.properties that contains the error messages list :

/**
 * 
 */
package fr.mjhazbri.webservices.exception;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.core.env.Environment;

import fr.mjhazbri.webservices.exception.api.ExceptionManager;

/**
 * @author jhazbri
 * 
 */
@Configuration
@PropertySources(@PropertySource("classpath:messages.properties"))
public class ExceptionManagerImpl implements ExceptionManager {

 @Autowired
 private Environment env;

 @Override
 public BusinessException buildBusinessException(ExceptionErrorCode errorCode) {
  String msg = getMessageByErrorCode(errorCode);
  return new BusinessException(msg, errorCode);
 }

 @Override
 public String getMessageByErrorCode(ExceptionErrorCode exceptionErrorCode) {
  return env.getProperty(exceptionErrorCode.getValue());
 }
}


And that is the content of the file messages.properties

GENERAL_ERROR = GENERAL_ERROR
VALIDATION_ERROR = VALIDATION_ERROR
CONNECTION_ERROR = CONNECTION_ERROR
INTERNAL_ERROR = INTERNAL_ERROR
UNKOWN_ERROR = UNKOWN_ERROR

Interceptor :

Now let's see the CXF Interceptor :
/**
 * 
 */
package fr.mjhazbri.webservices.interceptor;

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

import org.apache.cxf.common.injection.NoJSR250Annotations;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import fr.mjhazbri.webservices.exception.BusinessException;
import fr.mjhazbri.webservices.exception.ExceptionErrorCode;
import fr.mjhazbri.webservices.exception.api.ExceptionManager;

@NoJSR250Annotations
public class ExceptionInterceptor extends AbstractPhaseInterceptor<Message> {
 /**
  * Class logger.
  */
 private static final Logger logger = Logger.getLogger(ExceptionInterceptor.class);
 
 @Autowired
 private ExceptionManager exceptionManager ; 
 
 public ExceptionInterceptor() {
  super(Phase.MARSHAL);
 }
 
 public void handleMessage(Message message) throws Fault {
  logger.debug("ExceptionInterceptor () : handleMessage ... () ");
  Fault fault = (Fault) message.getContent(Exception.class);
  if (fault != null )
  {
   if (fault.getCause() instanceof BusinessException )
   {
    BusinessException ex = (BusinessException) fault.getCause();
    logger.debug("BusinessException  ....." );
    RuntimeException exception=  new WebServiceException(ex.getMessage());
    Fault faultResponse = new Fault(exception);
    faultResponse.setFaultCode(new QName(ex.getErrorCode().getValue()));
    message.setContent(Exception.class, faultResponse); 
   }
   else 
   {
    Throwable ex = fault.getCause();
    logger.debug("ExceptionInterceptor () : handleMessage for class " + ex.getClass().getName());
    logger.error("Exception not managed : "+ ex.getClass().getName(),ex);
    // préparer le message à retourner.
    RuntimeException exception=  new WebServiceException(exceptionManager.getMessageByErrorCode(ExceptionErrorCode.INTERNAL_ERROR));
    Fault faultResponse = new Fault(exception);
    faultResponse.setFaultCode(new QName(ExceptionErrorCode.INTERNAL_ERROR.name()));
    message.setContent(Exception.class, faultResponse); 
   }
   
  }
 }
}

And finally let's configure the cxf-servlet.xml