Working with Object Stores

This section provides information about working with object stores and contains illustrative Java™ and C# code samples.

Instantiating an ObjectStore Object

You can get a reference to an ObjectStore object by iterating an ObjectStoreSet collection. You can create an instance of ObjectStore by:

Instantiating an ObjectStore Object from a Domain

The following code example retrieves an ObjectStoreSet collection object from the Domain object. The returned collection contains elements that represent each object store defined by the Global Configuration Data (GCD). The code iterates through the collection, retrieving individual ObjectStore objects, and, by retrieving the value of the DisplayName property, returns the name of each ObjectStore object in the collection.

Java Example

// Instantiate object store from domain
public static void instantiateObjectStoreFromDomain(
        Connection conn,
        String domainName)	// Example: "Domain1"
{
    // Get domain
    Domain domain = Factory.Domain.fetchInstance(
                           conn, domainName, null);
    ObjectStoreSet osColl =  domain.get_ObjectStores();
		
    // Get each object store
    Iterator iterator = osColl.iterator();
    while(iterator.hasNext())
    {
        // Get next object store
        ObjectStore objStore = (ObjectStore)iterator.next();
			
        // Get the display name of the object store
        String objStoreName = objStore.get_DisplayName();
        System.out.println("Object store name = " + objStoreName); 
    }
}

C# Example

// Instantiate object store from domain
public static void InstantiateObjectStoreFromDomain(
IConnection conn, String domainName)  // Example: "Domain1"
{
    // Get domain
    IDomain domain = Factory.Domain.FetchInstance(
                            conn, domainName, null);
    IObjectStoreSet osColl = domain.ObjectStores;

    // Get each object store        
    foreach (IObjectStore objSstore in osColl)
    {
        // Get the display name of the object store
        String objStoreName = objStore.DisplayName;
        Debug.WriteLine("Object store name = " + objStoreName); 
    }
}

Instantiating an ObjectStore Object using Factory methods

Object stores are typically created by a system administrator using the FileNet Enterprise Manager administrative tool built into Content Engine. However, you can use factory methods as described in this section to create object stores. Prerequisites to creating an object store, whether through FileNet Enterprise Manager or programmatically, are creating a database; configuring connection pools and data sources in the application server to connect to the database; defining object store administrative users and groups defined; and defining general users and groups of the object store. Code samples in this section assume that these prerequisites have been satisfied.

createInstance method

To create a new instance of an ObjectStore object, call Factory.ObjectStore.createInstance. This method instantiates a local ObjectStore object. The ObjectStore object does not exist in the GCD until a round-trip to the server happens at a later commit (save) step. The save step can be an explicit call to the save method or via a batch operation.

Input parameters to this method are the following: a Domain object; a pre-defined set of administrative users and groups (for example, "Domain Admins") who can access the returned ObjectStore object; a pre-defined set of non-administrative security principals (users and groups, for example, "Domain Users") who can access the returned ObjectStore object; and, optionally, a customized schema script. After creating the object instance, you must set the following four properties: DisplayName, SymbolicName, JNDIDataSource (the local JNDI datasource name), and JNDIXADataSource (the transaction JNDI datasource name). You can set additional properties as needed.

Prior to object store creation, you can also set the properties that control the storage locations of various database objects. Doing so causes the appropriate database statements to be issued such that those database objects are appropriately located. The following properties control database object storage locations:

Important: Setting the DatabaseXXXStorageLocation properties AFTER the object store has been created only affects database locations of objects (that is, tables, indexes, or LOB columns) that are subsequently created.

In addition, you can call a different form of the createInstance method that takes a schema script. By using a customized schema script, a Database Administrator (DBA) can make modifications to the object store database schema. The DBA can obtain a factory-generated script relative to the database type by accessing the corresponding property on the Domain object. The properties are named ObjectStoreSchemaDB2, ObjectStoreSchemaMSSQL, and ObjectStoreSchemaOracle, and their values contain the factory-generated schema for an object store corresponding to the database vendor indicator. This approach overrides the values set by the DatabaseXXXStorageLocation properties during object store creation.

In the code fragments below, a connection (conn) is assumed to already have been established. The code retrieves the domain and then creates an ObjectStore object that represents ObjectStore1. The example provides an option to create the object store with a customized schema script.

Java Example

