3 Using JMS/XLA for Event Management

You can use the TimesTen JMS/XLA API to monitor TimesTen for changes to specified tables in a local database and receive real-time notification of these changes. The primary purpose of JMS/XLA is as a high-performance, asynchronous alternative to triggers.

JMS/XLA implements Java Message Service (JMS) interfaces to make the functionality of the TimesTen Transaction Log API (XLA) available to Java applications. JMS information and resources are available at the following location:

http://www.oracle.com/technetwork/java/jms/index.html

In addition, the standard JMS API documentation is installed with the TimesTen at the following location:

install_dir/3rdparty/jms1.1/doc/api/index.html

For information about tuning TimesTen JMS/XLA applications for improved performance, see "Tuning JMS/XLA applications".

Note:

In the unlikely event that the TimesTen replication solutions described in Oracle TimesTen In-Memory Database Replication Guide do not meet your needs, it is possible to use JMS/XLA to build a custom data replication solution.

This chapter includes the following topics:

JMS/XLA concepts

Java applications can use the JMS/XLA API to receive event notifications from TimesTen. JMS/XLA uses the JMS publish-subscribe interface to provide access to XLA updates.

Subscribe to updates by establishing a JMS Session instance that provides a connection to XLA and then creating a durable subscriber (TopicSubscriber). You can receive and process messages synchronously through the subscriber, or you can implement a listener (MessageListener) to process the updates asynchronously.

JMS/XLA is designed for applications that want to monitor a local database. TimesTen and the application receiving the notifications must reside on the same system.

Note:

The JMS/XLA API is a wrapper for XLA. XLA obtains update records directly from the transaction log buffer or transaction log files, so the records are available until they are read. XLA also allows multiple readers to access transaction log updates simultaneously.

See "XLA and TimesTen Event Management" in Oracle TimesTen In-Memory Database C Developer's Guide for information about XLA.

This section includes the following topics:

How XLA reads records from the transaction log

As applications modify a database, TimesTen generates transaction log records that describe the changes made to the data and other events such as transaction commits.

New transaction log records are always written to the end of the transaction log buffer as they are generated. Transaction log records are periodically flushed in batches from the log buffer in memory to transaction log files on disk.

Applications can use XLA to monitor the transaction log for changes to the database. XLA reads through the transaction log, filters the log records, and delivers XLA applications with a list of transaction records that contain the changes to the tables and columns of interest.

XLA sorts the records into discrete transactions. If multiple applications are updating the database simultaneously, transaction log records from the different applications are interleaved in the transaction log.

XLA transparently extracts all transaction log records associated with a particular transaction and delivers them in a contiguous list to the application.

Only the records for committed transactions are returned. They are returned in the order in which their final commit record appears in the transaction log. XLA filters out records associated with changes to the database that have not yet committed.

If a change is made but then rolled back, XLA does not deliver the records for the aborted transaction to the application.

Consider the example transaction log illustrated in Figure 3-1 and Example 3-1 that follow, which illustrate most of these basic XLA concepts.

Figure 3-1 Records extracted from the transaction log

Description of Figure 3-1 follows
Description of "Figure 3-1 Records extracted from the transaction log"

Example 3-1 Reading transaction log records

In this example, the transaction log contains the following records:


CT1 - Application C updates row 1 of table W with value 7.7.
BT1 - Application B updates row 3 of table X with value 2.
CT2 - Application C updates row 9 of table W with value 5.6.
BT2 - Application B updates row 2 of table Y with value "XYZ".
AT1 - Application A updates row 1 of table Z with value 3.
AT2 - Application A updates row 3 of table Z with value 4.
BT3 - Application B commits its transaction.
AT3 - Application A rolls back its transaction.
CT3 - Application C commits its transaction.

An XLA application that is set up to detect changes to tables W, Y, and Z would see the following:


