SOAP через Websocket с Appache CXF и встроенным Jetty - PullRequest
0 голосов
/ 12 июня 2019

Я пытался установить конечную точку SOAP с Websocket в качестве транспортного протокола через CXF и реализовать его вызов через CXF.С врезанным причалом.Я попробовал пару подходов, но ни один из подходов не сработал.Вот что я сделал:

Aproach 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"));

Результат этого кода:

SEVERE: [ws]onError java.util.concurrent.TimeoutException: запрос тайм-аута для неподключенного через 60000 мс в org.asynchttpclient.netty.timeout.TimeoutTimerTask.expire (TimeoutTimerTask.java:43) в org.asynchttpclient.nettyTimeasReRe.Time.TimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTimeTime.TimeRequestTimeoutTimerTask.java:48) в io.netty.util.HashedWheelTimer $ HashedWheelTimeout.expire (HashedWheelTimer.java:682) в io.netty.util.HashedWheelTimer $ HashedWheelBucket.exp..HashedWheelTimer $ Worker.run (HashedWheelTimer.java:485) в java.base / java.lang.Thread.run (Thread.java:834)

июнь.12, 2019 13:13:33 org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit $ AhcWebSocketWrappedOutputStream connect SEVERE: невозможно подключить java.util.concurrent.ExecutionException: java.util.concurrent.Time Outout-подключен через 60000 мс в java.base / java.util.concurrent.CompletableFuture.reportGet (CompletableFuture.java:395) в java.base / java.util.concurrent.CompletableFuture.get (CompletableFuture.java:1999) в орг.asynchttpclient.netty.ahc.AhcWebSocketConduit $ AhcWebSocketWrappedOutputStream.setupWrappedStream (AhcWebSocketConduit.java:167) в org.apache.cxf.transport.http.HTTPConduit $ WrappedOutputStream.handlett.th.tht_tg_t3_t_p_W3_HT_PHT_T3_HTWrappedOutputStream.onFirstWrite (HTTPConduit.java:1304) в org.apache.cxf.io.AbstractWrappedOutputStream.write (AbstractWrappedOutputStream.java:47) в org.apache.cxf.io.AbstractThresholdOutputStream.write (AbstractThresholdOutputStream.jxfache. atc.ap.at).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)

Я абсолютно не знаю, почему.Когда я пытаюсь подключиться через веб-сокет Chrome клиента по URL.Это говорит об успехе.В то же время при подключении через клиент он говорит Timeout.

Aproach 2.

Я решил обмануть CXF и предоставить конечную точку Websocket ручной работы, которая будет использоваться какфронт к веб-сервису CXF.Идея состоит в том, что Клиент отправит сообщение через веб-сокет, которое будет развернуто, а затем отправлено через 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 вместо конечной точки веб-службы.Я ожидаю, что я получу сообщение SOAP в методе onMessage, а затем смогу перенаправить SOAP в веб-службу CXF.

Теперь мой код выглядит следующим образом:

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 и указываю его непосредственно на jaxWsFrontend, я могу успешно отправить сообщение. Почему я не могу подключиться к веб-сокету с помощью механизмов транспортировки веб-сокетов CXF ???? Что я делаю не так?

ОБНОВЛЕНИЕ: включение регистрации из NETTY. Похоже, что netty выбросил java.lang.NoSuchMethodError: io.netty.channel.DefaultChannelId.newInstance () Lio / netty / channel / DefaultChannelId;

Возможно, у меня проблема совместимости версий с netty. Версия, которую я вижу, импортирована в проект - 4.1.33. Это транзитивная зависимость, которую я не объявил.

1 Ответ

0 голосов
/ 12 июня 2019

Хорошо, мне действительно удалось взломать это в одиночку. Я отправлю ответ для завершения. Очевидно, ребята из 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>

Aproach 1 работает Пример 2 Мне удалось вызвать событие onConnect, тайм-аут onMessage, но, на мой взгляд, это должно сработать, мне не хватает чего-то маленького. В любом случае, у меня больше нет времени, и я доволен Aproach 1.

...