The Store-and-Forward client feature

Since Version 9.2, Weblogic Server has this neat feature called the Store-and-Forward (SAF) client, which enables a JMS remote client to keep messages locally whenever a connection problem occurs with the server. When the connection is re-established, the messages are delivered.

From a developer's viewpoint, this behavior is almost transparent—our code will complete the procedure without any errors, as if the message were actually delivered to its destination queue. This is a great feature to use when network outages are frequent, or even when you only have a specific time window to communicate with the server—instead of dealing with all the batching details from inside your code, you just delegate this responsibility to the JMS transport.

Also, the changes you have to apply to your code in order to enable the SAF client are pretty simple. The following is a typical set of parameters that we must declare in order to acquire a server connection and use a JMS queue:

Context.INITIAL_CONTEXT_FACTORY=weblogic.jndi.WLInitialContextFactory
Context.SECURITY_PRINCIPAL=weblogic
Context.SECURITY_CREDENTIALS=welcome1
Context.PROVIDER_URL=t3://localhost:7001

QUEUE_CONNECTION_FACTORY=jms/yourQueueConnectionFactory
QUEUE_NAME=jms/yourQueue

Tip

The preceding lines aren't the actual code, just key/value pairs showing parameters that are usually declared (or read from a properties file) to open a remote connection and acquire a queue.

To enable the JMS SAF client, we basically use the same set of parameters by dropping one and changing the other three:

Context.INITIAL_CONTEXT_FACTORY=          
                weblogic.jms.safclient.jndi.InitialContextFactoryImpl
Context.SECURITY_CREDENTIALS=packt
Context.PROVIDER_URL=file:/opt/packt/etc/SAFClient.xml

QUEUE_CONNECTION_FACTORY=jms/yourQueueConnectionFactory
QUEUE_NAME=jms/yourQueue

The following is a description of the changes:

  • The PROVIDER_URL parameter must point to a configuration file generated by a command-line utility, ClientSAFGenerate. We're going to set up this file just after this block.
  • The INITIAL_CONTEXT_FACTORY parameter must point to a class named weblogic.jms.safclient.jndi.InitialContextFactoryImpl that knows how to parse the file provided by Context.PROVIDER_URL.
  • The SECURITY_PRINCIPAL parameter declares the username necessary to establish a connection to the server. When using the SAF client, though, this information is inside the XML file referred by PROVIDER_URL, so we don't need to use it when acquiring the server connection.
  • The SECURITY_CREDENTIALS parameter usually holds the user's password that will open the connection. When using the SAF client, this credential is also put inside the XML file, but we still need this entry—it will hold a password key that the engine must use to decrypt the password inside the configuration file.

We don't need to change anything else in the code other than these set of parameters, so the portion of code that deals with acquiring a handle to the JMS queue and posts a message to it remains unchanged.

Note

When using the SAF client, there's one caveat that you must be aware of: the messages you post will always reach the local repository first, and then they will be delivered to the appropriate server. By default, the SAF client holds the message for 20 seconds before trying to send it to the server.

So, if your client isn't designed to stay in memory, for instance, listening to a TCP port for incoming messages, you must tweak this configuration to avoid having all messages kept at the local store. We will see how to do it shortly.

One final observation: the SAF client doesn't participate in distributed transactions (XA). If your design has this kind of requirement, you can either use the SAF client knowing that it runs local transactions ( it doesn't influence any XA transactions that may be in course) or not use it at all.

The following is the sequence of steps we must execute in order to enable the SAF client:

  1. Create the configuration file that points to the queue(s) we want to use.
  2. Encrypt the connection password.
  3. Edit the configuration file and add the encrypted password.
  4. Add a reference to the SAF client in our code.

Let's do it.

Creating the configuration file

