简体   繁体   English

如何通过CXF中的Interceptor将SoapFault转换为SoapMessage?

[英]How to transform SoapFault to SoapMessage via Interceptor in CXF?

I have web-service created and configured via Spring and CXF . 我通过SpringCXF创建和配置了Web服务。 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. 您可以看到我在我的Web服务中添加了模式验证。 But CXF throws SoapFault when request is not corresponding with schema. 但是当请求与架构不对应时, CXF会抛出SoapFault I want to send to the client SoapMessage instead of SoapFault , that's why I added outFaultInterceptors . 我想发送给客户端SoapMessage而不是SoapFault ,这就是为什么我添加了outFaultInterceptors

My question is how to transform SoapFaul t to SoapMessage ? 我的问题是如何将SoapFaul转换为SoapMessage I've made few tries but I don't know how to implement outFaultInterceptor . 我做了很少尝试,但我不知道如何实现outFaultInterceptor

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. 能够将POJO发送到输出端有点棘手。 I suppose it can be much more simpler if constructing DOM by yourself. 我想如果自己构建DOM会更简单。

Interceptor 拦截器

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;
    }

}

Request/Response POJO 请求/回复POJO

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;
    }
}

WebService 网络服务

package foo.bar;

import javax.jws.WebService;

@WebService
public class InternalActServiceImpl {
    public Echo echo(Echo val) {
        return val;
    }
}

Spring Context: CxfInterceptorTest-context.xml Spring Context:CxfInterceptorTest-context.xml

<?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>

Unit Test 单元测试

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 org.apache.cxf.interceptor.Interceptor

The handleFault of handleMessage method will be called. 将调用handleMessage方法的handleFault。 The parameter is both cases will be an instance of 这两个参数都是一个实例

org.apache.cxf.message.Message org.apache.cxf.message.Message

You can call on that 你可以打电话来

removeContent()

or 要么

setContent()

to replace the message. 替换消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM