Chapter 3. XmlManager and Containers

Table of Contents

XmlManager
Berkeley DB Environments
XmlManager Instantiation and Destruction
Managing Containers
Container Properties
Container Types
Deleting and Renaming Containers

While containers are the mechanism that you use to store and manage XML documents, you use XmlManager objects to create and open XmlContainer objects. We therefore start with the XmlManager.

XmlManager

XmlManager is a high-level class used to manage many of the objects that you use in a BDB XML application. The following are some of the things you can do with XmlManager objects:

  • Manage containers. This management includes creating, opening, deleting, and renaming containers (see Managing Containers).

  • Create input streams used to load XML documents into containers (see Input Streams and Strings).

  • Create XmlDocument and XmlQueryContext objects.

  • Prepare and run XQuery queries (see Using XQuery with BDB XML).

  • Create a transaction object (see the Berkeley DB XML Getting Started with Transaction Processing guide for details).

Because XmlManager is the only way to construct important BDB XML objects, it is central to your BDB XML application.

Berkeley DB Environments

Before you can instantiate an XmlManager object, you have to make some decisions about your Berkeley DB Environment. BDB XML requires you to use a database environment. You can use an environment explicitly, or you can allow the XmlManager constructor to manage the environment for you.

If you explicitly create an environment, then you can turn on important features in BDB XML such as logging, transactional support, and support for multithreaded and multiprocess applications. It also provides you with an on-disk location to store all of your application's containers.

If you allow the XmlManager constructor to implicitly create and/or open an environment for you, then the environment is only configured to allow multithreaded sharing of the environment and the underlying databases (DB_PRIVATE is used). All other features are not enabled for the environment.

The next several sections describe the things you need to know in order to create and open an environment explicitly. We start with this activity first because it is likely to be the first thing you will do for all but the most trivial of BDB XML applications.

Environment Configuration Properties

In order to use an environment, you must first open it. When you do this, there are a series of configuration properties that you can optionally specify. These have the effect of enabling important subsystems (such as transactional support).

There are a great many environment configuration properties and these are described in the Berkeley DB documentation. However, there are a few that you are likely to want to use with your BDB XML application, so we describe them here:

  • EnvironmentConfig.setAllowCreate()

    If true and if the environment does not exist at the time that it is opened, then create it. It is an error to attempt to open a database environment that has not been created.

  • EnvironmentConfig.setInitializeLocking()

    If true, initializes the locking subsystem. This subsystem is used when an application employs multiple threads or processes that are concurrently reading and writing Berkeley DB databases. In this situation, the locking subsystem, along with a deadlock detector, helps to prevent concurrent readers/writers from interfering with each other.

    Remember that under the covers BDB XML containers are using Berkeley DB databases, so if you want your containers to be accessible by multiple threads and/or multiple processes, then you should enable this subsystem.

  • EnvironmentConfig.setInitializeLogging()

    If true, initializes the logging subsystem. This subsystem is used for database recovery from application or system failures. For more information on normal and catastrophic recovery, see the Berkeley DB XML Getting Started with Transaction Processing guide.

  • EnvironmentConfig.setInitializeCache()

    If true, initializes the shared memory pool subsystem. This subsystem is required for multithreaded BDB XML applications, and it provides an in-memory cache that can be shared by all threads and processes participating in this environment.

  • EnvironmentConfig.setTransactional()

    If true, initializes the transaction subsystem. This subsystem provides atomicity for multiple database access operations. When transactions are in use, recovery is possible if an error condition occurs for any given operation within the transaction. If this subsystem is turned on, then the logging subsystem must also be turned on.

    We discuss writing transactional applications in the Berkeley DB XML Getting Started with Transaction Processing guide.

  • EnvironmentConfig.setRunRecovery()

    If true, causes normal recovery to be run against the underlying database. Normal recovery ensures that the database files are consistent relative to the operations recorded in the log files. This is useful if, for example, your application experienced an ungraceful shut down and there is consequently an possibility that some write operations were not flushed to disk.

    Recovery can only be run if the logging subsystem is turned on. Also, recovery must only be run by a single thread of control; typically it is run by the application's master thread before any other database operations are performed.

Regardless of the properties you decide to set at creation time, it is important to use the same ones on all subsequent environment opens (the exception to this is EnvironmentConfig.setAllowCreate() which is only required to create an environment). In particular, avoid using properties to open environments that were not used at creation time. This is because different subsystems require different data structures on disk, and it is therefore illegal to attempt to use subsystems that were not initialized when the environment was first created.

Opening and Closing Environments

To use an environment, you must first open it. At open time, you must identify the directory in which it resides and this directory must exist prior to the open attempt. At open time, you also specify the open if any, that you want to use for your environment.

When you are done with the environment, you must make sure it is closed. You can either do this explicitly, or you can have the XmlManager object do it for you.

If you are explicitly closing your environment, you must make sure any containers opened in the environment have been closed before you close your environment. Also, in this case, to ensure that your environment is closed by your application, you should perform this activity in the finally block of your your application's top-level try block.