// Create an object store instance
public static void createObjectStoreInstance(
    Connection conn,
    String[] adminName,   // Example: "Domain Admins, CEMPAdmin"
    String[] userName,    // Example: "Domain Users, CEMPUser"
    String jndiSource,    // JNDI data source. Example: "myJndiDataSource"
    String objStoreName,  // Object store name. Example: "ObjectStore1"
    String scriptPath)    // Creation script file path. Example: "C:\os_script.txt"
	
    throws Exception {
            
        // Get the default domain
        Domain domain = Factory.Domain.getInstance(conn, null);

        // Create an object store
        String[] admins = {adminName};
        String[] users = {userName};
        ObjectStore objStore = null;
		
        if (scriptPath == null) {
            // Create without using a schema script
            System.out.println("Creating object store without a schema script");
            objStore = Factory.ObjectStore.createInstance(
                              domain, admins, users);
        } 
        else {
            // Create using a schema script
            // The getScript method reads in the script from a file
            String creationScript = getScript(scriptPath);
            System.out.println("Creating object store with a schema script");
			
            // To print the contents of the script file, uncomment the next line.
            // System.out.println(creationScript); 
            objStore = Factory.ObjectStore.createInstance(
                              domain, admins, users, creationScript);   		
        }

        // Set properties
        objStore.set_DisplayName(objStoreName);
        objStore.set_SymbolicName(objStoreName);
        objStore.set_JNDIDataSource(jndiSource);
        objStore.set_JNDIXADataSource(jndiXASource);
  
        // Save object store and display name
        objStore.save(RefreshMode.REFRESH);
        System.out.println("Object store name: " +  objStore.get_Name()); 
    }

C# Example

// Create an object store instance
public static void CreateObjectStoreInstance(
    IConnection conn,
    String[] adminName,    // Example: "Domain Admins, CEMPAdmin"
    String[] userName,     // Example: "Domain Users, CEMPUser"
    String jndiSource,     // Example: "myJndiDataSource"
    String jndiXASource    // Example: "myJndiXADataSource"
    String objStoreName,   // Object store name. Example: "ObjectStore1"
    String scriptPath)     // Creation script file path. Example: "C:\os_script.txt"
		
    // Get the default domain
    {IDomain domain = Factory.Domain.GetInstance(conn, null);
  
        // Create an object store         
        String[] admins = {adminName};
        String[] users = {userName};
        IObjectStore objStore = null;
		
        if (scriptPath == null) {
            // Create without using a schema script
            Debug.WriteLine ("Creating object store without a schema script");
            objStore = Factory.ObjectStore.CreateInstance(
                              domain, admins, users);
        }
        else {		
            // Create using a schema script       
            // The GetScript method reads in the script from a file 
            String creationScript = GetScript(scriptPath);
            Debug.WriteLine("Creating object store with a schema script");
			
            objStore = Factory.ObjectStore.CreateInstance(
                              domain, admins, users, creationScript);
        }
			 
        // Set properties
        objStore.DisplayName = objStoreName;
        objStore.SymbolicName = objStoreName;
        objStore.JNDIDataSource = jndiSource;              
        objStore.JNDIXADataSource = jndiXASource;         

        // Save object store and display name
        ojbStore.Save(RefreshMode.REFRESH);   
        Debug.WriteLine("Object store name: " +  objStore.Name); 
    }

getInstance method

You can construct a local instance of the ObjectStore class by calling Factory.ObjectStore.getInstance. This method does not verify the existence of the requested object on the server; it returns a local reference to the object, which is not affiliated with a server object until you perform a function on the object (for example, fetch a property value) that causes a round-trip to the server. This technique, also called "fetchless instantiation", is useful when the desired object will only serve passively, for example, as the target value of an object-valued property. The code fragment below instantiates an ObjectStore object in this manner:

Java Example

// Get object store instance
static void getObjectStoreInstance(
        Domain domain,
        String objStoreName)	// Example: "ObjectStore1"
 {
    // Get object store (fetchless instantiation)
    ObjectStore ojbStore = Factory.ObjectStore.getInstance(domain, objStoreName);

    // Show object store name
    objStore.refresh();
    System.out.println("Object store name: " + objStore.get_Name());    	      	  
 }

C# Example