BT2 and BT3 - Update row 2 of table Y with value "XYZ" and commit.
CT1 - Update row 1 of table W with value 7.7.
CT2 and CT3 - Update row 9 of table W with value 5.6 and commit.

This example demonstrates the following:

  • Transaction records for application B and application C all appear.

  • Though the records for application C begin to appear in the transaction log before those for application B, the commit for application B (BT3) appears in the transaction log before the commit for application C (CT3). As a result, the records for application B are returned to the XLA application ahead of those for application C.

  • The application B update to table X (BT1) is not presented because XLA is not set up to detect changes to table X.

  • The application A updates to table Z (AT1 and AT2) are never presented because it did not commit and was rolled back (AT3).

XLA and materialized views

You can use XLA to track changes to both tables and materialized views. A materialized view provides a single source from which you can track changes to selected rows and columns in multiple detail tables. Without a materialized view, the XLA application would have to monitor and filter the update records from all of the detail tables, including records reflecting updates to rows and columns of no interest to the application.

In general, there are no operational differences between the XLA mechanisms used to track changes to a table or a materialized view. However, for asynchronous materialized views, be aware that the order of XLA notifications for an asynchronous view is not necessarily the same as it would be for the associated detail tables, or the same as it would be for a synchronous view. For example, if there are two inserts to a detail table, they may be done in the opposite order in the asynchronous materialized view. Furthermore, updates may be reported by XLA as a delete followed by an insert, and multiple operations (such as multiple inserts or multiple deletes) may be combined into a single operation. Applications that depend on precise ordering should not use asynchronous materialized views.

For more information about materialized views, see the following:

XLA bookmarks

An XLA bookmark marks the read position of an XLA subscriber application in the transaction log. Bookmarks facilitate durable subscriptions, enabling an application to disconnect from a topic and then reconnect to continue receiving updates where it left off.

The rest of this section covers the following:

How bookmarks work

When you create a message consumer for XLA, you always use a durable TopicSubscriber. The subscription identifier you specify when you create the subscriber is used as the XLA bookmark name. When you use the ttXlaSubscribe and ttXlaUnsubscribe built-in procedures through JDBC to start and stop the XLA subscription for a table, you explicitly specify the name of the bookmark to be used.

Bookmarks are reset to the last read position whenever an acknowledgment is received. For more information about how update messages are acknowledged, see the "XLA acknowledgment modes".

You can remove a durable subscription by calling unsubscribe() on the JMS Session object. This deletes the corresponding XLA bookmark and forces a new subscription to be created when you reconnect. For more information see "Deleting bookmarks".

A bookmark subscription cannot be altered when it is in use. To alter a subscription, you must close the message consumer, alter the subscription using ttXlaSubscribe and ttXlaUnsubscribe, and open the message consumer.

Note:

You can also use the ttXlaBookmarkCreate TimesTen built-in procedure to create bookmarks. See "ttXlaBookmarkCreate" in Oracle TimesTen In-Memory Database Reference for information about that function.

Replicated bookmarks

If you are using an active standby pair replication scheme, you have the option of using replicated bookmarks, according to the replicatedBookmark attribute of the <topic> element in the jmsxla.xml file as discussed in "JMS/XLA configuration file and topics". For a replicated bookmark, operations on the bookmark are replicated to the standby database as appropriate, assuming there is suitable write privilege for the standby. This allows more efficient recovery of your bookmark positions if a failover occurs.

When you use replicated bookmarks, steps must be taken in the following order:

  1. Create the active standby pair replication scheme. (This is accomplished by the create active standby pair operation, or by the ttCWAdmin -create command in a Clusterware-managed environment.)

  2. Create the bookmarks.

  3. Subscribe the bookmarks.

  4. Start the active standby pair, at which time duplication to the standby occurs and replication begins. (This is accomplished by the ttRepAdmin -duplicate command, or by the ttCWAdmin -start command in a Clusterware-managed environment.)

