7 Replies Latest reply on Jan 12, 2009 4:20 AM by Andy Taylor

    Wild card Subscriptions

    Andy Taylor Master

      The pattern for wildcard subscriptions will be as follows. * will match against a single word and # will match against 0 or more words delimited by a .. so A.*.C will match A.B.C and A.E.D but not A.B.E.D, and A.B.# will match A.B.C.D or A.B ansd so forth, this is how amqp 0.9 specifies it.

      A simple JMS client using Wild Card Subscriptions will look like the following:

       Topic wildCardTopic = session.createTopic("topic.*");
       MessageConsumer messageConsumer = session.createConsumer(wildCardTopic);
      


      Currently in PostOfficeImpl the bindings ad addresses are held in Maps and Lists, these will be replaced by an Address/Bindingsmanager that will do the following.

      One small issue is the management service doesn't support names with *'s in. To be honest i'm not sure whether we would add wild card addresses etc to the management servie, would they need to be accessible by the a management console?

      When an address is added say A.B the address manager will take care of also adding any wildcard addresses that match , say A.* and A.#. The opposite will apply when addresses are removed.
      When a Binding is added that uses a wild card pattern the address manager will also add bindings with the same underlying queue to any addresses that match the wild card, so if a binding with address A.* and queue name subscriber1 was added then as binding with address A.B and the same queue would also be added.

      Doing it this way means that all the work is done during the creation of the bindings and the route method of post office will be just as performant since a single look up will still only be involved.


        • 1. Re: Wild card Subscriptions
          Tim Fox Master

           

          "ataylor" wrote:
          The pattern for wildcard subscriptions will be as follows. * will match against a single word and # will match against 0 or more words delimited by a .. so A.*.C will match A.B.C and A.E.D but not A.B.E.D, and A.B.# will match A.B.C.D or A.B ansd so forth, this is how amqp 0.9 specifies it.

          A simple JMS client using Wild Card Subscriptions will look like the following:

           Topic wildCardTopic = session.createTopic("topic.*");
           MessageConsumer messageConsumer = session.createConsumer(wildCardTopic);
          



          We should also allow a jms client to just create a JBossTopic instance directly specifying the wildcard.

          Also how is this used via the core api?

          Currently in PostOfficeImpl the bindings ad addresses are held in Maps and Lists, these will be replaced by an Address/Bindingsmanager that will do the following.

          One small issue is the management service doesn't support names with *'s in. To be honest i'm not sure whether we would add wild card addresses etc to the management servie, would they need to be accessible by the a management console?

          When an address is added say A.B the address manager will take care of also adding any wildcard addresses that match , say A.* and A.#. The opposite will apply when addresses are removed.
          When a Binding is added that uses a wild card pattern the address manager will also add bindings with the same underlying queue to any addresses that match the wild card, so if a binding with address A.* and queue name subscriber1 was added then as binding with address A.B and the same queue would also be added.

          Doing it this way means that all the work is done during the creation of the bindings and the route method of post office will be just as performant since a single look up will still only be involved.


          • 2. Re: Wild card Subscriptions
            Andy Taylor Master

             

            We should also allow a jms client to just create a JBossTopic instance directly specifying the wildcard.

            Yes definitely, some vendors also use jndi, i.e. jndi.loopup("/topic/atopic/*") but I'mnot sure whether we would want this or how east it would be since we don't have our own jndi impl.

            Also how is this used via the core api?


            At the minute it would need to be something like
             SimpleString wildCardQ = new SimpleString("queuejms.#");
             clientSession.createQueue(wildCardQ, wildCardQ, ......);
             ClientConsumer clientConsumer = clientSession.createConsumer(wildCardQ);
            




            • 3. Re: Wild card Subscriptions
              Tim Fox Master

              I have created a bunch more tests that fail using the current address manager, some come straight from the AMQP spec:

              public void testAddressManager2() throws Exception
               {
               AddressManager am = new WildcardAddressManager();
              
               Binding binding1 = new MyBinding();
              
               am.addMapping(new SimpleString("a.b.c.#"), binding1);
              
               //# should match zero or more words (see AMQP spec 0.10, 2.3.1.3)
               Bindings bindings = am.getBindings(new SimpleString("a.b.c"));
              
               assertTrue(bindings.getBindings().contains(binding1));
               assertEquals(1, bindings.getBindings().size());
               }
              
               public void testAddressManager3() throws Exception
               {
               AddressManager am = new WildcardAddressManager();
              
               Binding binding1 = new MyBinding();
              
               am.addMapping(new SimpleString("a.b.c.#"), binding1);
              
               //# should match zero or more words (see AMQP spec 0.10, 2.3.1.3)
               Bindings bindings = am.getBindings(new SimpleString("a.b.c.d"));
              
               assertTrue(bindings.getBindings().contains(binding1));
               assertEquals(1, bindings.getBindings().size());
               }
              
               public void testAddressManager4() throws Exception
               {
               AddressManager am = new WildcardAddressManager();
              
               Binding binding1 = new MyBinding();
              
               try
               {
               //Should fail, a.b.c# is not a valid key - all tokens should be delimited by '.'
               am.addMapping(new SimpleString("a.b.c#"), binding1);
              
               fail("Should throw exception");
               }
               catch (Exception e)
               {
               //Ok
               }
              
               }
              
               public void testAddressManager5() throws Exception
               {
               AddressManager am = new WildcardAddressManager();
              
               Binding binding1 = new MyBinding();
              
               try
               {
               am.addMapping(new SimpleString("#a.b.c"), binding1);
              
               fail("Should throw exception");
               }
               catch (Exception e)
               {
               //Ok
               }
              
               }
              
               public void testAddressManager6() throws Exception
               {
               AddressManager am = new WildcardAddressManager();
              
               Binding binding1 = new MyBinding();
              
               try
               {
               am.addMapping(new SimpleString("#*a.b.c"), binding1);
              
               fail("Should throw exception");
               }
               catch (Exception e)
               {
               //Ok
               }
              
               }
              
               public void testAddressManager7() throws Exception
               {
               AddressManager am = new WildcardAddressManager();
              
               Binding binding1 = new MyBinding();
              
               try
               {
               //Should fail, a.b.c* is not a valid key - all tokens should be delimited by '.'
               am.addMapping(new SimpleString("a.b.c*"), binding1);
              
               fail("Should throw exception");
               }
               catch (Exception e)
               {
               //Ok
               }
              
               }
              
               public void testAddressManager8() throws Exception
               {
               AddressManager am = new WildcardAddressManager();
              
               Binding binding1 = new MyBinding();
              
               try
               {
               am.addMapping(new SimpleString("*a.b.c"), binding1);
              
               fail("Should throw exception");
               }
               catch (Exception e)
               {
               //Ok
               }
              
               }
              
               public void testAddressManager9() throws Exception
               {
               AddressManager am = new WildcardAddressManager();
              
               Binding binding1 = new MyBinding();
              
               try
               {
               am.addMapping(new SimpleString(".."), binding1);
              
               fail("Should throw exception");
               }
               catch (Exception e)
               {
               //Ok
               }
              
               }
              
               public void testAddressManager10() throws Exception
               {
               AddressManager am = new WildcardAddressManager();
              
               Binding binding1 = new MyBinding();
              
               //Should fail, a.b.c# is not a valid key - all tokens should be delimited by '.'
               am.addMapping(new SimpleString("*.stock.#"), binding1);
              
               Bindings bindings = am.getBindings(new SimpleString("usd.stock"));
              
               assertTrue(bindings.getBindings().contains(binding1));
               }
              
               public void testAddressManager11() throws Exception
               {
               AddressManager am = new WildcardAddressManager();
              
               Binding binding1 = new MyBinding();
              
               //Should fail, a.b.c# is not a valid key - all tokens should be delimited by '.'
               am.addMapping(new SimpleString("*.stock.#"), binding1);
              
               Bindings bindings = am.getBindings(new SimpleString("eur.stock.db"));
              
               assertTrue(bindings.getBindings().contains(binding1));
               }
              
               public void testAddressManager12() throws Exception
               {
               AddressManager am = new WildcardAddressManager();
              
               Binding binding1 = new MyBinding();
              
               //Should fail, a.b.c# is not a valid key - all tokens should be delimited by '.'
               am.addMapping(new SimpleString("*.stock.#"), binding1);
              
               Bindings bindings = am.getBindings(new SimpleString("stock.nasdaq"));
              
               assertNull(bindings.getBindings());
               }
              


              • 4. Re: Wild card Subscriptions
                Andy Taylor Master

                regarding test2 i would say that a.b.c doesn't match a.b.c.#, wheres the 4th dot, or should we ignore that. The other tests expecting exceptions to be thrown for "invalid" bindings such as a.b.c#, could thgis not be a valid destination in JMS.

                • 5. Re: Wild card Subscriptions
                  Tim Fox Master

                   

                  "ataylor" wrote:
                  regarding test2 i would say that a.b.c doesn't match a.b.c.#, wheres the 4th dot, or should we ignore that. The other tests expecting exceptions to be thrown for "invalid" bindings such as a.b.c#, could thgis not be a valid destination in JMS.


                  Read the spec, it's all in there ;)

                  • 6. Re: Wild card Subscriptions
                    Tim Fox Master

                    From the spec:

                    "The binding key is formed using zero or more tokens, with each token delimited by the '.' char. The binding key
                    MUST be specified in this form and additionally supports special wild-card characters: '*' matches a single word and
                    '#' matches zero or more words.
                    Thus the binding key "*.stock.#" matches the routing keys "usd.stock" and "eur.stock.db" but not "stock.nasdaq".
                    "



                    ^^^ That should answer your question about the 4th dot.

                    Regarding "invalid" bindings, in second thoughts we should probably allow those addresses since they are valid JMS names.

                    However we should add tests that e.g.

                    a.b.c DOES NOT match a.b.c# (since it doesn't according to AMQP rules)

                    • 7. Re: Wild card Subscriptions
                      Andy Taylor Master

                      ok I'll fix the zero bindings problem and add some tests.