// Get object store instance
static void GetObjectStoreInstance(
        IDomain domain,
        String objStoreName)   // Example: "ObjectStore1"
{            
    // Get object store (fetchless instantiation)
    IObjectStore objStore = Factory.ObjectStore.GetInstance(domain, objStoreName);

    // Show object store name
    objStore.Refresh();
    Debug.WriteLine("Object store name: " + objStore.Name); 
}

fetchInstance method

To retrieve a particular ObjectStore object from the server, call Factory.ObjectStore.fetchInstance. This method makes a round-trip to the server to retrieve the property values of the ObjectStore object. You can limit the number of properties that are returned by using a property filter as shown in the code samples below. 

Java Example

// Get object store instance
static void fetchObjectStoreInstance(
        Domain domain,
        String objStoreName)    // Example: "ObjectStore1"
{
    // Define a property filter to limit the returned properties
    PropertyFilter filter = new PropertyFilter(); 
    filter.addIncludeProperty(0, null, null,
                              PropertyNames.ROOT_CLASS_DEFINITIONS, null); 
    filter.addIncludeProperty(0, null, null, 
                              PropertyNames.DISPLAY_NAME, null); 
    	  
    // Fetch object store using the property filter    	
    ObjectStore objStore = Factory.ObjectStore.fetchInstance(
                                  domain, objStoreName, filter);

    // Show object store display name
    System.out.println("Object store name: " + objStore.get_DisplayName());   	    	
}

C# Example

// Get object store instance
static void FetchObjectStoreInstance(
            IDomain domain,
            String objStoreName)    // Example: "ObjectStore1"
{
    // Define a property filter to limit the returned properties
    PropertyFilter filter = new PropertyFilter(); 
    filter.AddIncludeProperty(0, null, null,
                              PropertyNames.ROOT_CLASS_DEFINITIONS, null); 
    filter.AddIncludeProperty(0, null, null, 
                              PropertyNames.DISPLAY_NAME, null); 
  
    // Fetch object store using the property filter
    IObjectStore objStore = Factory.ObjectStore.FetchInstance(
                                   domain, objStoreName, filter); 

    // Show object store display name
    Debug.WriteLine("Object store name: " + objStore.DisplayName);     
}

Instantiating an ObjectStore Object from a RepositoryObject subclass

A RepositoryObject is any object that can be stored in an object store (such as Document, Folder, Annotation, and so on). The getObjectStore method of the RepositoryObject interface returns the object store to which an object belongs, as shown in the code fragments below:

Java Example

	
// Get object store from repository object sub class
private static void getObjectStoreFromSubclass(
    Document doc)  // Get a document using your own approach, for example, from a collection
{
    // Get the object store in which the document is stored 
    ObjectStore objStore = doc.getObjectStore();

    // Get the display name of the returned object store
    objStore.refresh();
    System.out.println("Object store name = " + objStore.get_DisplayName()); 
}

C# Example

// Get object store from repository object sub class
private static void GetObjectStoreFromSubclass(
    IDocument doc)  // Get a document using your own approach, for example, from a collection
{

    // Get the object store in which the document is stored 
    IObjectStore objStore = doc.GetObjectStore();

    // Get the display name of the returned object store
    objStore.Refresh();  
    Debug.WriteLine("Object store name = " + objStore.DisplayName); 
}

Installing an AddOn Object on the Object Store

Before you can install an addon to an object store, you must first create and save it, which automatically registers it in the IBM FileNet P8 Global Configuration Data (GCD) database of a domain. Once an addon is registered, you can install it to a new or existing object store.

To install a registered AddOn or UpgradeAddOn object, use the installAddOn method on the ObjectStore interface. Input to this method is the registered object you wish to install. For a code sample that illustrates how to retrieve the installable addons from the domain and select one for installation, refer to Working with Addon-Related Objects.

Setting Object Store Access Rights

The permissions (access rights) associated with an object store control the degree of access that users have to the objects within the object store. In the example below, user "CEMPAdmin" is granted full control to work with documents in this object store. Granting full control means that the specified user is granted permission to connect to the object store, store objects, modify objects, and remove objects. (For additional examples, see Setting Permissions.)

Java Example