For information on XmlManager instantiation, see XmlManager Instantiation and Destruction

For example:

package dbxml.gettingStarted;

import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
                                                                                                                                  
import java.io.File;
import java.io.FileNotFoundException;
                                                                                                                                  
...
                                                                                                                                  
Environment myEnv = null;
File envHome = new File("/export1/testEnv");
try {
    EnvironmentConfig envConf = new EnvironmentConfig();
    envConf.setAllowCreate(true);         // If the environment does not
                                          // exits, create it.
    envConf.setInitializeCache(true);     // Turn on the shared memory
                                          // region.
    envConf.setInitializeLocking(true);   // Turn on the locking subsystem.
    envConf.setInitializeLogging(true);   // Turn on the logging subsystem.
    envConf.setTransactional(true);       // Turn on the transactional 
                                          // subsystem.

    myEnv = new Environment(envHome, envConf);

    // Do BDB XML work here.

} catch (DatabaseException de) {
    // Exception handling goes here
} catch (FileNotFoundException fnfe) {
    // Exception handling goes here
} finally {
    try {
        if (myEnv != null) {
            myEnv.close();
        }
    } catch (DatabaseException de) {
        // Exception handling goes here
    }
} 

XmlManager Instantiation and Destruction

You create an XmlManager object by calling its constructor. You destroy a XmlManager object by calling its close() method. Note that XmlManager is closed and all of its resources released when the last open handle to the object is closed.

To construct an XmlManager object, you may or may not provide the constructor with an open Environment object. If you do instantiate XmlManager with an opened environment handle, then XmlManager will close and destroy that Environment object for you if you set XmlManagerConfig::setAdoptEnvironment() to true.

If you provide an Environment object to the constructor, then you can use that object to use whatever subsystems that you application may require (see Environment Configuration Properties for some common subsystems).

If you do not provide an environment object, then XmlManager will implicitly create an environment for you. In this case, the environment will not be configured to use any subsystems and it is only capable of being shared by multiple threads from within the same process. Also, in this case you can optionally identify the on-disk location where you want your containers to reside using one of the following mechanisms:

  • Specify the path to the on-disk location in the container's name.

  • Specify the environment's data location using the DB_HOME environment variable.

In either case, you can pass the XmlManager constructor a XmlManagerConfig object that controls that object's behavior with regard to the underlying containers (the property is NOT passed directly to the underlying environment or databases). Configuration methods are:

  • XmlManagerConfig.setAllowAutoOpen()

    If set to true, XQuery queries that reference created but unopened containers will automatically cause the container to be opened for the duration of the query.

  • XmlManagerConfig.setAdoptEnvironment()

    If set to true, XmlManager will close and destroy the Environment object that it was instantiated with when the XmlManager is closed.

  • XmlManagerConfig.setAllowExternalAccess()

    If set to true, XQuery queries executed from inside BDB XML can access external sources (URLs, files, and so forth).

For example, to instantiate an XmlManager with a default environment:

package dbxml.gettingStarted;

import com.sleepycat.dbxml.XmlException;
import com.sleepycat.dbxml.XmlManager;

...
                                                                                                                                  
XmlManager myManager = null;
try {
    myManager = new XmlManager();
} catch (XmlException e) {
    // Exception handling goes here
} finally {
    try {
        if (myManager != null) {
            myManager.close();
        }
    } catch (XmlException ce) {
        // Exception handling goes here
    }
} 

And to instantiate an XmlManager using an explicit environment object:

package dbxml.gettingStarted;

import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;

import com.sleepycat.dbxml.XmlException;
import com.sleepycat.dbxml.XmlManager;
import com.sleepycat.dbxml.XmlManagerConfig;
                                                                                                                                  
import java.io.File;
import java.io.FileNotFoundException;
                                                                                                                                  
...
                                                                                                                                  
Environment myEnv = null;
File envHome = new File("/export1/testEnv");
XmlManager myManager = null;
try {
    EnvironmentConfig envConf = new EnvironmentConfig();
    envConf.setAllowCreate(true);         // If the environment does not
                                          // exits, create it.
    envConf.setInitializeCache(true);     // Turn on the shared memory
                                          // region.
    envConf.setInitializeLocking(true);   // Turn on the locking subsystem.
    envConf.setInitializeLogging(true);   // Turn on the logging subsystem.
    envConf.setTransactional(true);       // Turn on the transactional 
                                          // subsystem.

    myEnv = new Environment(envHome, envConf);

    XmlManagerConfig managerConfig = new XmlManagerConfig();
    managerConfig.setAdoptEnvironment(true);
    myManager = new XmlManager(myEnv, managerConfig);

} catch (DatabaseException de) {
    // Exception handling goes here
} catch (FileNotFoundException fnfe) {
    // Exception handling goes here
} catch (XmlException e) {
    // Exception handling goes here
} finally {
    try {
        if (myManager != null) {
            myManager.close();
        }
    } catch (XmlException ce) {
        // Exception handling goes here
    } catch (DatabaseException de) {
        // Exception handling goes here
    }
}