-->

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




 
  
 

Aucun commentaire :

Enregistrer un commentaire