Notes:

  • Alternatively, if you use ttXlaBookmarkCreate to create a bookmark, that function has a parameter for specifying a replicated bookmark.

  • If you specify replicated bookmarks in the JMS/XLA configuration file, JMS/XLA will create and subscribe to the bookmarks when the application is started. (Also see "JMS/XLA configuration file and topics".)

Be aware of the following usage notes:

  • The position of the bookmark in the standby database is very close to that of the bookmark in the active database; however, because the replication of acknowledge operations is asynchronous, you may see a small window of duplicate updates when there is a failover, depending on how often acknowledge operations are performed.

  • It is permissible to drop the active standby pair scheme while replicated bookmarks exist. The bookmarks of course cease to be replicated at that point, but are not deleted. If you subsequently re-enable the active standby pair scheme, these bookmarks are automatically added to the scheme.

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

  • You can only read and acknowledge a replicated bookmark in the active database. Each time you acknowledge a replicated bookmark, the acknowledge operation is asynchronously replicated to the standby database.

XLA bookmarks and transaction log holds

You should be aware that when XLA is in use, there is a hold on TimesTen transaction log files until the XLA bookmark advances. The hold prevents transaction log files from being purged until XLA can confirm it no longer needs them. If a bookmark becomes stuck, which can occur if an XLA application terminates unexpectedly or disconnects without first deleting its bookmark or disabling change tracking, the log hold persists and there may be an excessive accumulation of transaction log files. This accumulation may result in disk space being filled.

For information about monitoring and addressing this situation, see "Monitoring accumulation of transaction log files" in Oracle TimesTen In-Memory Database Operations Guide.

JMS/XLA configuration file and topics

To connect to XLA, establish a connection to a JMS Topic object that corresponds to a particular database. The JMS/XLA configuration file provides the mapping between topic names and databases.

You can specify a replicated bookmark by setting replicatedBookmark="yes" in the <topic> element when you specify the topic. The default setting is "no". Also see "XLA bookmarks".

By default, JMS/XLA looks for a configuration file named jmsxla.xml in the current working directory. If you want to use another name or location for the file, you must specify it as part of the environment variable in the InitialContext class and add the location to the classpath.

Example 3-2 Specifying the JMS/XLA configuration file

The following code specifies the configuration file as part of the environment variable in the InitialContext class.

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
  "com.timesten.dataserver.jmsxla.SimpleInitialContextFactory");
env.put(XlaConstants.CONFIG_FILE_NAME, "/newlocation.xml");
InitialContext ic = new InitialContext(env);

The JMS/XLA API uses the class loader to locate the JMS/XLA configuration file if XlaConstants.CONFIG_FILE_NAME is set. In this example, the JMS/XLA API searches for the newlocation.xml file in the top directory in both the location specified in the CLASSPATH environment variable and in the JAR files specified in the CLASSPATH variable.

The JMS/XLA configuration file can also be located in subdirectories, as follows:

env.put(XlaConstants.CONFIG_FILE_NAME,
"/com/mycompany/myapplication/deepinside.xml");

In this case, the JMS/XLA API searches for the deepinside.xml file in the com/mycompany/myapplication subdirectory in both the location specified in the CLASSPATH environment variable and in the JAR files specified in the CLASSPATH variable.

The JMS/XLA API uses the first configuration file that it finds.

Example 3-3 Defining a topic in the configuration file

A topic definition in the configuration file consists of a name, a connection string, and a prefetch value that specifies how many updates to retrieve at a time.

For example, this configuration maps the DemoDataStore topic to the TestDB DSN:

<xlaconfig>
  <topics>
    <topic name="DemoDataStore"
      connectionString="DSN=TestDB"
      xlaPrefetch="100" />
  </topics>
</xlaconfig>

Example 3-4 Defining a topic to use replicated bookmarks

A topic definition can also specify whether a replicated bookmark should be used. The following repeats the preceding example, but with a replicated bookmark.

