带有Appache CXF和嵌入式Jetty的Websocket上的SOAP

时间:2019-06-12 12:52:25

标签: java soap websocket jetty cxf

我一直在尝试通过CXF将带有Websocket的SOAP端点设置为传输协议,并通过CXF实现调用它。带嵌入式码头。我尝试了几种方法,但都没有成功。这是我所做的:

方法1 。根据CXF文档,支持websocket作为传输协议,并且通过

提供支持
<dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-websocket</artifactId>
            <version>3.3.2</version>
</dependency>

我已经设置了以下依赖项:

 <dependency>
        <groupId>org.asynchttpclient</groupId>
        <artifactId>async-http-client</artifactId>
        <version>2.0.39</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>3.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>3.3.2</version>
    </dependency>
    <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.3.2</version>
    </dependency>

我执行的代码如下:

Endpoint endpoint = Endpoint.create(new MyHelloWorldServicePortType() {

            @Override
            public String sayHello(HelloMessage message) throws FaultMessage {

                return message.sayHello();
            }
};
((org.apache.cxf.jaxws.EndpointImpl)endpoint).getFeatures().add(new 
WSAddressingFeature());
endpoint.publish("ws://localhost:8088/MyHelloWorldService"  );
URL wsdlDocumentLocation =  new URL("file:/path to wsdl file");
 String servicePart = "MyHelloWorldService";
 String namespaceURI = "mynamespaceuri";
 QName serviceQN = new QName(namespaceURI, servicePart);
Service service = Service.create(wsdlDocumentLocation, serviceQN);
 MyHelloWorldServicePortType port = service.getPort( MyHelloWorldServicePortType.class);

portType.sayHello(new HelloMessage("Say Hello"));

这段代码的结果是:

  

严重:[ws] onError java.util.concurrent.TimeoutException:请求   在60000毫秒后超时未连接   org.asynchttpclient.netty.timeout.TimeoutTimerTask.expire(TimeoutTimerTask.java:43)     在   org.asynchttpclient.netty.timeout.RequestTimeoutTimerTask.run(RequestTimeoutTimerTask.java:48)     在   io.netty.util.HashedWheelTimer $ HashedWheelTimeout.expire(HashedWheelTimer.java:682)     在   io.netty.util.HashedWheelTimer $ HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:757)     在   io.netty.util.HashedWheelTimer $ Worker.run(HashedWheelTimer.java:485)     在java.base / java.lang.Thread.run(Thread.java:834)

     

君。 2019年12月12日下午13:33   org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit $ AhcWebSocketWrappedOutputStream   严重连接:无法连接   java.util.concurrent.ExecutionException:   java.util.concurrent.TimeoutException:请求超时   在60000毫秒后未连接   java.base / java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395)     在   java.base / java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1999)     在   org.asynchttpclient.netty.NettyResponseFuture.get(NettyResponseFuture.java:172)     在   org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit $ AhcWebSocketWrappedOutputStream.connect(AhcWebSocketConduit.java:309)     在   org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit $ AhcWebSocketWrappedOutputStream.setupWrappedStream(AhcWebSocketConduit.java:167)     在   org.apache.cxf.transport.http.HTTPConduit $ WrappedOutputStream.handleHeadersTrustCaching(HTTPConduit.java:1343)     在   org.apache.cxf.transport.http.HTTPConduit $ WrappedOutputStream.onFirstWrite(HTTPConduit.java:1304)     在   org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:47)     在   org.apache.cxf.io.AbstractThresholdOutputStream.write(AbstractThresholdOutputStream.java:69)     在   org.apache.cxf.transport.http.HTTPConduit $ WrappedOutputStream.close(HTTPConduit.java:1356)     在   org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit $ AhcWebSocketWrappedOutputStream.close(AhcWebSocketConduit.java:139)     在   org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)

我绝对不知道为什么。当我尝试通过URL上的websocket chrome客户端进行连接时。它说成功。通过客户端连接时,同时显示超时。

方法2。

我决定欺骗CXF,并提供一个手工Websocket端点,它将用作CXF Web服务的前端。这个想法是客户端将通过websocket发送消息,消息将被解包然后通过CXF发送。此方法与此处的方法非常相似,但此处使用JMS作为传输方式

https://github.com/pbielicki/soap-websocket-cxf

为此,我创建了以下Websocket枚举:

@ServerEndpoint("/jaxWSFront")
public class JaxWSFrontEnd {


      @OnOpen
      public void onOpen(final Session session) {
           System.out.println("Hellooo");

      }

      @OnMessage
      public void onMessage(String mySoapMessage,final Session session) throws Exception{
    //  The goal here is to get the soap message and redirect it via SOAP web //service. The JaxWSFacade acts as a point that understands websocket and then //gets the soap content and sends it to enpoint that understands SOAP.

       session.getBasicRemote().sendText("Helllo . Now you see me.");

       System.out.println("Hellooo again");
      }

      @OnClose
      public void onClose(Session session, CloseReason closeReason) {
           System.out.println("Hellooo");
      }

      @OnError
      public void onError(Throwable t, Session session) {
           System.out.println("Hellooo");
      }

} 

现在,我将我的客户端代理指向jaxWsFrontEnd而不是Webservice端点。我的期望是,我将在onMessage方法中接收SOAP消息,然后将能够转发到SOAP到CXF Web服务。

现在我的代码如下:

server = new Server(8088);

            ServletContextHandler context = new ServletContextHandler();
            context.setContextPath( "/" );
            server.setHandler(context);

            ServerContainer container = WebSocketServerContainerInitializer.configureContext(context);
            container.addEndpoint(JaxWSFrontEnd.class);

            server.setHandler( context );
            server.start();
  Endpoint endpoint = Endpoint.create(new MyHelloWorldServicePortType() {

                @Override
                public String sayHello(HelloMessage message) throws FaultMessage {

                    return message.sayHello();
                }
    };
    ((org.apache.cxf.jaxws.EndpointImpl)endpoint).getFeatures().add(new 
    WSAddressingFeature());

    URL wsdlDocumentLocation =  new URL("file:/path to wsdl file");
     String servicePart = "MyHelloWorldService";
     String namespaceURI = "mynamespaceuri";
     QName serviceQN = new QName(namespaceURI, servicePart);
    Service service = Service.create(wsdlDocumentLocation, serviceQN);
     MyHelloWorldServicePortType port = service.getPort( MyHelloWorldServicePortType.class);

    portType.sayHello(new HelloMessage("Say Hello"));

对于第二种方法,除了方法1之外,还具有以下依赖性:

<dependency>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>websocket-common</artifactId>
                    </dependency>
       <dependency>
          <groupId>org.eclipse.jetty.websocket</groupId>
          <artifactId>javax-websocket-server-impl</artifactId>

        </dependency>

方法2的结果与方法1完全相同,但我收到的例外是相同的,只有一点点差异。 当我使用Chrome Websocket客户端并将其直接指向jaxWsFrontend时,我能够成功发送消息。为什么我无法通过CXF Websocket传输机制连接到Websocket?我在做什么错了?

更新:启用NETTY的日志记录。这说明网易引发了java.lang.NoSuchMethodError:io.netty.channel.DefaultChannelId.newInstance()Lio / netty / channel / DefaultChannelId;

也许我有netty的版本兼容性问题。我看到的导入到项目中的版本是4.1.33。我没有声明它是一个传递依赖。

1 个答案:

答案 0 :(得分:0)

好吧,我实际上设法独自破解了它。我将发布完成答案。显然,CXF专家应更新其IMO文档。在他们的网站上指出,为了启用Websocket作为传输协议,我们需要 cxf-rt-transports-websocket 依赖项。

他们没有说的是,您还需要 async-http-client 而不是任何版本,而是 2.0.39 一个非常老的版本。问题在于它自动包括对 netty 4.1 的传递依赖,并且上面指定的错误开始显现。您实际需要的是nett 4.0.56

以下是使事情对我有用的片段:

<dependency>
            <groupId>org.asynchttpclient</groupId>
            <artifactId>async-http-client</artifactId>
            <version>2.0.39</version>
             <exclusions>
                <exclusion>
                    <groupId>io.netty</groupId>
                    <artifactId>netty-buffer</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.netty</groupId>
                    <artifactId>netty-codec-http</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.netty</groupId>
                    <artifactId>netty-handler</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.netty</groupId>
                    <artifactId>netty-transport-native-epoll</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.netty</groupId>
                    <artifactId>netty-transport</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.netty</groupId>
                    <artifactId>netty-common</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.netty</groupId>
                    <artifactId>netty-codec</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.netty</groupId>
                    <artifactId>netty-all</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.0.56.Final</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-websocket</artifactId>
        <version>3.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>3.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>3.3.2</version>
    </dependency>
    <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.3.2</version>
    </dependency>

方法1正在运作 方法2我设法触发了onConnect事件,即onMessage超时,但是我认为它应该可以工作,但我缺少一些小东西。无论如何,我没有更多的时间可花,我对Aproach 1感到满意。