PSE/PSE Pro for Java API User Guide

Managing Databases

You create databases to store your objects. The Database class provides the API for creating and managing databases.

Creating a Database

Opening and Closing a Database

Moving or Copying a Database

Destroying a Database

Obtaining Information About a Database

Database Operations and Transactions

Restrictions

Creating a Database

The Database class is an abstract class that represents a database.

A transaction must not be in progress when you create a database.

Databases are cross-platform compatible. You can create databases on any supported platform and access them from any supported platform.

Method Signature

To create a database, call the static create method on the Database class and specify the database name and an access mode. The method signature is

public static Database create(String name, int fileMode)
PSE/PSE Pro throws AccessViolationException if the access mode does not provide owner write access. Otherwise, PSE and PSE Pro ignore the access mode specification when you create a database. This is due to a limitation in the Java implementation.

Example

For example:

import COM.odi.*;
class DbTest {
      void test() {
            Database db = Database.create("objectsrus.odb", ObjectStore.OWNER_WRITE);
            ...
      }
}
This example creates an instance of Database and stores a reference to the instance in the variable named db. The Database.create method is called with two parameters.

The first parameter specifies the path name of a file. When you are using PSE or PSE Pro, you must end this name with .odb.

The second parameter specifies the access mode for the database.

Terminology note

Database is an abstract class so PSE/PSE Pro actually creates an instance of a subclass that extends Database. From your point of view, it does not matter whether PSE/PSE Pro creates an instance of Database or an instance of a Database subclass.

Result

The result is a database named "objectsrus.odb" with an access mode that allows the owner to modify the database. The example stores the reference to the Database object in the db variable. This means that db represents, or is a handle for, the objectsrus.odb database.

For each database you create, PSE/PSE Pro creates an instance of Database to represent your database. Each database is associated with exactly one instance of Database. Consequently, you can use object identity comparison operators to determine whether or not two Database objects represent the same database. For example, the following code segment returns true:

boolean checkIdentity(String dbname) {
      Database db = Database.create(dbname, ObjectStore.OWNER_WRITE);
      Database dbAgain = Database.open(dbname, ObjectStore.OPEN_UPDATE);
      return (db == dbAgain);
}

Specifying a Database Name

When you create or open a database you must specify or pass in a name of the form

database_name.odb

PSE/PSE Pro performs standard I/O to the host system to create the database in the location you specify. The operating system interprets the database name in the context of the local file system. Before you specify a directory that is physically remote, you must make the directory appear to be local by using NFS, or some other network file system.

Database Already Exists

For each database you create, PSE/PSE Pro creates two files. The first file has the path name you specify or pass when you create the database. The path name must be unique and must end with .odb. The second file has the same name except that PSE/PSE Pro replaces the .odb extension with a .odt extension. The .odb and .odt files together make up the database.

If you are using file locking, that is if the system property COM.odi.useDatabaseLocking is set to true, PSE/PSE Pro also creates a lock entry file. This file has the name of the database with a .odl extension. PSE/PSE Pro uses the lock entry file to maintain information about locks on the database.

The PSE/PSE Pro API uses the path.odb name. Your application should never specify the path.odt name. But you must be aware of the .odt file so that you can correctly move or copy a database.

If you try to create a database that already exists, PSE/PSE Pro throws DatabaseAlreadyExistsException. Before you create a database, you might want to check if it exists and destroy it if it does. For example, you can insert the following just before you create a database:

try {
      Database.open(dbName, ObjectStore.OPEN_UPDATE).destroy();
}      catch(DatabaseNotFoundException e) {
}

Warning

Do this only if you want to destroy and recreate your database. Otherwise, invoke Database.open().

Segments

PSE/PSE Pro creates each database with a single segment. A segment is a variable-sized region of disk space that PSE/PSE Pro uses to cluster objects stored in the database.

You cannot create additional segments.

Opening and Closing a Database

A database can be either open or closed. You must open a database before you can store or access objects in that database.

Applications that refer to only one database are not required to close that database.

An application must close a database

A PSE or PSE Pro application that uses one thread or one group of cooperating threads uses only one session. Such an application can have only one database open at a time. The application must close the database before it can open another one.

A PSE Pro application that uses multiple threads that do not cooperate with each other has one session for each noncooperating thread. If your application uses multiple groups of cooperating threads in which the groups do not cooperate with each other, it has one session for each separate group of cooperating threads. An application can use the different sessions to open the same database or different databases. Each session must close its database before it can open another one.

A single PSE Pro application can have more than one database open when it uses noncooperating threads and/or separate groups of cooperating threads. A single thread or a single group of cooperating threads cannot have more than one database open.

PSE does not support multiple sessions, and therefore does not allow multiple threads that do not cooperate with each other.

Objects in a closed database are not accessible.

Opening a Database

When you create a database, PSE/PSE Pro creates and opens the database. To open an existing database, call the static Database.open() method. The method signature is

public static Database open(String name, int openType)
For example:

Database db = Database.open("myDb.odb", ObjectStore.OPEN_READONLY); 
The first parameter specifies the path name of your database. The second parameter indicates the open type of the database.

Suppose you previously created and closed a database that is represented by an instance of a Database subclass stored in the db variable. You can call the instance open() method to open your database this way:

db.open(ObjectStore.OPEN_READONLY);
You can use the static class open() method this way:

db = Database.open("myDb.odb", ObjectStore.OPEN_READONLY);
Typically, both lines cause the same result. However, they might cause different results if a database has been destroyed and recreated.

Possible Open Types

PSE/PSE Pro provides four constants that you can specify for the openType parameter to Database.open().

If COM.odi.useDatabaseLocking is set to false (the default), PSE/PSE Pro does not use locks. It is the responsibility of the application to manage access to databases.

The constants you can specify for openType are:

If you open a database with ObjectStore.OPEN_READONLY, an attempt to modify an object throws UpdateReadOnlyException when you try to commit the transaction.

When an application opens a database with OPEN_READONLY or OPEN_READONLY_NON_BLOCKING it means that several applications can read the database at the same time. When an application opens a database with OPEN_UPDATE or OPEN_UPDATE_NON_BLOCKING it means that the application has exclusive use. No other application can access the objects in that database while your application has it open. Related information is in the section about concurrency.

PSE/PSE Pro maintains a list of the order in which locks are requested. For example suppose two applications, A and B, open the foo.odb database and specify ObjectStore.OPEN_READONLY. Then application C tries to open foo.odb with a specification of ObjectStore.OPEN_UPDATE. C must wait for A and B to release their locks. Then application D tries to open foo.odb with an open type of ObjectStore.READONLY. D must wait until C obtains and releases the lock on foo.odb.

Closing a Database

To close a database, call the close() method on the instance of the Database subclass that represents the database. For example:

db.close();
You cannot close a database when a transaction is in progress. When you close a database, all persistent objects that belong to that database become stale.

If the last committed transaction that operated on the database retained persistent objects, you can use an overloading of close() that allows you to specify what should happen to the retained objects. The method signature is

public void close(boolean retainAsTransient)
Specify true to make retained objects transient. If you specify false, it is the same as calling the close() method without an argument. All access to retained objects ends.

If you do not close a database, PSE/PSE Pro closes it when you shut down PSE/PSE Pro. In general, it is best to leave databases open for the entire session.

Moving or Copying a Database

You can move or copy a database provided that

You do not need to copy or move the .odl file or .dir latch directory, if these exist.

Destroying a Database

Destroying a database makes all objects in the database permanently inaccessible and deletes the .odb and .odt files.

You cannot recover a destroyed database except from backups.

To destroy a database, call the destroy() method on the Database subclass instance. For example:

db.destroy();
The database must be open for update and a transaction cannot be in progress.

When you destroy a database, all persistent objects that belonged to that database become stale.

Obtaining Information About a Database

You can call methods on a database to learn

You can also run the osjshowdb utility to learn or verify exactly which objects are in a database.

