13 Replies Latest reply on Oct 23, 2003 9:59 AM by Raja

    Stopping delivery of message

    Stephane Nicoll Master

      Hello,

      I need to stop the delivery of a destination (a Queue) at runtime. (maybe through JMX?) and inside my code (no manual intervention) Let me explain.

      I would like the queue to be available for new messages (i.e. new messages can be posted on the queue) but the delivery is disable for some time (i.e. the onMessage of any MDB attached to this queue is not fired).

      I would like to achieve this behavior on a queue-per-queue basis (not global to the JMS server)

      I am using latest 3.2.2

      Regards,

      Stephane

        • 1. Re: Stopping delivery of message
          Raja Master

          A Quick solution i can think of is to deploy the MDB as a separate jar file, get the Objectname of the EJB(from jmx-console) and then call the stop method on that EJBDeployer. This way, the Sender can keep publishing the messages but unless u start the EJB back again, your messages will be waiting in the queue. Hope this is what you want. ;-)

          -Raj

          • 2. Re: Stopping delivery of message
            Stephane Nicoll Master

            Unfortunately no !

            I cannot change my deployment procedure

            Regards,

            Stephane

            • 3. Re: Stopping delivery of message
              Raja Master

              I just did a check on my ear file . Even though there are multiple ejbs in my jar file, there is a separate entry for each EJB in the JMX-console, something like

              jndiName=......,service=EJB

              If you can retrieve this for ur MDB, you can as well call the stop method on it. So you dont have to create another jar file just for ur MDBs

              -Raj

              • 4. Re: Stopping delivery of message
                Stephane Nicoll Master

                That's a great idea :)
                I will check and let you know

                Thanks!

                Stephane

                • 5. Re: Stopping delivery of message
                  Raja Master

                  It was an interesting little project and i was able to stop the mdb from receiving any more messages. But when i want to restart it back, i got this exception
                  Cause: org.jboss.deployment.DeploymentException: Could not set up environment; - nested throwable: (javax.naming.NameAlreadyBoundException; remaining name 'env')

                  I was able to lookup my mdb and call a stop on it and it still was able to process one message after stop is called. After one message, it wasnt able to process the rest of it. Maybe it was something in the queue for performance reasons. I have seen in Weblogic that it does a prefetch when one message is in progress , maybe its something like that.

                  But when icall start after stopping the mdb, i got the above exception, Any ideas?

                  Im also posting the SAR File

                  Thanks
                  Raj


                  public class SAR extends ServiceMBeanSupport implements SARMBean
                  {
                  private ObjectName mdb;

                  public ObjectName getMdb()
                  {
                  return this.mdb;
                  }

                  public void setMdb(ObjectName mdb)
                  {
                  this.mdb = mdb;
                  }


                  protected void startService() throws Exception {
                  }

                  protected void stopService() throws Exception {

                  }

                  //Call the Stop method on the Object name
                  public void tempStop() throws Exception {
                  getServer().invoke(this.mdb, "stop", new Object[] {}, new String[] {});
                  }

                  //Call Start method on MDB
                  public void tempStart() throws Exception {
                  getServer().invoke(this.mdb, "start", new Object[] {}, new String[] {});
                  }

                  }

                  • 6. Re: Stopping delivery of message
                    ovs_nagi Newbie

                    HI,
                    Have a property say "status" on the message which says to "hold" or "run" the message. then when u want to stop the onMessage, start a message listener and change the status to "hold" and requeue. this status would be checked to process the message in onMessage method.

                    Hope this helps.

                    -nagi

                    • 7. Re: Stopping delivery of message
                      Stephane Nicoll Master

                      In theory it could. Sounds tricky to me however.

                      Cheers,

                      Stephane

                      • 8. Re: Stopping delivery of message
                        Stephane Nicoll Master

                        It worked stopping the associated EJB Mbean (see MBean posted above)

                        Thanks to all

                        Stephane

                        • 9. Re: Stopping delivery of message
                          Raja Master

                          Were you able to start it back using the tempStart method in the MBean? I couldnt get it to work as it was trying to bind the "env" namespace(Which was bound already). I havent looked at tweaking it yet but maybe u got it to work. I tried this on JBoss 3.0.7

                          -Raj

                          • 10. Re: Stopping delivery of message
                            Stephane Nicoll Master

                            Here is the MBean I used which is a test. It uses hard coded MDB (test - one Mbean, test2 - two mbeans)

                            package com.kiala.j2ee.service;

                            import org.jboss.system.ServiceMBeanSupport;

                            import javax.management.*;

                            /**
                            * MBean that allows to stop/start a Driver. This
                            * is tricky since all information are hard coded
                            * but this could be easily extended.
                            *
                            * In the case there is more that one MBean to start we should take
                            * care to start the 'default' MDB at the end (that is start MDB with
                            * specific selector first so they can fetch THEIR messages and stop
                            * the other one afterwards). The reverse should be done when stopping
                            * the driver (stop the default one first, then stop the specific ones)
                            *
                            * @jmx:mbean name="Driver Manager Service"
                            * description="An MBean that allows to manager drivers (start/stop)"
                            * extends="org.jboss.system.ServiceMBean"

                            * @author Stephane Nicoll <stephane.nicoll@skynet.be>
                            * @author $Author$ (last edit)
                            * @version $Revision$
                            *
                            * Created: 22-oct.-2003 13:00:48
                            */
                            public class DriverManagerService extends ServiceMBeanSupport
                            implements DriverManagerServiceMBean {

                            private static org.apache.log4j.Logger logger =
                            org.apache.log4j.Logger.getLogger(DriverManagerService.class.getName());

                            protected final static String START_OPERATION = "start";
                            protected final static String STOP_OPERATION = "stop";

                            protected final static String MDB_TEST_OBJECT_NAME = "jboss.j2ee:jndiName=local/TestMDB,service=EJB";
                            protected final static String STUFF_MDB_TEST2_OBJECT_NAME = "jboss.j2ee:jndiName=local/Test2MDB,service=EJB";
                            protected final static String DEFAULT_MDB_TEST2_OBJECT_NAME = "jboss.j2ee:jndiName=local/Test2DefaultMDB,service=EJB";


                            /**
                            * Stops the specified driver. No further messages are delivered to that driver.
                            * Note that services are still able to send messages to the queue but they
                            * won't be collected.
                            * @param driverName the name of the driver, e.g. 'NodeSynch', 'Notification'
                            * @return true if the driver was stopped successfully, false otherwise
                            * @throws IllegalArgumentException if the driver name is unknown
                            *
                            * @jmx:managed-operation
                            */
                            public boolean stopDriver(String driverName) {
                            try {
                            ObjectName[] objectNames = getObjectNames(STOP_OPERATION, driverName);
                            for (int i = 0; i < objectNames.length; i++) {
                            ObjectName objectName = objectNames;
                            logger.debug("Stopping ["+objectNames+"]");
                            getServer().invoke(objectName, "stop", new Object[]{}, new String[]{});
                            logger.info("Stopped ["+objectNames+"]");
                            }
                            return true;
                            } catch (MalformedObjectNameException e) {
                            logger.error("", e);
                            } catch (InstanceNotFoundException e) {
                            logger.error("", e);
                            } catch (MBeanException e) {
                            logger.error("", e);
                            } catch (ReflectionException e) {
                            logger.error("", e);
                            }
                            return false;
                            }

                            /**
                            * Starts the specified driver. Incoming messages will be immediately delivered
                            * to the driver.
                            * @param driverName the name of the driver, e.g. 'NodeSynch', 'Notification'
                            * @return true if the driver was started successfully, false otherwise
                            * @throws IllegalArgumentException if the driver name is unknown
                            *
                            * @jmx:managed-operation
                            */
                            public boolean startDriver(String driverName) throws IllegalArgumentException {
                            try {
                            ObjectName[] objectNames = getObjectNames(START_OPERATION, driverName);
                            for (int i = 0; i < objectNames.length; i++) {
                            ObjectName objectName = objectNames
                            ;
                            logger.debug("Starting ["+objectNames+"]");
                            getServer().invoke(objectName, "start", new Object[]{}, new String[]{});
                            logger.info("Started ["+objectNames+"]");
                            }
                            return true;
                            } catch (MalformedObjectNameException e) {
                            logger.error("", e);
                            } catch (InstanceNotFoundException e) {
                            logger.error("", e);
                            } catch (MBeanException e) {
                            logger.error("", e);
                            } catch (ReflectionException e) {
                            logger.error("", e);
                            }
                            return false;
                            }

                            /**
                            * This is a tricky method we should redefine. It returns, based on a driver, the
                            * entity to stop/start (as a driver might have multiple MDB attached on it). The
                            * order of the object is the one that should be used to invoke the operation.
                            * @param operation the operation to invoke on the objects
                            * @param driverName the driver's name
                            * @return an array of ObjectNames
                            * @throws IllegalArgumentException if the driver is unknown
                            * @throws MalformedObjectNameException if an object name is incorrect
                            */
                            protected ObjectName[] getObjectNames(String operation, String driverName)
                            throws IllegalArgumentException, MalformedObjectNameException {
                            if (driverName == null)
                            throw new IllegalArgumentException("Unknown driver [" + driverName + "]");
                            if (operation == null)
                            throw new IllegalArgumentException("Unknown operation [" + driverName + "]");

                            // test is a simple example with one Mbean
                            if (driverName.equals("test")) {
                            // only one MDB so do not care about operation
                            ObjectName mdb = new ObjectName(MDB_TEST_OBJECT_NAME);
                            return new ObjectName[]{mdb};
                            // test2 is a simple example with two Mbean
                            } else if (driverName.equals("test2")) {
                            ObjectName defaultMDB = new ObjectName(DEFAULT_MDB_TEST2_OBJECT_NAME);
                            ObjectName stuffMDB = new ObjectName(STUFF_MDB_TEST2_OBJECT_NAME);
                            if (operation.equals(START_OPERATION)) { // specific at the end
                            return new ObjectName[]{stuffMDB, defaultMDB};
                            } else if (operation.equals(STOP_OPERATION)) { // specific first
                            return new ObjectName[]{defaultMDB, stuffMDB};
                            } else
                            throw new IllegalArgumentException("Unknown operation ["+operation+"]");
                            } else
                            throw new IllegalArgumentException("Unknown driver [" + driverName + "]");
                            }

                            protected void startService() throws Exception {
                            }

                            protected void stopService() throws Exception {
                            }
                            }


                            Regards,

                            Stephane

                            • 11. Re: Stopping delivery of message
                              Raja Master

                              Thanks for the code. Were you able to start the MDB Service successfully after stopping it ?

                              What version do you use?

                              -Raj

                              • 12. Re: Stopping delivery of message
                                Stephane Nicoll Master

                                Yes. So basically what I have is:

                                One queue Test with an MDB on it
                                One queue Test2 with two MDBs on it (one with a selector, one default without a selector)

                                I have two MBean, the one I gave you and another one which is used to send XXX msgs to a queue.

                                Using the JMX console I send message to both queue which were consumed. Then I stopped queue Test and did the same things, only Test2's messages were consumed. Then using the JMX console again, I restarted Test MDBs after a while and I saw Test's messages being consumed.

                                I used 3.2.2 but I sent my code to my colleagues which are running 3.2.1 and I did not received any complain.

                                Any further help, let me know.

                                Regards,

                                Stephane

                                • 13. Re: Stopping delivery of message
                                  Raja Master

                                  Oh Okay, that explains it. Versions 3.2.x contain code to teardown the environment by doing an unbind("env") when the stopService() is called. This code is not present in 3.0.7

                                  -Raj