Multi-user and remote access to JDataStores

JDataStore is a feature of JBuilder Professional and Enterprise, and the Inprise Application Server.

JDataStore applications aren't limited to accessing local JDataStore files. Through the use of a JDataStore Server, you can access JDataStores from other machines. The JDataStore Server also enables multi-user access. Access requests from numerous clients are handled by the server process.


Using the JDBC driver for remote access

You can use JDataStore's Type 4 (direct pure Java) JDBC driver com.borland.datastore.jdbc.DataStoreDriver to access both local and remote JDataStore files. The URL for local connections is:
jdbc:borland:dslocal:<filename>

But the URL for remote connections is:

jdbc:borland:dsremote://<hostname>/<filename>

Note that on Unix, filenames relative to root start with a slash, so URLs for those files would have two slashes between the hostname and filename.

A JDataStore Server process must be running on the <hostname> machine. Communications between the client application and the JDataStore Server use port 2508 by default. You can change the port number when starting (or restarting) the server. You change it on the client by getting the connection with extended properties. For example, if you want to access the JDataStore file c:\someApp\ecom.jds on the computer mobile.mycompany.com through port 9876, you might do something like:

Class.forName( "com.borland.datastore.jdbc.DataStoreDriver" );
java.util.Properties info = new java.util.Properties();
info.setProperty( "user", "MyUserName" );
info.setProperty( "port", "9876" );
Connection con = DriverManager.getConnection(
    "jdbc:borland:dsremote://mobile.mycompany.com/c:/someApp/ecom.jds", info );

For more information on connection properties, see "Driver properties" for the DataStoreDriver component in the DataExpress Component Library Reference.

Other than these differences, a remote JDBC connection operates in much the same manner as a local JDBC connection from the client application's perspective. For more information, see "Using JDBC for data access."

Because JDataStores accessed through a remote connection are potentially JDataStores accessed by multiple users, you must consider some concurrency issues as detailed in "Avoiding blocks and deadlocks."


Running the JDataStore Server

To access JDataStore files through a remote JDBC connection, you must have a JDataStore Server running on a machine that has local access to those files. This could be the actual machine that contains the files, or it could be a machine that has direct network access to JDataStore files on a networked drive.

For development purposes, you can start the server from the JBuilder menu. Select Tools|JDataStore Server. This starts the server process, displaying a simple UI:

Figure 4.1   JDataStore server

From the menu, you can get help, terminate the server, or run the JDataStore Explorer (for more information on the JDataStore Explorer, see "Using the JDataStore Explorer.") From the Options tab, you can change a few items in the server's configuration.

Reconfiguring the server

You can't change the server configuration while it is running. The File|Shutdown menu command stops the actual server process and closes all connections in an orderly fashion.

Once the server stops, you can use the Options tab to change the port number, temp directory, and status log directory settings for the server. Then use File|Startup to restart the server process.


Deploying the JDataStore Server

When development ceases on an application and it enters production, you must deploy the JDataStore Server to a server machine.

Packaging the server

The JAR files you need to run the server depend on whether you want the GUI (graphical user interface). Without the GUI, you need just these JAR files:

If you want the GUI, you also need these JAR files:

If you want online help for the GUI to be available, you also need this JAR file:

If you want the server's online help to be available, you must also copy the help JAR files from the /doc directory. The help files for the JDataStore Server are in jb_ui.jar. The JDataStore Developer's Guide is in jb_dspg.jar.

Starting the server

To start the server, you must add the necessary JAR files to the classpath. The main class for the JDataStore Server is com.borland.dbtools.dsserver.Server, so the command line for starting the server with default options is this:
java com.borland.dbtools.dsserver.Server

You can also specify the options listed in the following table:

Table 4.1   JDataStore Server startup options 

Option

Description

-port=<number>

The port to listen to. Default: 2508

-ui=<uiType>

The look and feel of the UI. One of the following:

  • windows
  • motif
  • metal
  • none
  • <LookAndFeel class name>

-temp=<dirName>

The directory to use for all temporary files

-doc=<helpDir>

The directory that contains online help files

-?
-help

Displays a message listing these options

If you don't use the -ui option (or specify none), the server starts as a console application. Without a UI, you won't be able to reconfigure the server or launch the JDataStore Explorer. To halt the server, use the appropriate operating system or shell action. For example, when running in the foreground, press Ctrl+C. When running in the background on Unix, use the kill command.

An executable file for the server is also provided, and it can be started from the command line. The executable uses the classpath and main class name settings in the dss.config file.


Creating custom JDBC servers

