Dans ce nouvel article sur spring-ws nous allons voir comment intercepter les messages sortant ou entrant. Cette opération est possible au niveau du client ou du serveur. Le principe étant le même, je ne m’attarderai que sur le client.
Tracer les messages dans les logs
Le framework propose cette fonctionnalité dans ses options de log. Au niveau de log4j vous devez ajouter la définition des loggers suivants
<logger name="org.springframework.ws.client.MessageTracing.sent" additivity="false"> <level value="TRACE" /> <appender-ref ref="FILE_SOAP_REG" /> </logger> <logger name="org.springframework.ws.client.MessageTracing.received" additivity="false"> <level value="TRACE" /> <appender-ref ref="FILE_SOAP_REG" /> </logger>
Cet ajout affiche les requêtes envoyées et reçues dans l’appender portant le nom FILE_SOAP_REG
Faire un traitement métier avant l’envoi, à la réception d’une réponse ou d’une fault
Pour pouvoir intervenir avant l’envoi ou après la réponse d’un webservice, nous devons mettre en place un interceptor qui respetera le contrat
- org.springframework.ws.client.support.interceptor.ClientInterceptor côté client
- org.springframework.ws.server.EndpointInterceptor côté serveur
Il existe plusieurs implémentations dans Spring de ces interfaces pour gérer des problématiques diverses comme les logs, la sécurité des appels, la validation des données envoyées.... Pour vous montrer un exemple simple nous allons écrire un Interceptor spécifique qui tracera les éléments dans la log applicative
public class MonMessageInterceptor implements ClientInterceptor { private static final Logger LOG = Logger.getLogger(MonMessageInterceptor.class); @Override public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException { LOG.debug(messageContext.getRequest()); //Renvoie true pour continuer le traitement return true; } @Override public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException { LOG.info(String.format("Message reçu [%s] pour la demande [%s]", convertWebServiceMessageToString(messageContext.getRequest()), convertWebServiceMessageToString(messageContext.getResponse()))); //Renvoie true pour continuer le traitement return true; } @Override public boolean handleFault(MessageContext messageContext) throws WebServiceClientException { LOG.error(String.format("Message d'erreur [%s] lors de l'execution de la requete [%s]", convertWebServiceMessageToString(messageContext.getRequest()), convertWebServiceMessageToString(messageContext.getResponse()))); //Renvoie true pour continuer le traitement return true; } /** * Cette méthode permet de transformer un message SOAP en String pour l'écrire en base de données * @param message * @return */ protected String convertWebServiceMessageToString(WebServiceMessage message){ try { ByteArrayOutputStream os = new ByteArrayOutputStream(); message.writeTo(os); return os.toString(); } catch (IOException e) { LOG.error("Impossible de lire le message SOAP pour le tracer", e); return "Impossible de récuperer le payload " + e.getMessage(); } } }
Une fois l’interceptor créé il ne reste plus qu’à le déclarer dans le contexte Spring
<bean id="webServiceTemplatePublication" class="org.springframework.ws.client.core.WebServiceTemplate"> <constructor-arg ref="messageFactory" /> <property name="marshaller" ref="jaxb2Marshaller" /> <property name="unmarshaller" ref="jaxb2Marshaller" /> <property name="messageSender" ref="httpSender" /> <property name="checkConnectionForFault" value="false" /> <property name="interceptors"> <list> <ref bean="monMessagInterceptor" /> </list> </property>
</bean> <bean id="monMessagInterceptor" class="com.javamind.MonMessageInterceptor"/>
Modifier le message avant l’appel à un webservice
Si votre besoin est de modifier le message avant l’envoi de la requête au webservice distant, vous ne devez pas passer par un interceptor mais par un org.springframework.ws.client.core.WebServiceMessageCallback
Imaginons un webservice proposant plusieurs opérations SOAP et dont l’opération dépend du contexte. Nous pouvons ajouter un WebServiceMessageCallback dans les méthodes du webServiceTemplate de spring. Par exemple
PartieJoueurDto reponse = (PartieJoueurDto) webServiceTemplate .marshalSendAndReceive( joueurDto, new WebServiceMessageCallback() { public void doWithMessage(WebServiceMessage message) { if (message instanceof SoapMessage) { SoapMessage soapMessage = (SoapMessage) message; String soapActionWebService = getOperationSoap(context); soapMessage.setSoapAction(soapActionWebService ); //On ajoute la soap action dans le header soapMessage.getSoapHeader().addAttribute(QNameUtils .parseQNameString(WebServiceHeaders.SOAP_ACTION), soapActionWebService); } } });
Conclusion
Voici deux manières d’agir sur les messages envoyés ou reçus par un webservice. Pour plus d’informations je vous laisse lire la documentation officielle de spring webservice
Tank you! This helped me a lot. Now my Webservice client is printing the SOAP request and response on the log file.
RépondreSupprimer