I’m user of CXF in an SOA development context.
I’m wondering if my problem has a solution with CXF. Here’s my need. We have developed a webapp serving JAXWS endpoints, the endpoint implementations consists in analyzing the request via interceptors, storing data from the request to a database from the service layer in Java, and resend the original request to another server via a CXF client. The point is that some of our requests contains a DSIG signature (https://www.w3.org/TR/xmldsig-core/) or an signed SAML Assertion. Our need is to resend the requests without altering them (such as a proxy) from a CXFClient. CXF uses to send the marshalled object to the server, but this way the original stream is not sent
Is there a way to resend the incoming request from the service layer from a Java CXFClient without altering it (the Signatures depends on the format of the request: blanks, namespaces prefixes, carriage returns…) ? We prefer the CXFClient because we would like to reuse our homemade CXF interceptor which logs the outgoing request.
We have tested an interceptor to intend to replace the outputStream by the original request before sending it to the server, we used this answer: How To Modify The Raw XML message of an Outbound CXF Request?, but we are still KO, CXF still sends the stream made from the marshalled object. See code below.
Context: - CXF 2.7.18 (JDK 6), and 3.1.10 (JDK 8) - Platform: windows 7 64bit/ rhel 7 64bit - Apache Tomcat 7 - Tcpdump to analyse incoming traffic
Sample of code of our client:
final Client cxfClient = org.apache.cxf.frontend.ClientProxy.getClient( portType );
cxfClient.getInInterceptors().clear();
cxfClient.getOutInterceptors().clear();
cxfClient.getOutFaultInterceptors().clear();
cxfClient.getRequestContext().put(CustomStreamerInterceptor.STREAM_TO_SEND,
PhaseInterceptorChain.getCurrentMessage().getContent( InputStream.class ) );
cxfClient.getOutInterceptors().add( new CustomStreamerInterceptor() );
org.apache.cxf.transport.http.HTTPConduit http = (org.apache.cxf.transport.http.HTTPConduit) cxfClient.getConduit();
...
port.doSomething(someRequest);
CustomStreamerInterceptor:
package test;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor.SoapOutEndingInterceptor;
import org.apache.cxf.helpers.LoadingByteArrayOutputStream;
import org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.io.CacheAndWriteOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.Phase;
public class CustomStreamerInterceptor extends AbstractOutDatabindingInterceptor {
public static final String STREAM_TO_SEND = "STREAM_TO_SEND";
public CustomStreamerInterceptor () {
super( Phase.WRITE_ENDING );
addAfter( SoapOutEndingInterceptor.class.getName() );
}
@Override
public void handleMessage( Message message ) throws Fault {
try {
InputStream toSend = (InputStream) message.get( STREAM_TO_SEND );
if ( toSend != null ) {
toSend.reset();
LoadingByteArrayOutputStream lBos = new LoadingByteArrayOutputStream();
IOUtils.copy( toSend, lBos );
CacheAndWriteOutputStream cawos = (CacheAndWriteOutputStream) message.getContent( OutputStream.class );
cawos.resetOut( lBos, false );//fail !
}
}
catch ( Exception e ) {
throw new Fault( e );
}
}
}
Thanks you for any help, it would be very usefull.