<xlaconfig>
  <topics>
    <topic name="DemoDataStore"
      connectionString="DSN=TestDB"
      xlaPrefetch="100" replicatedBookmark="yes" />
  </topics>
</xlaconfig>

XLA updates

Applications receive XLA updates as JMS MapMessage objects. A MapMessage object contains a set of typed name and value pairs that correspond to the fields in an XLA update header.

You can access the message fields using the MapMessage getter methods. The getMapNames() method returns an Enumeration object that contains the names of all of the fields in the message. You can retrieve individual fields from the message by name. All reserved field names begin with two underscores, for example __TYPE.

All update messages have a __TYPE field that indicates what type of update the message contains. The types are specified as integer values. As a convenience, you can use the constants defined in com.timesten.dataserver.jmsxla.XlaConstants to compare against the integer types. The supported types are described in Table 3-1.

Table 3-1 XLA update types

Update type Description

INSERT

A row has been added.

UPDATE

A row has been modified.

DELETE

A row has been removed.

COMMIT_ONLY

A transaction has been committed.

CREATE_TABLE

A table has been created.

DROP_TABLE

A table has been dropped.

CREATE_INDEX

An index has been created.

DROP_INDEX

An index has been dropped.

ADD_COLUMNS

New columns have been added to the table.

DROP_COLUMNS

Columns have been removed from the table.

CREATE_VIEW

A materialized view has been created.

DROP_VIEW

A materialized view has been dropped.

CREATE_SEQ

A sequence has been created.

DROP_SEQ

A sequence has been dropped.

CREATE_SYNONYM

A synonym has been created.

DROP_SYNONYM

A synonym has been dropped.

TRUNCATE

All rows in the table have been deleted.


For more information about the contents of an XLA update message, see "JMS/XLA MapMessage contents".

XLA acknowledgment modes

The XLA acknowledgment mechanism is designed to ensure that an application has not only received a message, but has successfully processed it. Acknowledging an update permanently resets the application XLA bookmark to the last record that was read. This prevents previously returned records from being reread, ensuring that an application receives only new batches of records if the bookmark is reused when an application reconnects to XLA.

JMS/XLA can automatically acknowledge XLA update messages, or applications can choose to acknowledge messages explicitly. You specify how updates are to be acknowledged when you create the Session object.

JMS/XLA supports three acknowledgment modes:

  • AUTO_ACKNOWLEDGE: In this mode, updates are automatically acknowledged as you receive them. Each message is delivered only once. Duplicate messages are not sent, so messages might be lost if there is an application failure. Messages are always delivered and acknowledged individually, so JMS/XLA does not prefetch multiple records. The xlaprefetch attribute in the topic is ignored.

  • DUPS_OK_ACKNOWLEDGE: In this mode, updates are automatically acknowledged, but duplicate messages might be delivered when there is an application failure. JMS/XLA prefetches records according to the xlaprefetch attribute specified for the topic and sends an acknowledgment when the last record in a prefetched block is read. If the application fails before reading all of the prefetched records, all of the records in the block are presented to the application it restarts.

    See "JMS/XLA configuration file and topics" for examples setting xlaprefetch.

  • CLIENT_ACKNOWLEDGE: In this mode, applications are responsible for acknowledging receipt of update messages by calling acknowledge() on the MapMessage instance. JMS/XLA prefetches records according to the xlaprefetch attribute specified for the topic.

The following example sets the acknowledgment mode:

Session session = connection.createSession (false, Session.CLIENT_ACKNOWLEDGE);

Also see "Reduce frequency of update acknowledgments".

Prefetching updates

Prefetching multiple update records at a time is more efficient than obtaining each update record from XLA individually. Because updates are not prefetched when you use AUTO_ACKNOWLEDGE mode, it can be slower than the other modes. If possible, you should design your application to tolerate duplicate updates so you can use DUPS_OK_ACKNOWLEDGE, or explicitly acknowledge updates. Explicitly acknowledging updates usually yields the best performance, as long as you can avoid acknowledging each message individually.

Acknowledging updates

To explicitly acknowledge an XLA update, call acknowledge() on the update message. Acknowledging a message implicitly acknowledges all previous messages. Typically, you receive and process multiple update messages between acknowledgments. If you are using the CLIENT_ACKNOWLEDGE mode and intend to reuse a durable subscription in the future, you should call acknowledge() to reset the bookmark to the last-read position before exiting.

Access control impact on XLA

"Considering TimesTen features for access control" provides a brief overview of how TimesTen access control affects operations in the database. Access control impacts XLA, as follows:

  • Any XLA functionality requires the system privilege XLA. This includes connecting to TimesTen (which also requires the CREATE SESSION privilege) as an XLA reader and executing the TimesTen XLA built-in procedures ttXlaBookmarkCreate, ttXlaBookmarkDelete, ttXlaSubscribe, and ttXlaUnsubscribe, all of which are documented in "Built-In Procedures" in Oracle TimesTen In-Memory Database Reference.

  • A user with the XLA privilege has capabilities equivalent to the SELECT ANY TABLE, SELECT ANY VIEW, and SELECT ANY SEQUENCE system privileges.

XLA limitations

Be aware of the following XLA limitations when you use TimesTen JMS/XLA:

  • JMS/XLA is available on all platforms supported by TimesTen. However, XLA does not support data transfer between different platforms or between 32-bit and 64-bit versions of the same platform.

  • JMS/XLA support for LOBs is limited. See "Monitoring tables for updates" for information.

  • JMS/XLA does not support applications linked with a driver manager library or the client/server library.

  • An XLA reader cannot subscribe to a table that uses in-memory columnar compression.

  • For autorefresh cache groups, the change-tracking trigger on Oracle Database does not have column-level resolution. (To have that would be very expensive.) Therefore the autorefresh feature updates all the columns in the row, and XLA can only report that all the columns have changed, even if data did not actually change in all columns.

JMS/XLA and Oracle GDK dependency

The JMS/XLA API uses orai18n.jar, part of the Oracle Globalization Development Kit (GDK) for translating from the database character set specified by the DatabaseCharacterSet attribute to UTF-16 encoding. The JMS/XLA API supports a specific version of the GDK with each TimesTen release. If JMS/XLA finds other versions of the GDK loaded in the JVM, it displays a severe warning and continues processing. You can find out the GDK version supported by JMS/XLA by entering the following commands:

$ cd install_dir/lib
$ java -cp ./orai18n.jar oracle.i18n.util.GDKOracleMetaData -version

Also see "Compiling Java applications".

Connecting to XLA

To connect to XLA so you can receive updates, use a JMS connection factory to create a connection. Then use the connection to establish a session. When you are ready to start processing updates, call start() on the connection to enable message dispatching. This is shown in Example 3-5 that follows, from the syncJMS Quick Start demo.

Example 3-5 Connecting to XLA

/* JMS connection */
private javax.jms.TopicConnection connection; 
/* JMS session */
private TopicSession session; 
...
// get Connection
Context messaging = new InitialContext(); 
TopicConnectionFactory connectionFactory =
        (TopicConnectionFactory)messaging.lookup("TopicConnectionFactory"); 
connection = connectionFactory.createTopicConnection(); 
connection.start(); 
...
// get Session
session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

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 "Unsubscribing 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).

Example 3-6, from the asyncJMS Quick Start demo, uses a listener to process updates asynchronously.

Example 3-6 Using 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 Example 3-7, from the asyncJMS Quick Start demo, the method onMessage() extracts the update type from the MapMessage object and displays the action that the update signifies.

Example 3-7 Determining the update type

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.

Example 3-8, from the asyncJMS Quick Start demo, extracts the column values from insert, update, and delete messages using the column names.

Example 3-8 Extracting column values

