Details

    • Type: Enhancement
    • Status: Open (View Workflow)
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: 2.1.3.Final
    • Fix Version/s: None
    • Component/s: Core
    • Labels:
      None

      Description

      Currently it seems impossible to configure a number of decoders that would pass the resulting object to a generic super type message handler.

      interface Message {}
      class SubscribeResponse implements Message {}
      class KLineResponse implements Message {}
      
      ClientEndpointConfig config = ClientEndpointConfig.Builder.create() 
          .decoders(Arrays.asList(SubscribeResponseDecoder.class, KLineResponseDecoder.class))
          .build();
      
      class MyMessageHandler implements MessageHandler.Whole<Message> {
      
           void onMessage(Message msg) {
               ....
           }
      }
      
      session.addMessageHandler(new MyMessageHandler());
      

      When I do this, the implementation chokes with ...

      java.lang.IllegalStateException: UT003006: Unable to detect FrameType for clazz interface io.gridley.test.stream.KLineStreamTest$Message
      	at io.undertow.websockets.jsr.FrameHandler.createHandlerWrappers(FrameHandler.java:432)
      	at io.undertow.websockets.jsr.FrameHandler.addHandlerInternal(FrameHandler.java:382)
      	at io.undertow.websockets.jsr.FrameHandler.addHandler(FrameHandler.java:375)
      	at io.undertow.websockets.jsr.UndertowSession.addMessageHandler(UndertowSession.java:117)
      

      To solve this, I currently do some convoluted reflection on my decoders and message handlers like this ...

      public void onOpen(Session session, EndpointConfig config) {
          
          LOG.info("Open socket: {}", endpointUri);
          
          // Map the configured decoders to 
          Map<Decoder.Text<?>, MessageHandler.Whole<?>> handlerMapping = new HashMap<>();
          
          for (Class<? extends Decoder> clazz : config.getDecoders()) {
              try {
                  Decoder.Text<?> decoder = (Text<?>) clazz.newInstance();
                  Method method = clazz.getMethod("decode", String.class);
                  Class<?> decodedType = method.getReturnType();
                  decoder.init(config);
                  
                  for (MessageHandler.Whole<?> handler : messageHandlers) {
                      Class<?> handledType = Arrays.asList(handler.getClass().getMethods()).stream()
                              .filter(m -> m.getName().equals("onMessage"))
                              .map(m -> m.getParameterTypes()[0])
                              .findAny().get();
                      
                      if (handledType.isAssignableFrom(decodedType)) {
                          handlerMapping.put(decoder, handler);
                      }
                  }
              } catch (ReflectiveOperationException ex) {
                  throw new CheckedExceptionWrapper(ex);
              }
          }
          
          session.addMessageHandler(String.class, msg -> {
      
              Decoder.Text<?> decoder = handlerMapping.keySet().stream()
                  .filter(d -> d.willDecode(msg))
                  .findFirst().orElse(null);
      
              if (decoder != null) {
                  try {
                      Object decoded = decoder.decode(msg);
                      MessageHandler.Whole handler = handlerMapping.get(decoder);
                      handler.onMessage(decoded);
                  } catch (DecodeException ex) {
                      throw new CheckedExceptionWrapper(ex);
                  }
              }
              
              else {
                  LOG.info("Raw Message: {}", msg);
              }
          });
      }
      

      Would it perhaps be possible to this internally in Undertow? The MessageHandler could perhaps be annotated to advice the implementation which FrameType it is handling. All that mapping logic from decoder to message handler with an explicit calls to the decoder and respective message handler should ideally be avoidable in user code.

        Gliffy Diagrams

          Attachments

            Activity

              People

              • Assignee:
                flavia.rainone Flavia Rainone
                Reporter:
                thomas.diesler Thomas Diesler
              • Votes:
                0 Vote for this issue
                Watchers:
                1 Start watching this issue

                Dates

                • Created:
                  Updated: