Uploaded image for project: 'Undertow'
  1. Undertow
  2. UNDERTOW-1756

Mapping decoded types to their respective handlers

    XMLWordPrintable

Details

    • Feature Request
    • Resolution: Unresolved
    • Major
    • None
    • 2.1.3.Final
    • Core
    • 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.

      Attachments

        Activity

          People

            flaviarnn Flavia Rainone
            tdiesler@redhat.com Thomas Diesler
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated: