Implémentation d'intercepteurs CXF

L'implémentation d'un intercepteur est assez simple. Il suffit d'implémenter l'interface Interceptor. Plusieurs implémentation abstraite existent pour faciliter la tâche. Les deux plus fréquentes sont AbstractPhaseInterceptor et AbstractSoapInterceptor qui permettent d'accéder au Message ou au SoapMessage.

Le premier intercepteur créé va permettre la prise de date du démarrage de l'appel au web service et devra être placé en input. On démarre le ExecTimeCalculator dans la méthode handleMessage.

import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;

public class LogInTimeInterceptor extends AbstractPhaseInterceptor<Message> {

public LogInTimeInterceptor() { super(Phase.RECEIVE);
}
public void handleMessage(Message message) throws Fault {
ExecTimeCalculator.getInstance().start();
}
}

Le deuxième intercepteur va s'occuper de récupérer le nom du service et de l'opération appelée, et les envoyer à l'ExecTimeCalculator pour arrêter la date de fin d'exécution et afficher le service, l'opération et le temps total d'exécution.

import javax.xml.namespace.QName;

import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;

public class LogOutTimeInterceptor extends AbstractPhaseInterceptor<Message> {

//private static final Logger logger = Logger.getLogger(LogOutTimeInterceptor.class);

public LogOutTimeInterceptor() {
super(Phase.SEND);
}

public void handleMessage(Message message) throws Fault {
QName service = (QName) message.get(Message.WSDL_SERVICE);
QName op = (QName) message.get(Message.WSDL_OPERATION);
ExecTimeCalculator.getExecTime(service.getLocalPart(), op.getLocalPart());
}

}

Configuration du webservice avec les intercepteurs

La configuration dans le contexte Spring CXF du webservice se fait très simplement avec en plus des sections <jaxws:inInterceptors> et <jaxws:outInterceptors> dans laquelle on va rajouter nos intercepteurs :

    <bean id="serviceImpl" class="fr.openfarm.wss.ServiceTestImpl"/>
<bean id="logInTime" class="fr.openfarm.wss.LogInTimeInterceptor"/>
<bean id="logOutTime" class="fr.openfarm.wss.LogOutTimeInterceptor"/>
<jaxws:endpoint id="service" implementor="#serviceImpl"
implementorClass="fr.openfarm.wss.ServiceTestImpl"
address="/ServiceTest">
<jaxws:inInterceptors>
<ref bean="logInTime"/>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<ref bean="logOutTime"/>
</jaxws:outInterceptors>
</jaxws:endpoint>

Calcul du temps d'exécution

Ce temps d'exécution nous avons pouvoir le calculer grâce à une variable en ThreadLocal mise dans un singleton... On va stocker un objet Calendar sous la forme d'un ThreadLocal. Ceci signifie que lorsqu'ExecTimeCalculator est appelé par un thread, l'objet Calendar sera affecté à ce thread et à lui seul. Chaque thread garde donc une copie propre de l'objet Calendar par l'intermédiaire du ThreadLocal. Etant donné que l'input et l'output d'une requête de web service se fait dans le même thread, on peut alors calculer le temps d'exécution si l'on stocke la date de démarrage.

import java.text.SimpleDateFormat;
import java.util.Calendar;
import org.apache.log4j.Logger;

public class ExecTimeCalculator {

private static final Logger logger = Logger.getLogger(ExecTimeCalculator.class);
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

private static ExecTimeCalculator instance;
private ThreadLocal<Calendar> date;

private ExecTimeCalculator() {
this.date = new ThreadLocal<Calendar>();
this.date.set(null);
}

public static ExecTimeCalculator getInstance() {
if( instance == null ) instance = new ExecTimeCalculator();
return instance;
}

public void start() {
Calendar now = Calendar.getInstance();
getInstance().date.set(now);
logger.debug("Date début exec : " + sdf.format(now.getTime())
+ " [ threadId = " + Thread.currentThread().getId() + "]");
}

public static void getExecTime(String service, String operation) {
Calendar now = Calendar.getInstance();
logger.debug("Date fin exec : " +sdf.format(now.getTime())
+ " [ threadId = " + Thread.currentThread().getId() + "]");
logger.info(service + "." + operation + " : execution time = "
+ (now.getTimeInMillis() - getInstance().getDate().get().getTimeInMillis())
+ " ms");
getInstance().getDate().set(null);
}

public ThreadLocal<Calendar> getDate() {
return date;
}

public void setDate(ThreadLocal<Calendar> date) {
this.date = date;
}

}

A vous de jouer!

Source :

http://www.jroller.com/gmazza/entry/jaxwshandlers_to_cxfinterceptors

https://cwiki.apache.org/CXF20DOC/interceptors.html