2 Replies Latest reply on May 14, 2012 6:19 PM by John Gregg

    SAF client and multiple threads

    John Gregg

      One of my JMS clients does not run in WL and I'm experimenting with the standalone SAF client (wlfullclient generated from WLS 10.3.3) on his behalf. There are a couple of things I don't understand.

      For testing purposes, I created a simple client that connects, sends a message, and disconnects/exits. The message gets successfully written to the SAF store but does not actually get delivered. Additionally, if I try to send multiple messages at once, they get written to the store but not sent. I interpreted this statement [in the docs|http://docs.oracle.com/cd/E12840_01/wls/docs103/client/saf_client.html] to mean the messages would be sent ASAP, assuming the provider was available:

      "With the standard JNDI lookup, the JMS SAF client is started automatically..."

      I guess this means the client is started in the sense that messages can be written to the store, but they will not actually be delivered to the final destination without some other intervention. Is that right?

      Assuming I have to explicitly start the ClientSAF facility, I wrote a little code to call ClientSAFFactory.getClientSAF(rootDirectory, in).open(). Since this method blocks, I put it in another thread, then tried to invoke my send test again. This time, send failed because it could not get a lock on the persistent store:
      javax.naming.NamingException: weblogic.store.PersistentStoreException: [Store:280105]The persistent file store "SAFSTORE0V" cannot open file SAFSTORE0V000000.DAT. [Root exception is weblogic.jms.common.JMSException: weblogic.store.PersistentStoreException: [Store:280105]The persistent file store "SAFSTORE0V" cannot open file SAFSTORE0V000000.DAT.]
           at weblogic.jms.safclient.jndi.InitialContextFactoryImpl.getNamingException(InitialContextFactoryImpl.java:31)
           at weblogic.jms.safclient.jndi.InitialContextFactoryImpl.getInitialContext(InitialContextFactoryImpl.java:162)
           at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
           at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:247)
           at javax.naming.InitialContext.init(InitialContext.java:223)
           at javax.naming.InitialContext.<init>(InitialContext.java:197)
           at jms.JMSFileSender.main(JMSFileSender.java:88)
           at jms.saf.Shell.main(Shell.java:48)
           at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
           at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
           at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
           at java.lang.reflect.Method.invoke(Method.java:592)
           at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
      As you can see, the exception is thrown when I tried to create the SAF initial context. Note that this is in the same java process as the thread that has the thread that has the store open already. I seem to have a catch-22. Not calling open() on the ClientSAF prevents my messages from actually being delivered. Calling open() delivers them, but while it's open any SAF clients will fail on initial context creation. How is this supposed to work?


      Edited by: John Gregg on May 14, 2012 9:11 AM
        • 1. Re: SAF client and multiple threads
          Dongbo Xiao-Oracle
          With client saf, once the client does the look up of the destination, the saf forwarder is started and ready to forward messages. Once the messages are sent, the messages should be stored locally and then be forwarded to the remote destination as long as the remote destination is up running.

          I don't have a clear picture of your entire saf configuration. The following are things that you can check.
          1. The remote destination has to be a WLS destination. You mentioned that this client of yours does not use WLS. I am not sure if the remote destination is a WLS destination.
          2. The remote destination is up running when messages are sent. If your remote destination starts after the saf client looks up the destination, the saf forwarder may fail and gets into its retry logic; there will be delays between retry attempts.
          3. You can always turn on saf debugging, which may help you to figure out what is going on. -Dweblogic.debug.DebugJMSSAF=true.

          Hope this helps.
          • 2. Re: SAF client and multiple threads
            John Gregg
            Thanks for the feedback.

            The remote destination in WLS 9.2 and has been up the whole time.

            My initial test was plain vanilla JMS code to send a single message. I looked up the cxn factory and destination, created a producer, sent a message, etc. Immediately after sending the message, I close the various JMS resources and the initial context and the jvm exited. No message was sent, but when I ran the test the next time, I see "<May 14, 2012 12:50:53 PM CDT> <Info> <Messaging> <BEA-282002> <The messaging kernel ClientSAFAgent0 has recovered 1 persistent messages>" in the log. That means my previous message was queued but not sent.

            I put Thread.sleep(60000) in there after sending but before closing/exiting and eventually saw the messages sent. This is good news.

            I also tried a loop where I went through a complete cycle to send 1 message per iteration. In each iteration, I created the initial context, did the jndi lookups, sent a message, closed the jms artifacts, and closed the initial context. Even with a Thread.sleep() in each iteration to bring the total time to execute multiple loops to 1 minute, no messages were sent. Does closing the initial context shut down the agent? That is a very ugly side effect.

            My next test was just to call ClientSAF.open(). It was a little slow to initialize, but it found the stored messages and sent them.

            Finally I combined these two tests into a single jvm with multiple threads. On one thread I called ClientSAF.open(). I waited until the output said the agent was initialized, then I tried to send a message using the plain vanilla JMS code again, but this time in a different thread in the same JVM. This is where I got the error about being unable to lock the store.

            I don't understand this. Let's say a client app runs in JBoss and wants to use SAF to send to WL JMS. Obviously there could be multiple threads all trying to send messages, which includes writing them to the store, and at least one other thread trying to read messages from the store and forward them to the destination. They must all be able to work with the same file simultaneously. I assumed the agent would manage this, but it appears that it does not. If not,then the only way I can see client SAF being useful is to either keep the initial context open forever or programatically start and stop the agent after each message send operation. Either way is pretty ugly.