/* 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 XLA application has finished reading from the transaction log, it should gracefully exit by closing the XLA connection, deleting any unneeded bookmarks, and unsubscribing from any tables to which you explicitly subscribed.

Closing 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.

Deleting bookmarks

Deleting XLA bookmarks during shutdown is optional. Deleting a bookmark enables the disk 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 disk 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.

Unsubscribing 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.

Example 3-9 Unsubscribing from a table

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

For more information about using TimesTen built-in procedures in a Java application, see "Using CALL to execute procedures and functions".

Using JMS/XLA as a replication mechanism

TimesTen replication as described in Oracle TimesTen In-Memory Database Replication Guide is sufficient for most customer needs; however, it is also possible to use JMS/XLA to replicate updates from one database to another. Implementing your own replication scheme on top of JMS/XLA in this way is fairly complicated, but can be considered if TimesTen replication is not feasible for some reason.

Applying JMS/XLA messages to a target database

The source database generates JMS/XLA messages. To apply the messages to a target database, you must extract the XLA descriptor from them. Use the MapMessage interface to extract the update descriptor:

MapMessage message;
/*
 *...other code
 */
try {
  byte[]updateMessage=
    mapMessage.getBytes(XlaConstants.UPDATE_DESCRIPTOR_FIELD);
}
catch (JMSException jex){
/*
 *...other code
 */
}

The target database may reside on a different system from the source database. The update descriptor is returned as a byte array and can be serialized for network transmission.

You must create a target database object that represents the target database so you can apply the objects from the source database. You can create a target database object named myTargetDataStore as an instance of the TargetDataStoreImpl class. For example:

TargetDataStore myTargetDataStore=
   new TargetDataStoreImpl("DSN=sampleDSN");

Apply messages to myTargetDataStore by using the TargetDataStore method apply(). For example:

myTargetDataStore.apply(updateDescriptor);

By default, TimesTen checks for conflicts on the target database before applying the update. If the target database has information that is later than the update, TargetDataStore throws an exception. If you do not want TimesTen to check for conflicts, use the TargetDataStore method setUpdateConflictCheckFlag() to change the behavior.

By default, TimesTen commits the update to the database based on commit flags and transaction boundaries contained in the update descriptor. If you want the application to perform manual commits instead, use the setAutoCommitFlag() method to change the autocommit flag. To perform a manual commit on myTargetDataStore, use the following command:

myTargetDataStore.commit();

You can perform a rollback if errors occur during the application of the update. Use the following command for myTargetDataStore:

myTargetDataStore.rollback();

Close myTargetDataStore by using the following command:

myTargetDataStore.close();

See "JMS/XLA replication API" for more information about the TargetDataStore interface.

TargetDataStore error recovery

Invoking TargetDataStore can yield transient and permanent errors.

TargetDataStore methods return a nonzero value when transient errors occur. The application can retry the operation and is responsible for monitoring update descriptors that must be reapplied. For more information about transient XLA errors, see "Handling XLA errors" in Oracle TimesTen In-Memory Database C Developer's Guide.

TargetDataStore methods return a JMSException object for permanent errors. If the application receives a permanent error, it should verify that the database is valid. If the database is invalid, the target database object should be closed and a new one should be created. Other types of permanent errors may require manual intervention.

The following example shows how to recover errors from a TargetDataStore object.

Example 3-10 Recovering errors

TargetDataStore theTargetDataStore;
byte[] updateDescriptor;
int rc;

// Other code
try {
  ...
  if ( (rc = theTargetDataStore.apply(updateDescriptor) ) == 0 ) {
    // Apply successful.
  }
  else {
    // Transient error. Retry later.
  }
 }
catch (JMSException jex) {
  if (theTargetDataStore.isDataStoreValid() ) {
    // Database valid; permanent error that may need Administrator intervention.
  }
  else {
    try {
      theTargetDataStore.close();
  }
  catch (JMSException closeEx) {
    // Close errors are not usual. This may need Administrator intervention.
  }
}