Guide  Reference  Contents  Previous  Next  Index
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".
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".
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".
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.
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(); ... }
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.
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.
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.
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.
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".
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.
ExampleThis 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(); ... }
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.
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.
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.
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.
ExampleThis 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(); }
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.
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.
Guide  Reference  Contents  Previous  Next  Index