Is a Database Open?

To determine whether or not a database is open, call the isOpen() method on the database. For example:

myBoolean = db.isOpen();
This method returns true if the database is open. It returns false if the database is closed or if it was destroyed. To determine whether false indicates a closed or destroyed database, try to open it.

Is a Database Open for Update or ReadOnly?

To check whether a database is open for update or readonly, call the getOpenType() method on the database. The database must be open or PSE/PSE Pro throws DatabaseNotOpenException. The method signature is

public int getOpenType()
This method returns one of the following constants:

Here is an example of how you can use this method:

void checkUpdate(Database db) {
      if (db.getOpenType() != ObjectStore.OPEN_UPDATE)
            throw new Error("The database must be open for update.");
}

What Is the Path Name of a Database?

To find out the path name for a database, call the getPath() method on the database. For example:

String myString = db.getPath();

What Is the Size of a Database?

To obtain the size of a database, call the getSizeInBytes() method on the database. The database must be open and a read-only or update transaction must be in progress. For example:

db = Database.open("myDb.odb", ObjectStore.OPEN_READONLY);
Transaction tr = Transaction.begin(ObjectStore.READONLY);
int dbSize = db.getSizeInBytes();
This method does not necessarily return the exact number of bytes that the database uses. The value returned might be the result of your operating system's rounding up to a block size. You should be aware of how your operating system handles operations such as these.

Displaying Information About a Database

The osjshowdb utility displays information about one or more databases. This utility is useful when you want to know how many and what types of objects are in a database. You can use this utility to verify the generals contents of the database.

This utility and its API are not available with PSE.

This utility displays the following information:

-showObjs option

If you specify the -showObjs option, the osjshowdb utility also displays the following information for each object:

-showData option

Specify the -showData option with osjshowdb to display string values as well as the references an object contains. When you specify the -showData option, it implies the -showObjs option.

Path variables

Before you invoke osjshowdb from the command line, ensure that tools.zip is in your classpath. Also ensure that the distribution bin directory that contains osjshowdb is in your PATH variable. To execute the osjshowdb utility, use this format:

osjshowdb [-showData] [-showObjs] db1.odb [ db2.odb]...

You can specify one or more databases.

When the utility displays java.lang.String objects, the number of elements is the number of characters in the string. The total bytes indicates the number of bytes that the data occupies on the disk.

There are some internal structures in the database that are not included in the calculations performed by the osjshowdb utility. Consequently, the total number of bytes as indicated in the output from osjshowdb is never equal to the actual size of a segment.

API

The API for the osjshowdb utility is Database.showDB().

Sample output

Here is some sample output from the osjshowdb utility:

