Guide  Reference  Contents  Previous  Next  Index



Naming Persistent Objects

Naming a persistent object allows you to identify the object with a name that is meaningful to you or the users of your application. Naming also facilitates retrieval of the object from the database by enabling you to look it up by name. This chapter describes how to give a persistent object (including a persistent collection or a persistent container) names of any of the following types:

Unlike other persistent objects, a container can also have a system name because it is a storage object. You can specify a container's system name as a parameter to the addContainer method that adds the container to a database; to look up the container by its system name, you call the lookupContainer method of its database. For more information, see "System Names".

In This Chapter

Named Roots
Root Names
Making an Object a Named Root
Working With Root Names
Name Scopes
Scope Names
Defining a Scope Name
Working With Scope Names
Application-Defined Dictionaries
Creating a Name Map
Adding a Name to the Dictionary
Working With Name Maps
Comparison of Naming Mechanisms

Named Roots

A named root is a persistent object that can be located by a root name, which is unique within the federated database or a particular database. Typically, a named root is the root object in a directed graph of persistent objects. When you first write the named root to the database, you store the entire graph. You can use the root name to retrieve the named root, and you can then traverse links of the named root to retrieve all the objects in its graph. See "Finding Objects in a Graph".

Root Names

A root name can be any valid Java string of arbitrary length. A federated database or database stores its root names in its root dictionary (a name map). An object can have more than one root name within the same database and can have a root name in more than one database. Each root name in a particular root dictionary must be unique within that root dictionary; that is, a given database cannot have more than one object with the same root name.

A database with named roots has a special container, called its roots container, where it stores its root dictionary. A roots container is used primarily for the root dictionary, but the default clustering strategy may store named roots (and the objects in their object graphs) in the roots container. You can increase concurrent access to the root directory by storing named roots in different containers. For more information about clustering and concurrency, see "Assigning Basic Objects to Containers".

Making an Object a Named Root

To give an object a root name, you call the bind method of the federated database or database in which you want the object to be a named root. The session that owns the local representation of the federated database or database must be in a transaction.

The bind method takes the object to be named and the root name as parameters. The session must be able to obtain a write lock on the root dictionary of the federated database or database. The bind method throws a checked exception if the federated database or database already has a root with the specified root name.

If an object is transient when you make it a named root, the bind method makes the object persistent. In that case, the default clustering strategy clusters the object into the roots container. Once the object has been made persistent, it belongs to the same session as the federated database or database in which it was named.


Note: If you store a named root in the roots container or any other garbage-collectible container, and your application depends on the oogc administrative tool to delete unreferenced objects, be sure that all objects in the named root's object graph are also stored in garbage-collectible containers. For more information, see "Garbage-Collectible Containers".

Example

This code fragment makes an object of the Salesperson class a named root in the database salesDB. The complete method definition appears in the Sales.Interact programming example . The Interact class has a static field called session, which is initialized to contain an instance of the Session class when the connection is opened; all examples in this chapter use that session object for transaction control.

    // Static utility to add a salesperson
    public static Salesperson addSalesperson (...) {
        ...
        session.begin();
        ...
        ooDBObj salesDB = ...;
        ...
        Salesperson salesperson = ...;
        ...
        String rootname = ...;
        // Make new salesperson a named root
        try {
            salesDB.bind(salesperson, rootname);
        } catch (ObjectNameNotUniqueException e4) {
            System.out.println("Employee ID " + rootname +
                                    " already in use.");
            session.abort();
            return null;
        }
        session.commit();
        ...
    }

Working With Root Names

Once you have defined root names in the connected federated database or a particular database, you can take any of the following actions. All operations involving root names must be performed while the session that owns the local representation of the federated database or database is in a transaction.

The session must be able to obtain a read lock on the root dictionary.
The session must be able to obtain a read lock on the root dictionary.
The session must be able to obtain a write lock on the root dictionary.
Although named roots are stored in name maps, there is no method to directly replace an object associated with a name in the root dictionary. If you want to replace an object in the root dictionary, you must first unbind a name and then rebind the name to a new object.


Note: If a named root is stored in the roots container or any other garbage-collectible container, removing its root name makes the object subject to garbage collection unless the object can be reached from another named root or from an indexed object. If the named root cannot be reached, all objects in its graph are also subject to garbage collection unless they can be reached by some other path.

Name Scopes

Objectivity/DB provides a mechanism that allows you to name persistent objects within the scope of a particular scope object. A scope object can be the federated database, a database, a persistent container, or a persistent basic object.


Note: If you want to use a container as a scope object, the container must be hashed. If you want to use a basic object as a scope object, its container must be hashed. When you add a container to a database, a parameter to the addContainer method specifies whether the container should be hashed.

A scope object defines a name scope, that is, a set of names for persistent objects. Each name in the set is called a scope name and uniquely identifies a persistent object to the scope object (but not to other objects). You can think of a name scope as a local name space defined by the scope object.

Scope Names

A scope name can be any valid Java string of arbitrary length. Different scope objects may use different scope names to refer to the same object.

A scope object uses the hashing mechanism of a hashed container to associate each name in the name scope with the appropriate object. The following table identifies the hashed container used by each kind of scope object.

Scope Object Uses Hashing Mechanism Of
Basic objectThat basic object's container
ContainerThat container
DatabaseThe default container of that database
Federated databaseThe default container of the default database of that federated database

The default clustering strategy may store named objects in the hashed container used by the scope object. You can increase concurrent access to the scope names by storing scope-named objects in different containers. You should store scope-named objects in non-garbage-collectible containers. For more information about clustering and concurrency, see "Assigning Basic Objects to Containers".

Defining a Scope Name

To give an object a scope name, you call the nameObj method of the scope object. The session that owns the local representation of the scope object must be in a transaction.

The nameObj method takes the object to be named and the scope name as parameters. The session must be able to obtain a write lock on the hashed container used by the scope object. A runtime error is thrown if nameObj fails, for example, because some object already has the specified name in the scope object's name scope.

If an object is transient when you give it a scope name, the nameObj method makes the object persistent. In that case, the default clustering strategy clusters the object into the hashed container used by the scope object. Once the object has been made persistent, it belongs to the same session as the scope object.

You cannot associate a scope name with a null object reference. If you have a need to associate names with null object references, you must use one of the other two naming mechanisms.

Example

This code fragment names an object of the Contact class in the scope of the container scope. The complete method definition appears in the Sales.Interact programming example .

    // Static utility to add a contact
    public static Contact addContact (...) {
        ooContObj scope;
        ...
        session.begin();
        ...
        Contact contact = ...;
        ...
        scope = ...;
        ...
        String scopename = ...;
         // Give the contact a scope name
        try {
            scope.nameObj(contact, scopename);
        } catch (ObjyRuntimeException e) {
            System.out.println("Contact " + scopename + 
                               " already exists.");
            session.abort();
            return null;
        }
        session.commit();
        ...
    }

Working With Scope Names

Once you have defined scope names for a scope object, you can take any of the following actions. These operations must be performed while the session that owns the local representation of the scope object is in a transaction.

The session must be able to obtain a read lock on the hashed container used by the scope object.
The session must be able to obtain a read lock on the hashed container used by the scope object.
The session must be able to obtain a write lock on the hashed container used by the scope object.

Application-Defined Dictionaries

You can implement an application-defined dictionary with a name map in which the keys are object names. You can create as many such dictionaries as you like; each dictionary represents a separate name space for objects. You can name a given object in as many dictionaries as you like.

One advantage of using an application-defined dictionary is that you have control over the clustering and growth performance of the name map that implements the dictionaries.

Creating a Name Map

You can create a name map and make it persistent just as you would with any persistent object. Before you create the name map, you should decide:

In many applications, a name map is a resource that will be shared by many users who need to name and look up objects. If you expect names to be added to, and deleted from, the dictionary by multiple users, you need to plan for concurrent access to the name map. For example, you could put the name map in a container by itself or in a container with few other objects that require updates. For more information about clustering and concurrency, see "Assigning Basic Objects to Containers".
You can set the initial number of bins (hash buckets), the maximum average number of elements in a bin, and the percentage by which the name map's hash table grows when it is resized.

Your decisions determine how to set the parameters to the constructor that you use to create the name map. For additional information about growth characteristics and a detailed description of the constructors that create name maps, see the ooMap class description in the Objectivity for Java reference.

In addition to creating the name map, you must plan how applications will retrieve it from the database.

Adding a Name to the Dictionary

After creating a name map to be used as an application-defined dictionary, you can add a name to the dictionary by calling the add or forceAdd method of the name map. The session that owns the local representation of the name map must be in a transaction and must be able to obtain a write lock on the name map. Both methods take as parameters the object to be named and its proposed name; they differ in their behavior when the proposed name is already a key in the name map.

The forceAdd method is faster than the add method and can be used to initialize dictionaries when they are created. After initial creation, the add and replace methods can be used for maintenance of the dictionary.

If an object is transient when you add the name to the name map, it is made persistent. In that case, the default clustering strategy clusters the object into name map's container. Once the object has been made persistent, it belongs to the same session as the name map.

Example

This code fragment names an object of the Client class in the application-defined dictionary nameTable; the name of the client company is used as the object's name. The complete method definition appears in the Sales.Interact programming example .

    // Static utility to add a client
    public static Client addClient (String companyName, ...) {
        ...
        ooMap nameTable;
        ...
        session.begin();
        ...
        Client client = ...;
        ...
        nameTable = ...;
        ...
        // Add client to name map
        try {
            nameTable.add(client, companyName);
        } catch (ObjyRuntimeException e) {
            System.out.println("Company " + companyName +
                               " already exists.");
            session.abort();
            return null;
        }
        session.commit();
        }

Working With Name Maps

Once you have created a name map, you can take any of the following actions. All these operations must be performed while the session that owns the local representation of the name map is in a transaction.

Comparison of Naming Mechanisms

All three naming mechanisms accept arbitrary Java strings as names and use a hashing mechanism to associate names with persistent objects. Scope names use a hashed container to organize the names; root names and application-defined dictionaries both use name maps.

The following table contains a summary of the limitations and advantages of the three naming mechanisms.

 LimitationsAdvantages
Root Names You must name objects in a name space defined by the federated database or a database. Each database and federated database can have only one such name space.You can store named roots and their object graphs in garbage-collectible containers to simplify database maintenance.
You can look up named objects directly through the federated database or database. If desired, you can associate a root name with a null object reference.
Scope Names Scope objects must use hashed containers, which take more space than non-hashed containers.
You cannot associate a scope name with a null object reference.
You can name objects in a name space defined by a basic object, a container, a database, or the federated database (but each scope object can have only one such name space).
You can look up named objects directly through the scope object.
Names in
Name Maps
You must explicitly retrieve the name map before you can look up objects.You can name objects in any name space that is meaningful to the application; each name map represents such a name space.
You can control where the name map is stored, thus improving concurrency.
You can tune the name map for the performance needs of your application. If desired, you can associate a name with a null object reference.



Guide  Reference  Contents  Previous  Next  Index



Copyright © 2000, Objectivity, Inc. All rights reserved.