Almost all the information that the SAF client needs to connect to a server is located inside a configuration file created by the ClientSAFGenerate utility. Here's how we create it:

  1. Open a terminal or a command prompt, and run the domain configuration script, setDomainEnv.sh (on Windows, setDomainEnv.cmd), to set up the environment—you can find it inside the bin folder of your domain:
    $ cd $DOMAIN_HOME/tickets/bin
    $ source ./setDomainEnv.sh
    
  2. Now, go to /config/jms inside the domain—WebLogic Server creates one file for each JMS system module that you declare and saves them inside the subfolder of your domain:
    $ cd ../config/jms
    $ ls –w1
    jmsmodule-tickets-jms.xml
    
  3. Issue the following command to create the configuration file, adjusting the parameters according to your installation (check whether the output folder exists before running the command):
    $ java weblogic.jms.extensions.ClientSAFGenerate
                -url t3://localhost:7001
                -username weblogic
                -moduleFile jmsmodule-tickets-jms.xml
                -outputFile /opt/packt/etc/SAFClient.xml

    Note

    If you need to map more than one JMS module, use the same command but add a -existingClientFile parameter pointing to the already created configuration file to append the new values, and keep everything else as is.

Leave the terminal open, we will use it again later. The utility doesn't connect to the server to gather information, as the URL and username parameters could imply—they are used to create the appropriate entries in the configuration file—so take extra care when typing them.

If everything went well, the /opt/packt/etc/SAFClient.xml file has been created with a reference to our destination queue and information about the connection:

  <saf-imported-destinations name="jmsmodule-tickets">
    <saf-queue name="ExhibitionQueue">
      <remote-jndi-name>jms.tickets.exhibition</remote-jndi-name>
      <local-jndi-name>jms.tickets.exhibition</local-jndi-name>
    </saf-queue>
    <saf-remote-context>RemoteContext0</saf-remote-context>
  </saf-imported-destinations>
  <saf-remote-context name="RemoteContext0">
    <saf-login-context>
      <loginURL>t3://localhost:7001</loginURL>
      <username>weblogic</username>
    </saf-login-context>
  </saf-remote-context>
</weblogic-client-jms>

Note

If you're using a cluster, you may want to set the loginURL entry to address all your WebLogic servers—for instance, t3://node1:7001, node2:7011, and so on. If the first node is down for some reason, the client tries to reach the next one and then the next, until a connection is established.

Encrypting the connection password

We must encrypt the connection password inside the configuration file, but the utility that generates it doesn't accept a password parameter, so we must create it using another application:

  1. At the same terminal opened in the previous section, run this command:
     java -Dweblogic.management.allowPasswordEcho=true
           weblogic.jms.extensions.ClientSAFEncrypt
  2. It will ask you to enter Password Key—this is a password that we will pass to the SAF client so it can decrypt the connection password. Enter a value—we will use packt—and hit Enter.
  3. Now, in the Password prompt, enter the user's actual password—welcome1 if you're following the book standard—and hit Enter.
  4. The encrypted password will be shown; copy it so we can place the whole tag inside the configuration file:
    <password-encrypted>{Algorithm}AES/CBC/PKCS5Padding{Salt}OMDCZlaTWng={IV}KCcjtoVJqxYeQXvmKukpmg=={Data}Sm1TYOAlERODdHKHqKvGwaNU/YZuJXIhn/THV9+yel8=</password-encrypted>
  5. You can encrypt other passwords or type quit to exit the utility. As we have just one value, go ahead and finish it.

Adjusting the configuration file

There are three things we must add to the configuration file, SAFClient.xml, so open it with a text editor and proceed with the following changes:

  1. Paste the whole password-encrypted generated tag just below the username tag:
    <saf-remote-context name="RemoteContext0">
      <saf-login-context>
        <loginURL>t3://localhost:7001</loginURL>
        <username>weblogic</username>
        <password-encrypted>{Algorithm} … </password-encrypted>
      </saf-login-context>
    </saf-remote-context>
  2. As we adopted one of the default WebLogic's JMS connection factory, we need to add its declaration to the configuration file, just before the saf-imported-destinations tag:
      <connection-factory name="wls.default">
        <jndi-name>weblogic.jms.ConnectionFactory</jndi-name>
        <transaction-params>
          <xa-connection-factory-enabled>false
             </xa-connection-factory-enabled>
        </transaction-params>
      </connection-factory>

    Note

    When you create your own JMS connection factories, they exist inside a JMS module, as you may remember. As the ClientSAFGenerate utility maps a JMS module, you won't have to execute this extra step to add a JMS connection factory to the configuration file.

  3. As our remote client has a very short lifespan, we must change SAF's posting delay to 0, so as soon as a message is sent from our code, it will try to deliver the message to the server. To do it, add this block of tags after the connection-factory block we just inserted:
    <saf-agent>
     <default-retry-delay-base>0</default-retry-delay-base>
    </saf-agent>
  4. Save and close the file.