Name: c:\temp\testDB.odb
      There are 14 roots:
      Name: personA      Type: COM.odi.test.exceptionTests.Employee
      Name: intArr      Type: java.lang.Integer[]
      Name: char      Type: java.lang.Character
      Name: long      Type: java.lang.Long
      Name: str3      Type: java.lang.String
      Name: str1      Type: java.lang.String
      Name: TestB      Type: COM.odi.test.exceptionTests.Employee
      Name: personC      Type: COM.odi.test.exceptionTests.Employee
      Name: personB      Type: COM.odi.test.exceptionTests.Employee
      Name: charArr      Type: java.lang.Character[]
      Name: longArr      Type: java.lang.Long[]
      Name: int      Type: java.lang.Integer
      Name: str2      Type: java.lang.String
      Name: TestA      Type: COM.odi.test.exceptionTests.Employee
      There is 1 segment:
      Segment: 0
      Size: 112944 (111 Kbytes)
                                        Total
      OID          Elements   Bytes    Type
      <1|0|0>             8         64   java.lang.Object[]
      <1|0|1>             2        16    java.lang.Long[]
    <1|0|2>              1          8    java.lang.String[]
    <1|0|3>                        36   COM.odi.test.exceptionTests.Employee
     Contains references to:
      0: <1|0|199>
      12: <1|0|205>
      20: <1|0|218>
      28: <1|0|222>
    <1|0|4>              1          8  java.lang.Object[]
    <1|0|5>                        36  COM.odi.test.exceptionTests.Employee
     Contains references to:
      0: <1|0|175>
      12: <1|0|181>
      20: <1|0|194>
      28: <1|0|198>
    <1|0|6>                       36  COM.odi.test.exceptionTests.Employee
     Contains references to:
      0: <1|0|85>
      12: <1|0|91>
      20: <1|0|110>
      28: <1|0|114>
    <1|0|9>             11        16  java.lang.String
      Value: "TestString1"
    <1|0|10>            11        16  java.lang.String
      Value: "TestString2"
    <1|0|11>            11        16  java.lang.String
      Value: "TestString3"
    ...
    <1|0|2750>                     8  java.lang.Long
    <1|0|2751>           5         8  java.lang.String
      Value: "TestB"
         Count  Tot Size  Type
                     (bytes)
             8       288  COM.odi.test.exceptionTests.Employee
            25       900  COM.odi.test.exceptionTests.Person
             6       120  COM.odi.test.exceptionTests.Person[]
             1        28  COM.odi.util.OSHashtable
            14       392  COM.odi.util.OSHashtableEntry
             1        16  COM.odi.util.OSHashtableEntry[]
           315      7560  COM.odi.util.OSVector
           315      2520  COM.odi.util.OSVectorEntry
           315      2520  COM.odi.util.OSVectorEntry[]
             4        72  java.lang.Character[]
             4        72  java.lang.Integer[]
           419      3352  java.lang.Long
             4        72  java.lang.Long[]
           317     20232  java.lang.Object[]
           736      9472  java.lang.String
             1         8  java.lang.String[]

Checking References in a Database

The osjcheckdb utility or the Database.check() method checks the references in a database. This tool scans a database and checks that there are no references to destroyed objects. The most likely cause of dangling references is an incorrectly written program. You can fix dangling references by finding the objects that contain them and overwriting the invalid references with something else, such as a null value. In addition to finding references to destroyed objects, the tool performs various consistency checks on the database.

If the tool does not find any problems it does not produce any output.

Check paths

Before you invoke osjcheckdb from the command line, ensure that tools.zip is in your CLASSPATH variable. Also ensure that the distribution bin directory that contains osjcheckdb is in your PATH variable. The format for invoking this tool from the command line is

Command line

osjcheckdb database_name1.odb ...

You can specify one or more databases. Separate multiple specifications with a space.

Be sure to specify the name of the .odb file of the database.

The tool displays messages about any errors that it finds.

API

The function signature for invoking the API for this tool is

Database.check(java.io.PrintStream)
The method writes any errors it finds to the argument stream. It also returns a Boolean value, which is true if the references are valid and false if there are any bad references.

This tool and its API are not provided with PSE.

Database Operations and Transactions

For each database operation, there are rules about whether or not it can be performed

The table below shows which rules apply to which operations. If your application tries to perform a database operation that breaks a rule, you receive a run time exception.

Database Operation Inside a Transaction? Outside a Transaction
check() Yes No
close() No Yes
create() No Yes
createRoot() Yes No
createSegment() Yes No
destroy() No Yes
destroyRoot() Yes No
getDefaultSegment() Yes No
getOpenType() Yes Yes
getPath() Yes Yes
getRoot() Yes No
getRoots() Yes No
getSegment() Yes No
getSizeInBytes() Yes No
isOpen() Yes Yes
of() Yes No
open() Yes Yes
setDefaultSegment() Yes No
setRoot() Yes No
showDB() Yes No

Restrictions

The fileMode argument to COM.odi.Database.create() does not work because Java does not allow you to specify the access mode. However, the file mode must still specify that the owner can modify the file.

Neither PSE nor PSE Pro allow cross-database references.



[previous] [next]

doc@odi.com
Copyright © 1997 Object Design, Inc. All rights reserved.

Updated: 05/13/97 12:17:33