JMS/XLA Usage and Functionality

There are key aspects when using JMS/XLA.

Connecting to XLA

To connect to XLA so you can receive updates:

  1. Create the appropriate JMS connection factory depending on whether your application uses the JMS API version 1.1 or the Jakarta Messaging API version 1.1 using the property Context.INITIAL_CONTEXT_FACTORY when creating the initial context.
    • For Jakarta Messaging API version 1.1, use the value com.timesten.dataserver.jakartajmsxla.SimpleInitialContextFactory.
    • For JMS API version 1.1, use the value com.timesten.dataserver.jmsxla.SimpleInitialContextFactory.

    If the property is not specified, then TimesTen JMS/XLA will default to the JMS API version 1.1 provider unless download-directory/jakarta.jms-api-3.1.0.jar or download-directory/jakarta.jms-api-3.0.0.jar is present in the CLASSPATH, in which case, TimesTen JMS/XLA will use the Jakarta Messaging API version 1.1 provider. The JARs jakarta.jms-api-3.1.0.jar and jakarta.jms-api-3.0.0.jar contains the class jakarta.jms.TopicConnectionFactory required for the Jakarta Messaging API version 1.1 provider. See Setting the Classpath for Java Development.

  2. Use the JMS connection factory to create a connection.
  3. Use the connection to establish a session.
  4. When you are ready to start processing updates, call start() on the connection to enable message dispatching.

The following example is from the asyncJMS2 sample program for Jakarta JMS in the TimesTen Classic Quick Start sample application. See About TimesTen Quick Start and Sample Applications.

    /** JMS connection */
    private jakarta.jms.TopicConnection connection; 
    ...
    //jakarta jms

      Properties props = new Properties();

      props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
      "com.timesten.dataserver.jakartajmsxla.SimpleInitialContextFactory");
        

        // get Connection
        Context messaging = new InitialContext(props); 
        TopicConnectionFactory connectionFactory = (TopicConnectionFactory)messaging.lookup("TopicConnectionFactory"); 
        connection = connectionFactory.createTopicConnection(); 
        connection.start(); 

        // get Session
        log("create session"); 
        session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); 
    ...

For JavaX JMS, refer to the asyncJMS sample program instead in the TimesTen Classic Quick Start.

Monitoring Tables for Updates

Before you can start receiving updates, you must inform XLA which tables you want to monitor for changes.

To subscribe to changes and turn on XLA publishing for a table, call the ttXlaSubscribe built-in procedure through JDBC.

When you use ttXlaSubscribe to enable XLA publishing for a table, you must specify parameters for the name of the table and the name of the bookmark that are used to track the table:

ttXlaSubscribe(user.table, mybookmark)

For example, call ttXlaSubscribe by the JDBC CallableStatement interface:

Connection con;

CallableStatement cStmt;
...
cStmt = con.prepareCall("{call ttXlaSubscribe(user.table, mybookmark)}");
cStmt.execute();

Use ttXlaUnsubscribe to unsubscribe from the table during shutdown. For more information, see Unsubscribe from a Table.

The application can verify table subscriptions by checking the SYS.XLASUBSCRIPTIONS system table.

For more information about using TimesTen built-in procedures in a Java application, see Using CALL to Execute Procedures and Functions.

Note:

LOB support in JMS/XLA is limited, as follows:

  • You can subscribe to tables containing LOB columns, but information about the LOB value itself is unavailable.

  • Columns containing LOBs are reported as empty (zero length) or null (if the value is actually NULL). In this way, you can tell the difference between a null column and a non-null column.

See the next section, Receiving and Processing Updates, for additional notes.

Receiving and Processing Updates

You can receive XLA updates either synchronously or asynchronously.

To receive and process updates for a topic synchronously, perform the following tasks.

  1. Create a durable TopicSubscriber instance to subscribe to a topic.

  2. Call receive() or receiveNoWait() on your subscriber to get the next available update.

  3. Process the returned MapMessage instance.

To receive and process updates for a topic asynchronously, perform the following tasks.

  1. Create a MessageListener instance to process the updates.

  2. Create a durable TopicSubscriber instance to subscribe to a topic.

  3. Register the MessageListener with the TopicSubscriber.

  4. Start the connection.

    Note:

    You may miss messages if you do not register the MessageListener before you start the connection. If the connection is already started, stop the connection, register the MessageListener, then start the connection.

  5. Wait for messages to arrive. You can call the Object method wait() to wait for messages if your application does not have to do anything else in its main thread.

When an update is published, the MessageListener method onMessage() is called and the message is passed in as a MapMessage instance.

The application can verify table subscriptions by checking the SYS.XLASUBSCRIPTIONS system table.

Note:

LOB support in XLA is limited. You can access LOB fields in update messages using the MapMessage method getBytes() for BLOB fields or getString() for CLOB or NCLOB fields; however, these fields contain zero-length data (or null data if the value is actually NULL).

The following example, from the asyncJMS TimesTen Classic Quick Start sample application, uses a listener to process updates asynchronously.

MyListener myListener = new MyListener(outStream);

outStream.println("Creating consumer for topic " + topic);
Topic xlaTopic = session.createTopic(topic);
bookmark = "bookmark";
TopicSubscriber subscriber = session.createDurableSubscriber(xlaTopic, bookmark);

// After setMessageListener() has been called, myListener's onMessage
// method is called for each message received.
subscriber.setMessageListener(myListener);

Note that bookmark must already exist. You can use JDBC and the ttXlaBookmarkCreate built-in procedure to create a bookmark. Also, the TopicSubscriber must be a durable subscriber. XLA connections are designed to be durable. XLA bookmarks make it possible to disconnect from a topic and then reconnect to start receiving updates where you left off. The string you pass in as the subscription identifier when you create a durable subscriber is used as the XLA bookmark name.

You can call unsubscribe() on the JMS TopicSession to delete the XLA bookmark used by the subscriber when the application shuts down. This causes a new bookmark to be created when the application is restarted.

When you receive an update, you can use the MapMessage getter methods to extract information from the message and then perform whatever processing your application requires. The TimesTen XlaConstants class defines constants for the update types and special message fields for use in processing XLA update messages.

The first step is typically to determine what type of update the message contains. You can use the MapMessage method getInt() to get the contents of the __TYPE field, and compare the value against the numeric constants defined in the XlaConstants class.

In the next example, from the asyncJMS TimesTen Classic Quick Start sample application, the method onMessage() extracts the update type from the MapMessage object and displays the action that the update signifies.

public void onMessage(Message message)
{
  MapMessage mapMessage = (MapMessage)message;
  String messageType = null;
  /* Standard output stream */
  private static PrintStream outStream = System.out;
 
  if (message == null)
  {
    errStream.println("MyListener: update message is null");
    return ;
  }
 
  try
  {
    outStream.println();
    outStream.println("onMessage: got a " + mapMessage.getJMSType() + " message");
 
    // Get the type of event (insert, update, delete, drop table, etc.).
    int type = mapMessage.getInt(XlaConstants.TYPE_FIELD);
    if (type == XlaConstants.INSERT)
    {
      outStream.println("A row was inserted.");
    }
    else if (type == XlaConstants.UPDATE)
    {
      outStream.println("A row was updated.");
    }
    else if (type == XlaConstants.DELETE)
    {
      outStream.println("A row was deleted.");
    }
    else
    {
 
      // Messages are also received for DDL events such as CREATE TABLE.
      // This program processes INSERT, UPDATE, and DELETE events,
      // and ignores the DDL events.
      return ;
    }    
  ...
  }
...
}

When you know what type of message you have received, you can process the message according to the application's needs. To get a list of all of the fields in a message, you can call the MapMessage method getMapNames(). You can retrieve individual fields from the message by name.

The following example, from the asyncJMS TimesTen Classic Quick Start sample application, extracts the column values from insert, update, and delete messages using the column names.

/* Standard output stream */
private static PrintStream outStream = System.out;
...
if (type == XlaConstants.INSERT 
 || type == XlaConstants.UPDATE 
 || type == XlaConstants.DELETE)
{
 
  // Get the column values from the message.
  int cust_num = mapMessage.getInt("cust_num");
  String region = mapMessage.getString("region");
  String name = mapMessage.getString("name");
  String address = mapMessage.getString("address");
 
  outStream.println("New Column Values:");
  outStream.println("cust_num=" + cust_num);
  outStream.println("region=" + region);
  outStream.println("name=" + name);
  outStream.println("address=" + address);
}

For detailed information about the contents of XLA update messages, see JMS/XLA MapMessage Contents. For information about how TimesTen column types map to JMS data types and the getter methods used to retrieve the column values, see Data Type Support.

Terminating a JMS/XLA Application

When the application has finished reading from the transaction log, there are steps to enable the application to gracefully exit.

Close the Connection

To close the connection to XLA, call close() on the Connection object.

After a connection has been closed, any attempt to use it, its sessions, or its subscribers results in an IllegalStateException error. You can continue to use messages received through the connection, but you cannot call the acknowledge() method on the received message after the connection is closed.

Delete Bookmarks

Deleting XLA bookmarks during shutdown is optional. Deleting a bookmark enables the file system space associated with any unread update records in the transaction log to be freed.

If you do not delete the bookmark, it can be reused by a durable subscriber. If the bookmark is available when a durable subscriber reconnects, the subscriber receives all unacknowledged updates published since the previous connection was terminated. Keep in mind that when a bookmark exists with no application reading from it, the transaction log continues to grow and the amount of file system space consumed by your database increases.

To delete a bookmark, you can simply call unsubscribe() on the JMS Session, which invokes the ttXlaBookmarkDelete built-in procedure to remove the XLA bookmark.

Note:

You cannot delete replicated bookmarks while the replication agent is running.

Unsubscribe from a Table

To turn off XLA publishing for a table, use the ttXlaUnsubscribe built-in procedure. If you use ttXlaSubscribe to enable XLA publishing for a table, use ttXlaUnsubscribe to unsubscribe from the table when shutting down your application.

Note:

If you want to drop a table, you must unsubscribe from it first.

When you unsubscribe from a table, specify the name of the table and the name of the bookmark used to track the table:

ttXlaUnsubscribe(user.table, mybookmark)

The following example calls ttXlaUnSubscribe through a CallableStatement object.

Connection con;
CallableStatement cStmt;
...
cStmt = con.prepareCall("{call ttXlaUnSubscribe(user.table, mybookmark)}");
cStmt.execute();

See Using CALL to Execute Procedures and Functions.