We just have to change a few lines of code of our Enqueue class to be able to use the SAF client feature.

Adjusting the code

As said earlier, we need to change three connection parameters: provider_url, the user password, A.K.A security credentials, and the JNDI connection factory. The following are the current relevant lines of code:

static final String WLS_ADDRESS = 
          "t3://localhost:7001";
static final String WLS_CTX_FACTORY =
          "weblogic.jndi.WLInitialContextFactory";

env.put(Context.SECURITY_CREDENTIALS, "welcome1");

They must be changed to something similar to the following code:

// Points to the configuration file
static final String WLS_ADDRESS = 
          "file:/opt/packt/etc/SAFClient.xml";

// Must have this exact value – it's the SAF Context Factory
static final String WLS_CTX_FACTORY =
          "weblogic.jms.safclient.jndi.InitialContextFactoryImpl";

// The password you use to encrypt the login password
env.put(Context.SECURITY_CREDENTIALS, "packt");

Also, we can comment the line that attaches a user to the context, as this information is already in the configuration file:

// env.put(Context.SECURITY_PRINCIPAL, "weblogic");

Note

If you want, you can leave the line as it is, but remember that this information is not considered. The SAF client expects to find a username tag in the configuration file, and an exception will be thrown if this condition isn't satisfied.

We now have to add the SAF T3 client library to the project's classpath:

  1. Open the Project Properties window for the project RemoteClient.
  2. Click on Java Build Path present in the list to the left.
  3. Click on the Libraries tab, then on Add External JARs….
  4. Navigate to the server library folder, the same folder where you found the wlthint3client.jar library, select and click on wlsaft3client.jar, and then click on Enter.
  5. Click on OK in the Project Properties window.

And we're good to go.

Testing the SAF client

This is the easiest part, just run the remote client a couple of times!

When the application is started, you will see a group of messages in the console stating that the SAF client has been initialized:

<Thu Dec 13 12:05:56 BRST 2012> <Info> <Store> <WL-280008> <Opening the persistent file store "SAFSTORE0V" for recovery: directory=/opt/packt/etc/stores/default requestedWritePolicy="Direct-Write" fileLockingEnabled=true driver="NIO".> 
<Thu Dec 13 12:05:57 BRST 2012> <Info> <Store> <WL-280009> <The persistent file store "SAFSTORE0V" (91256ed7-83b7-4b9d-a9c5-61831fe5bb74) has been opened: blockSize=512 actualWritePolicy="Direct-Write(single-handle-buffered)" explicitIOEnforced=false records=11.> 
<Thu Dec 13 12:05:58 BRST 2012> <Info> <Messaging> <WL-282003> <The messaging kernel ClientSAFAgent0 will use up to 318,155,434 bytes of memory before paging begins.> 
<Thu Dec 13 12:05:58 BRST 2012> <Info> <Messaging> <WL-282001> <The messaging kernel ClientSAFAgent0 is beginning recovery of its persistent state.> 
<Thu Dec 13 12:05:58 BRST 2012> <Info> <Messaging> <WL-282002> <The messaging kernel ClientSAFAgent0 has recovered 0 persistent messages.> 
<Thu Dec 13 12:05:58 BRST 2012> <Info> <Messaging> <WL-282003> <The messaging kernel ClientSAFAgent0 will use up to 318,155,434 bytes of memory before paging begins.> 

Then, after a few seconds, another message will be printed stating that the client acquired a connection to the server:

Agent "ClientSAFAgent0" got connected to RemoteContext0 while processing messages for ExhibitionQueue

To test the feature, you can stop WebLogic Server and post a few messages, then start it and run the remote client one more time. When you do this, the client will print recurrent error messages, but that's fine. Notice that one of the console messages prints the number of JMS messages being held by the SAF client:

<WL-282002> <The messaging kernel ClientSAFAgent0 has recovered 4 persistent messages.> 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.211.166