// Set access rights
public static void setAccessRights(
    Domain domain,
    String granteeName,		// Example: "CEMPAdmin"
    String objStoreName)	// Example: "ObjectStore1"
{

    // Create a new access permission object
    AccessPermission ap = Factory.AccessPermission.createInstance();
                
    // Set access permissions  
    ap.set_GranteeName(granteeName);
    ap.set_AccessType(AccessType.ALLOW);            
    ap.set_AccessMask(new Integer(AccessLevel.FULL_CONTROL_OBJECT_STORE_AS_INT)); 

    // Set and save the new permissions
    ObjectStore objStore = Factory.ObjectStore.fetchInstance(domain, objStoreName, null);
    AccessPermissionList apl = objStore.get_Permissions();
    apl.add(ap);
    objStore.set_Permissions(apl); 
    objStore.save(RefreshMode.REFRESH);
}

C# Example

// Set access rights
public static void SetAccessRights(
    IDomain domain,
    String granteeName,     // Example: "CEMPAdmin"
    String objStoreName)    // Example: "ObjectStore1"
{
    // Create a new access permission object
    IAccessPermission ap = Factory.AccessPermission.CreateInstance();
              
    // Set access permissions  
    ap.GranteeName = granteeName;  
    ap.AccessType = AccessType.ALLOW;
    ap.AccessMask = (Int32)AccessLevel.FULL_CONTROL_OBJECT_STORE;

    // Set and save the new permissions
    IObjectStore objStore = Factory.ObjectStore.FetchInstance(domain, objStoreName, null);    
    objStore.Permissions.Add(ap);
    objStore.Save(RefreshMode.REFRESH);        
}

Setting Privileged Write Access on an Object Store

To users who run system-level tools, such as import/export, migration applications, and federation tools, and who therefore require the ability to modify certain system-level properties, you must explicitly grant Privileged Write access (AccessRight.PRIVILEGED_WRITE). This access right is not included in "Full Control" levels of object store access. After granting the access right, an application can make calls to change the system-level properties. (For conceptual information about privileged write access and system-level properties, see the Security topic.)

Important:

The code snippet below sets privileged write access on the object store, allowing a special administrative user the right to modify system-level properties on a document. The special user is allowed to set the document properties to reflect original creator, create date, and modification information.

Java Example

// Set write access
private static void setWriteAccess(
    ObjectStore objStore,    
    String granteeName,
    String granteePassword,
    String originalCreator,
    Date originalCreateDate,
    String originalModifier,
    Date originalModifyDate)
{
    // Create a new access permission object
    AccessPermission ap = Factory.AccessPermission.createInstance();

    // Set access permissions  
    ap.set_GranteeName(granteeName);  
    ap.set_AccessType(AccessType.ALLOW);
    ap.set_AccessMask( 
        new Integer(AccessRight.PRIVILEGED_WRITE_AS_INT + 
                    AccessLevel.FULL_CONTROL_OBJECT_STORE_AS_INT));

    // Add the permission to the list for the Object Store
    objStore.get_Permissions().add(ap);            
            
    // Save the object store with its permissions
    objStore.save(RefreshMode.REFRESH);
            
    // Login in as the user who has the newly granted
    // privileged write access
    Connection conn = objStore.getConnection();
    Subject sub = UserContext.createSubject(conn, granteeName, granteePassword, "FileNetP8");
    UserContext.get().pushSubject(sub);

    // Create a document "doc"
    Document doc = Factory.Document.createInstance(objStore, "Document");
            
    // Set system-level properties on the created document "doc" 
    doc.set_Creator(originalCreator);
    doc.set_DateCreated(originalCreateDate);
    doc.set_LastModifier(originalModifier);
    doc.set_DateLastModified(originalModifyDate);
            
    // Perform additional actions as desired
            
    // Save the document            
    doc.save(RefreshMode.REFRESH);
    System.out.println("Document created: " +  doc.get_Id());
}

C# Example

// Set write access
private static void SetWriteAccess(
    IObjectStore objStore,
    String granteeName,
    String granteePassword,
    String originalCreator,
    DateTime originalCreateDate,
    String originalModifier,
    DateTime originalModifyDate)
{
    // Create a new access permission object
    IAccessPermission ap =
        Factory.AccessPermission.CreateInstance();

    // Set access permissions  
    ap.GranteeName = granteeName;
    ap.AccessType = AccessType.ALLOW;
    ap.AccessMask = (Int32)AccessRight.PRIVILEGED_WRITE + 
                    (Int32)AccessLevel.FULL_CONTROL_OBJECT_STORE;

    // Set permissions
    objStore.Permissions.Add(ap);

    // Save the object store with its permissions
    objStore.Save(RefreshMode.REFRESH);

    // Login in as user with newly granted write access
    UsernameToken token = new UsernameToken(granteeName, granteePassword, PasswordOption.SendPlainText);
    UserContext.SetThreadSecurityToken(token);
            
    // Create a document "doc"
    IDocument doc = Factory.Document.CreateInstance(objStore, "Document");

    // Set system-level properties
    doc.Creator = originalCreator;
    doc.DateCreated = originalCreateDate;
    doc.LastModifier = originalModifier;
    doc.DateLastModified = originalModifyDate;

    // Perform additional actions as desired

    // Save the document
    doc.Save(RefreshMode.REFRESH);
    Debug.WriteLine("Document created: " + doc.Id);
}

Avoid read-only exception on update

If you subsequently fetch the document object with the intent of modifying its LastModifier or DateLastModified property values again, another step is required. In this scenario, you might subsequently fetch the document object with a filter specifying (directly or indirectly) the LastModifier or DateLastModified property and update those property values. When you call save, a client-side read-only exception is thrown. To avoid the exception, prior to updating the property values and calling save, you must call removeFromCache to remove LastModifier and DateLastModified properties from the local property cache.

Working with Custom Schema Scripts

You can create an object store specifying a customized schema script by calling the Factory.ObjectStore.createInstance(domain, admins, users, schemaScript) method. By using a customized schema script, you can get finer grained control of storage locations for object store tables, indexes, and LOB columns than you can get by using the ObjectStore object's default database storage locations.

Your customized schema script should be derived from one of the default (factory-generated) scripts available via the ObjectStoreSchemaXXX properties, where XXX is DB2, MSSQL, or Oracle. The schema script must also contain the correct version information. The version information in the header of the script must correspond to the Content Engine's schema revision level indicator, which is stored in the ObjectStore database's DDState.schema_revision_string column. When the script is retrieved via the Domain-level property, it contains the correct revision level. However, in rare circumstances (usually involving an upgrade to the server after the script was retrieved), the schema revision string stored in the database might not match the revision information in the schema script header. Content Engine will not process the script if this indicator does not match the schema revision level expected by the Content Engine server and an exception will be generated. The following text is an example of the version information found in the script header (the generation date and revision number will be different in your environment):

-- Generated for SQL Server databases on: Wed Apr 02 11:11:30 PDT 2008
-- The following SchemaRevision comment must be present and must correspond to
-- the proper schema revision level at the time the ObjectStore is created.
-- SchemaRevision: 14.1.14

Important: When customizing the script, do not alter any of the names and structures of existing tables, indexes, or columns. Doing so will cause system failures.

Note that the DB2 for z/OS script is available from the ObjectStoreSchemaDB2 property when the GCD is configured against a DB2 for z/OS database. When modifying the default database scripts, be aware that the DB2 for z/OS script differs significantly from the scripts for DB2 on LUW, MSSQL, and Oracle, including the use of substitution placeholders. Each substitution variable is surrounded by a question mark character (?) and the variable name corresponds to a string-valued custom property name specified during WebSphere application server configuration. The following excerpt shows how this variable is used within the script (the ellipses in this example indicate additional statements that have been deleted for brevity):

CREATE TABLE DocVersion(object_id varchar(16) for bit data NOT NULL PRIMARY KEY , object_class_id varchar(16) for bit data NOT NULL , security_id varchar(16) for bit data NOT NULL , … , security_folder_id varchar(16) for bit data ) IN DATABASE ?zOSDatabaseName?
CREATE INDEX I_DocVersion22 ON DocVersion (version_series_id, major_version_number DESC, minor_version_number DESC)  USING STOGROUP ?zOSDefaultSTOGROUP? ?zOSSTOGROUPOptions?

Compare the example above with the MSSQL script excerpt below (the ellipses indicate additional statements that have been deleted for brevity):

CREATE TABLE DocVersion(object_id uniqueidentifier NOT NULL PRIMARY KEY , object_class_id uniqueidentifier NOT NULL , security_id uniqueidentifier NOT NULL , … , security_folder_id uniqueidentifier )
CREATE INDEX I_DocVersion22 ON DocVersion (version_series_id, major_version_number DESC, minor_version_number DESC)