The CXF architecture provides us with interceptors – or the ability to intercept outgoing request and responses. One useful scenario could be logging.
CXF in this case has stayed one step ahead and already built custom Log Interceptors.
I decided to add logging capabilities to my client. I used the code for CXF client from my previous post with some modifications:
I decided to add logging capabilities to my client. I used the code for CXF client from my previous post with some modifications:
public static void simpleExecution() { final String endpointAddress = "http://localhost:8080/WithSpring/services/echo"; JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(IEcho.class); //the service SEI factory.setAddress(endpointAddress); //outputs the received message to the logger factory.getInInterceptors().add(new LoggingInInterceptor()); //outputs the sent message to the logger factory.getOutInterceptors().add(new LoggingOutInterceptor()); IEcho client = (IEcho) factory.create(); String reply = client.echoHi("Dude"); System.out.println("Server said: " + reply); }In the code we have added only two lines. The JaxWsProxyFactoryBean is a factory for creating JAX-WS proxies. In its hierarchy are present two CopyOnWriteArrayList instances for holding both request and response associated interceptors. If we were to run the code now:
1356 [main] DEBUG org.apache.cxf.endpoint.ClientImpl - set requestContext to m essage be{java.lang.reflect.Method=public abstract java.lang.String com.code.fir st.ws.server.IEcho.echoHi(java.lang.String), org.apache.cxf.jaxws.context.Wrappe dMessageContext.SCOPES={org.apache.cxf.message.Message.ENDPOINT_ADDRESS=APPLICAT ION}, org.apache.cxf.message.Message.ENDPOINT_ADDRESS=http://localhost:8080/With Spring/services/echo} 1356 [main] DEBUG org.apache.cxf.endpoint.ClientImpl - ... 1356 [main] DEBUG org.apache.cxf.endpoint.ClientImpl - Interceptors contribute d by client: [org.apache.cxf.interceptor.LoggingOutInterceptor@d1e7c2] 1356 [main] DEBUG org.apache.cxf.endpoint.ClientImpl - Interceptors contribute d by endpoint: ... 1356 [main] DEBUG org.apache.cxf.endpoint.ClientImpl - Interceptors contribute d by binding: ... 1356 [main] DEBUG org.apache.cxf.endpoint.ClientImpl - Interceptors contribute d by databinding: [] ... 1371 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Adding intercep tor org.apache.cxf.interceptor.LoggingOutInterceptor@d1e7c2 to phase pre-stream ... 1683 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Chain org.apach e.cxf.phase.PhaseInterceptorChain@33b121 was modified. Current flow: setup [PolicyOutInterceptor] pre-logical [HolderOutInterceptor, SwAOutInterceptor, WrapperClassOutIntercept or, SoapHeaderOutFilterInterceptor] post-logical [SoapPreProtocolOutInterceptor] prepare-send [MessageSenderInterceptor] pre-stream [LoggingOutInterceptor, AttachmentOutInterceptor, StaxOutIntercepto r] write [SoapOutInterceptor] marshal [WrappedOutInterceptor, BareOutInterceptor] write-ending [SoapOutEndingInterceptor] pre-stream-ending [StaxOutEndingInterceptor] prepare-send-ending [MessageSenderEndingInterceptor] 1698 [main] INFO org.apache.cxf.services.IEchoService.IEchoPort.IEcho - Outbo und Message --------------------------- ID: 1 Address: http://localhost:8080/WithSpring/services/echo Encoding: UTF-8 Http-Method: POST Content-Type: text/xml Headers: {Accept=[*/*], SOAPAction=[""]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">< soap:Body><ns2:echoHi xmlns:ns2="http://server.ws.first.code.com/"><msg>Dude</ms g></ns2:echoHi></soap:Body></soap:Envelope> --------------------------------------As seen from the logs:
- Various modules of CXF add their own interceptors to the workflow. In fact if we look closely at the interceptor names, we can see that a major chunk of CXF functionality is implemented through interceptors.
- The interceptors are grouped by phase. At various phases, the associated interceptors are executed.
- The LoggingOutInterceptor is associated with the pre-stream phase and it logs the xml payload and HTTP headers.
1730 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Chain org.apach e.cxf.phase.PhaseInterceptorChain@c9630a was modified. Current flow: receive [PolicyInInterceptor, LoggingInInterceptor, AttachmentInInterceptor] post-stream [StaxInInterceptor] read [WSDLGetInterceptor, ReadHeadersInterceptor, SoapActionInInterceptor, Sta rtBodyInterceptor] pre-protocol [MustUnderstandInterceptor] post-protocol [CheckFaultInterceptor, JAXBAttachmentSchemaValidationHack] unmarshal [DocLiteralInInterceptor, SoapHeaderInterceptor] post-logical [WrapperClassInInterceptor] pre-invoke [SwAInInterceptor, HolderInInterceptor, PolicyVerificationInInterce ptor] 1730 [main] DEBUG org.apache.cxf.phase.PhaseInterceptorChain - Invoking handle Message on interceptor org.apache.cxf.interceptor.LoggingInInterceptor@1dddba 1745 [main] INFO org.apache.cxf.services.IEchoService.IEchoPort.IEcho - Inbou nd Message ---------------------------- ID: 1 Response-Code: 200 Encoding: UTF-8 Content-Type: text/xml;charset=UTF-8 Headers: {Content-Length=[220], content-type=[text/xml;charset=UTF-8], Date=[Thu , 04 Apr 2013 13:52:50 GMT], Server=[Apache-Coyote/1.1]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">< soap:Body><ns2:echoHiResponse xmlns:ns2="http://server.ws.first.code.com/"><retu rn>Hi Dude</return></ns2:echoHiResponse></soap:Body></soap:Envelope> -------------------------------------- ... Server said: Hi DudeThe XML that was marshaled and unmarshaled are both visible in the response. We can make it more readable by modifying the code:
//outputs the bytes of the message to the logger LoggingInInterceptor loggingInInterceptor = new LoggingInInterceptor(); loggingInInterceptor.setPrettyLogging(true); factory.getInInterceptors().add(loggingInInterceptor); //outputs the bytes of the message to the logger LoggingOutInterceptor loggingOutInterceptor = new LoggingOutInterceptor(); loggingOutInterceptor.setPrettyLogging(true); factory.getOutInterceptors().add(loggingOutInterceptor);The setPrettyLogging method formats the xml content before logging. The same logs would now look like below:
1652 [main] INFO org.apache.cxf.services.IEchoService.IEchoPort.IEcho - Outbo und Message --------------------------- ID: 1 Address: http://localhost:8080/WithSpring/services/echo Encoding: UTF-8 Http-Method: POST Content-Type: text/xml Headers: {Accept=[*/*], SOAPAction=[""]} Payload: <?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <ns2:echoHi xmlns:ns2="http://server.ws.first.code.com/"> <msg>Dude</msg> </ns2:echoHi> </soap:Body> </soap:Envelope> -------------------------------------- 1714 [main] INFO org.apache.cxf.services.IEchoService.IEchoPort.IEcho - Inbou nd Message ---------------------------- ID: 1 Response-Code: 200 Encoding: UTF-8 Content-Type: text/xml;charset=UTF-8 Headers: {Content-Length=[220], content-type=[text/xml;charset=UTF-8], Date=[Thu , 04 Apr 2013 14:02:27 GMT], Server=[Apache-Coyote/1.1]} Payload: <?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <ns2:echoHiResponse xmlns:ns2="http://server.ws.first.code.com/"> <return>Hi Dude</return> </ns2:echoHiResponse> </soap:Body> </soap:Envelope> --------------------------------------The same can also be achieved via Spring defined beans too:
<jaxws:client id="client" serviceClass="com.code.first.ws.server.IEcho" address="http://localhost:8080/WithSpring/services/echo"> <jaxws:inInterceptors> <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" > <property name="prettyLogging" value="true" /> </bean> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" > <property name="prettyLogging" value="true" /> </bean> </jaxws:outInterceptors> </jaxws:client>We can take advantage of Spring's inheritance technique (idea taken from here):
<bean id="abstractLoggingInterceptor" abstract="true"> <property name="prettyLogging" value="true" /> </bean> <jaxws:client id="client" serviceClass="com.code.first.ws.server.IEcho" address="http://localhost:8080/WithSpring/services/echo"> <jaxws:inInterceptors> <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" parent="abstractLoggingInterceptor" /> </jaxws:inInterceptors> <jaxws:outInterceptors> <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" parent="abstractLoggingInterceptor" /> </jaxws:outInterceptors> </jaxws:client>
No comments:
Post a Comment