jms-spec
  1. jms-spec
  2. JMS_SPEC-88

Bind JMS to CDI events and/or business interfaces

    Details

    • Type: New Feature New Feature
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: None
    • Labels:
      None

      Description

      The simplified API is a huge leap forward in terms of simplicity to create and consume messages. But when writing a real service (probably an MDB) that consumes multiple messages coming in from a queue or topic, then unpacking them and dispatching calls to the right method is still rather tedious, error prone, and difficult to test.

      Take this example of a service that handles two different xml messages, one to create a customer and one to delete a customer. Using text messages that contain xml is a good option, if you want to exchange complex objects and need tools to look into messages in transit. I don't show the Create/DeleteCustomer data objects here.

      @MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destination", propertyValue = "CustomerService") })
      public class ReceiverMdb implements MessageListener {
          @Override
          public void onMessage(Message message) {
              try {
                  String xml = ((TextMessage) message).getText().trim();
                  StringReader reader = new StringReader(xml);
                  if (xml.endsWith("</createCustomer>")) {
                      CreateCustomer create = JAXB.unmarshal(reader, CreateCustomer.class);
                      createCustomer(create.getFirstName(), create.getLastName());
                  } else if (xml.endsWith("</deleteCustomer>")) {
                      DeleteCustomer delete = JAXB.unmarshal(reader, DeleteCustomer.class);
                      deleteCustomer(delete.getId());
                  } else {
                      throw new RuntimeException("unknown message type: " + xml);
                  }
              } catch (JMSException e) {
                  throw new RuntimeException(e);
              }
          }
      
          private void createCustomer(String firstName, String lastName) {
              System.out.println("create customer " + firstName + " " + lastName);
          }
      
          private void deleteCustomer(String id) {
              System.out.println("delete customer " + id);
          }
      }
      

       


      I can see two alternatives to reduce the unpacking and dispatching to the bare minimum:

      1) Binding to CDI events

      The same example would look like this:

      @Stateless
      public class CustomerService {
          public void createCustomer(@Observes CreateCustomer create) {
              System.out.println(create);
          }
      
          public void deleteCustomer(@Observes DeleteCustomer delete) {
              System.out.println(delete);
          }
      }
      

      Note that the Create/DeleteCustomer classes would have to be annotated as @MessageEvent, so the container can create an appropriate binding from JMS.

      2) Binding to a business interface

      For the same example, the Create/DeleteCustomer classes would not be necessary. Instead there would be a business interface and the service implements it:

      @MessageApi
      public interface CustomerService {
          public void createCustomer(String firstName, String lastName);
          public void deleteCustomer(String id);
      }
      
      public class CustomerServiceBean implements CustomerService {
          @Override
          public void createCustomer(String firstName, String lastName) {
              System.out.println("create: " + firstName + " " + lastName);
          }
      
          @Override
          public void deleteCustomer(String id) {
              System.out.println("delete: " + id);
          }
      }
      

       


      Both binding methods would help with sending messages as well, but the difference is bigger when receiving them.

      A lot of questions still need to be answered: How do you define message properties, destination name, delivery mode, time-to-live, delay, etc.? All would have useful defaults, but sometimes they need to be specified, and sometimes they even need to be dynamic. How do you bind to other message types, like mapped messages?

      I've started to collect some possible answers to most of these questions here as part of an experimental implementation for both binding types here. I'm aware of the CDI binding implementation in the Seam JMS module here.

        Activity

        There are no comments yet on this issue.

          People

          • Assignee:
            Unassigned
            Reporter:
            rdohna
          • Votes:
            1 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: