SOAP через Websocket с Appache CXF и Embedded Jetty

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

Подход 1. В соответствии с документацией CXF веб-сокет поддерживается как транспортный протокол, и его поддержка предоставляется через

<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: Request timeout to not-connected after 60000 ms at org.asynchttpclient.netty.timeout.TimeoutTimerTask.expire(TimeoutTimerTask.java:43) at org.asynchttpclient.netty.timeout.RequestTimeoutTimerTask.run(RequestTimeoutTimerTask.java:48) at io.netty.util.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:682) at io.netty.util.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:757) at io.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:485) at java.base/java.lang.Thread.run(Thread.java:834)

jun. 12, 2019 1:13:33 P.M. org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit$AhcWebSocketWrappedOutputStream connect SEVERE: unable to connect java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutException: Request timeout to not-connected after 60000 ms at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395) at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1999) at org.asynchttpclient.netty.NettyResponseFuture.get(NettyResponseFuture.java:172) at org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit$AhcWebSocketWrappedOutputStream.connect(AhcWebSocketConduit.java:309) at org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit$AhcWebSocketWrappedOutputStream.setupWrappedStream(AhcWebSocketConduit.java:167) at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleHeadersTrustCaching(HTTPConduit.java:1343) at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.onFirstWrite(HTTPConduit.java:1304) at org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:47) at org.apache.cxf.io.AbstractThresholdOutputStream.write(AbstractThresholdOutputStream.java:69) at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1356) at org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit$AhcWebSocketWrappedOutputStream.close(AhcWebSocketConduit.java:139) at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)

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

Подход 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. Это транзитивная зависимость, которую я не декларировал.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
520
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Хорошо, мне действительно удалось взломать его в одиночку. Я опубликую ответ для завершения. По-видимому, ребята из CXF должны обновить свою документацию IMO. На их сайте указано, что для включения Websocket в качестве транспортного протокола нам нужно cxf-rt-транспорт-websocket зависимость.

Чего они не говорят, так это того, что вам дополнительно нужен асинхронный http-клиент не любой версии, а 2.0.39 довольно старой версии. Проблема в том, что он автоматически включает транзитивные зависимости к нетти 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.

Другие вопросы по теме