The JDataStore Server that comes with JBuilder provides remote access to JDataStore files. You can create custom servers with additional functionality. For example, because the server will probably be running all the time, you can add a maintenance thread that backs up files at the same time every night. Another example would be to add the ability to retrieve file streams stored in a JDataStore. File streams are not accessible through JDBC.

The core of any JDataStore Server is the com.borland.datastore.jdbc.DataStoreServer class. For more information, see the DataStoreServer class in the DataExpress Component Library Reference.


Providing access to JDataStores via the web

The JDataStore Server is useful for making JDataStore data available on a company network, but you may want to provide access to JDataStore files via the web. XmlServlet is a utility which can run queries against JDataStore, or any other JDBC driver, and generate XML or plain text output. For more information on XmlServlet see "Creating data-aware servlets using XML Servlet" in the Distributed Application Developer's Guide.


Multi-user transaction issues

Multi-user access introduces potential problems with transactions, ranging from decreased performance to deadlock. (These same issues can also be a problem for complex single-user applications that use multiple transactional connections.) Avoiding or minimizing these problems requires that you understand the transaction mechanisms employed by the JDataStore.

Transaction isolation level

The JDataStore uses stream locks to manage access to resources. Stream locks provide the strongest possible transaction isolation level, designated by java.sql.Connection.TRANSACTION_SERIALIZABLE. It prevents these operations from happening:

Serializable transactions guarantee that the data is consistent during the transaction's lifetime.

Avoiding blocks and deadlocks

A connection usually requires a lock to either read from or write to a stream or row. It can be blocked by another connection that's either reading or writing. You can prevent blocks in two ways:

Conserving write transactions

Connections should use burst writes. A burst write accumulates changes, and then when necessary, starts a transaction, immediately writes those changes, and commits them. This is the preferred model for most database servers and it's the model used by DataExpress in its provider/resolver paradigm.

Using read-only transactions

Read-only transactions aren't blocked by writers or other readers, and because they don't get locks, they never block other transactions.

To make JDBC connections use read-only transactions, set the readOnly property of the java.sql.Connection object (returned by the java.sql.DriverManager.getConnection() and com.borland.dx.dataset.sql.Database.getJdbcConnection() methods) to true. When using DataStoreConnection objects, set the readOnlyTx property to true before opening the connection.

Read-only transactions work by simulating a snapshot of the JDataStore. The snapshot sees only data from transactions committed at the point the transaction started (otherwise, the connection would have to see if there are pending changes and roll them back whenever it accesses the data). A snapshot begins when the DataStoreConnection opens. It's refreshed every time its commit() method is called.

Detecting blocks and deadlocks

The DataStoreConnection has a lockWaitTime property that defaults to ten seconds. If a lock can't be secured in that time, the transaction aborts with an informative exception. This mechanism applies to long-duration locks.

When a transaction aborts, it holds on to its locks. You must decide whether to commit or roll back the transaction or to retry the lock. JDataStore automatically detects deadlocks. When a deadlock occurs, an informative exception is thrown. If a deadlock is detected for a JDBC connection, that connection's transaction will be automatically aborted. DataStoreConnection objects that encounter deadlock do not automatically roll back.


Connection pooling and distributed transaction support

JDataStore provides several components for dealing with JDBC 2.0 DataSources, connection pooling, and distributed transaction (XA) support. These features require J2EE. If your version of JBuilder does not include J2EE.jar, you will need to download it from Sun, and add it to your project as a required library. See "Adding a required library to a project" in the Database Application Developer's Guide for instructions on adding a required library.

The basic idea behind connection pooling is simple. In an application that opens and closes many database connections, it is efficient to keep unused Connection objects in a pool for future re-use. This saves the overhead of having to open a new physical connection each time a connection is opened. For more information on connection pooling, see "Pooling connections" in the Database Application Developer's Guide.

The JdbcConnectionPool object supports pooled XA transactions. This feature allows JDataStore to participate in a distributed transaction as a resource manager. JDataStore provides XA support by implementing three standard interfaces specified by Sun in the Java Transaction API (JTA) specification:

To get a distributed connection to a JDataStore from a JdbcConnectionPool, you call JdbcConnectionPool.getXAConnection(). The connection returned by this method only works with the JDataStore JDBC driver. XA support is only useful when combined with a distributed transaction manager, such as the one provided by Inprise Application Server.

Under normal operation, all global transactions should be committed or rolled back before the associated XAConnection is closed. If a connection is participating in a global transaction that is not yet in a prepared state but is in a successful started or suspended state, the transaction will be rolled back during any crash recovery that may occur.