I have web-service created and configured via Spring
and CXF
. See beans below:
<?xml version="1.0" encoding="UTF-8"?>
<beans <!-- ommited -->>
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="internalActService" class="package.InternalActServiceImpl" />
<jaxws:endpoint implementor="#internalActService" address="/InternalActService">
<jaxws:properties>
<entry key="schema-validation-enabled" value="true" />
</jaxws:properties>
<jaxws:outFaultInterceptors>
<bean class="package.InternalActServiceFaultOutInterceptor" />
</jaxws:outFaultInterceptors>
</jaxws:endpoint>
</beans>
As can you see I added schema validation to my web service. But CXF
throws SoapFault
when request is not corresponding with schema.
I want to send to the client SoapMessage
instead of SoapFault
, that's why I added outFaultInterceptors
.
My question is how to transform SoapFaul
t to SoapMessage
? I've made few tries but I don't know how to implement outFaultInterceptor
.
You will have to make sure that you create an appropriate directory structure for your project and add the earlier shown hello. wsdl file to the specified folder. The wsdl2java plugin will compile this wsdl and create Apache CXF classes in a pre-defined folder.
Interceptors are the fundamental processing unit inside CXF. When a service is invoked, an InterceptorChain is created and invoked. Each interceptor gets a chance to do what they want with the message. This can include reading it, transforming it, processing headers, validating the message, etc.
In Apache Camel, the Camel CXF component is the key to integrating routes with Web services. You can use the Camel CXF component to create a CXF endpoint, which can be used in either of the following ways: Consumer — (at the start of a route) represents a Web service instance, which integrates with the route.
Apache CXF™ is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.
Probably you forgot to setup interceptor phase and its order in the interceptor chain.
Try something like this:
package org.foo.bar;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.interceptor.AttachmentOutInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.StaxOutInterceptor;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageContentsList;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import java.util.Arrays;
import java.util.List;
public class InternalActServiceFaultOutInterceptor extends AbstractSoapInterceptor {
public InternalActServiceFaultOutInterceptor() {
super(Phase.PRE_STREAM);
addBefore(Arrays.asList(StaxOutInterceptor.class.getName(), AttachmentOutInterceptor.class.getName()));
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
Exception exception = message.getContent(Exception.class);
if(exception != null) {
message.getExchange().put(Exception.class, null);
for(Class<?> contentFormat : message.getContentFormats()) {
message.setContent(contentFormat, null);
}
message.setContent(List.class, new MessageContentsList(createSoapMessage(RegisterDocumentResponse.class)));
}
}
protected <T> T createSoapMessage(Class<T> messageType) {
// create your message
return null;
}
}
-EDIT-
Here is a unit test that works for me. It's a little bit tricky to be able to send POJOs to the output. I suppose it can be much more simpler if constructing DOM by yourself.
package foo.bar;
import java.util.Arrays;
import java.util.List;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.InterceptorChain;
import org.apache.cxf.interceptor.OutgoingChainInterceptor;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageContentsList;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.service.model.BindingMessageInfo;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.MessageInfo;
import org.apache.cxf.service.model.OperationInfo;
import org.apache.cxf.service.model.ServiceModelUtil;
import org.apache.cxf.ws.policy.PolicyOutInterceptor;
public class InternalActServiceFaultOutInterceptor extends AbstractSoapInterceptor {
public InternalActServiceFaultOutInterceptor() {
super(Phase.SETUP);
addBefore(Arrays.asList(PolicyOutInterceptor.class.getName()));
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
Exchange exchange = message.getExchange();
resetOrigInterceptorChain(message);
resetFault(exchange);
Message outMessage = createOutMessage(exchange);
InterceptorChain chain = prepareNewInterceptorChain(exchange);
chain.doIntercept(outMessage);
}
private InterceptorChain prepareNewInterceptorChain(Exchange exchange) {
Message message = exchange.getOutMessage();
bind(message);
InterceptorChain chain = OutgoingChainInterceptor.getOutInterceptorChain(exchange);
message.setInterceptorChain(chain);
return chain;
}
private Message createOutMessage(Exchange exchange) {
Endpoint ep = exchange.get(Endpoint.class);
Message outMessage = ep.getBinding().createMessage();
outMessage.setExchange(exchange);
outMessage.setContent(List.class, new MessageContentsList(createSoapMessage()));
exchange.setOutMessage(outMessage);
return outMessage;
}
private void resetFault(Exchange exchange) {
exchange.put(Exception.class, null);
}
private void resetOrigInterceptorChain(SoapMessage message) {
InterceptorChain chain = message.getInterceptorChain();
for(Interceptor<?> interceptor : chain) {
chain.remove(interceptor);
}
chain.reset();
}
private void bind(Message message) {
Exchange exchange = message.getExchange();
BindingOperationInfo bop = unwrap(message.getExchange().getBindingOperationInfo());
message.put(MessageInfo.class, bop.getOperationInfo().getOutput());
message.put(BindingMessageInfo.class, bop.getOutput());
bop = unwrap(ServiceModelUtil.getOperationForWrapperElement(exchange, bop.getName(), false));
exchange.put(BindingOperationInfo.class, bop);
if (bop != null) {
exchange.put(BindingOperationInfo.class, bop);
exchange.put(OperationInfo.class, bop.getOperationInfo());
}
}
private BindingOperationInfo unwrap(BindingOperationInfo bop) {
while(bop.getUnwrappedOperation() != null) {
bop = bop.getUnwrappedOperation();
return bop;
}
return bop;
}
protected Echo createSoapMessage() {
Echo e = new Echo();
e.setValue("Bye World!");
return e;
}
}
package foo.bar;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "EchoType")
public class Echo {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
package foo.bar;
import javax.jws.WebService;
@WebService
public class InternalActServiceImpl {
public Echo echo(Echo val) {
return val;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-jaxws.xml" />
<bean id="internalActService" class="foo.bar.InternalActServiceImpl" />
<jaxws:endpoint implementor="#internalActService" address="http://localhost:9080/InternalActService">
<jaxws:properties>
<entry key="schema-validation-enabled" value="true" />
</jaxws:properties>
<jaxws:outFaultInterceptors>
<bean class="foo.bar.InternalActServiceFaultOutInterceptor" />
</jaxws:outFaultInterceptors>
</jaxws:endpoint>
package foo.bar;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class CxfInterceptorTest {
private static final String REQ =
"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:bar=\"http://bar.foo/\">\r\n" +
" <soapenv:Header/>\r\n" +
" <soapenv:Body>\r\n" +
" <bar:echo>\r\n" +
" <arg0>\r\n" +
" <value1>Hello World</value1>\r\n" +
" </arg0>\r\n" +
" </bar:echo>\r\n" +
" </soapenv:Body>\r\n" +
"</soapenv:Envelope>";
@Test
public void validate() throws Exception {
String s = call();
Assert.assertTrue(s.contains("Bye World!"));
}
private String call() throws Exception {
URL url = new URL("http://localhost:9080/InternalActService");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setInstanceFollowRedirects(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "text/xml;charset=UTF-8");
conn.setRequestProperty("SOAPAction", "");
OutputStream os = conn.getOutputStream();
os.write(REQ.getBytes());
os.flush();
os.close();
final int buffSize = 1024;
byte[] buff = new byte[1024];
InputStream is = conn.getInputStream();
StringBuilder builder = new StringBuilder(buffSize);
for(int readBytes = -1; (readBytes = is.read(buff, 0, buffSize)) != -1; ) {
builder.append(new String(buff, 0, readBytes));
}
is.close();
return builder.toString();
}
}
Your interceptor should implement
org.apache.cxf.interceptor.Interceptor
The handleFault of handleMessage method will be called. The parameter is both cases will be an instance of
org.apache.cxf.message.Message
You can call on that
removeContent()
or
setContent()
to replace the message.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With