Service Based Objects (SBO’s) in Documentum


Documentum Business Object Framework which was introduced from Documentum 5.3 plays a key role in most of the current Documentum implementations.  Service-based Object is one of the basic members of Documentum BOF family.  Let’s try to see what makes Service Based Objects very popular and how can you implement it.

What is an SBO

In simple terms, SBO in Documentum can be compared to session beans of the J2EE environment.  SBO enable the developers to concentrate just on the business logic, and all the other aspects will be managed for you by the server. This reduces the application code significantly and reduces lots of complexities. The most significant advantage of a BOF that it’s deployed in a central repository. The repository maintains this module and DFC ensures that the latest version of the code is delivered to the client automatically.

Service-Based Objects are repository and object type in-depended that means the Same SBO can be used by multiple Documentum repositories and can It can retrieve and do operations on different object types. SBO’s can also access external resources, for example, a Mail server or an LDAP server. Before the introduction of Documentum Foundation Services, SBO’s were commonly used exposed to expose Documentum web services.

An SBO can call another SBO or by any Type based Objects. (Type Based Objects (TBO) are a different kind of Business Object types which I will explain in a separate study note)

A very simple to understand example for an SBO implementation would be a Zip code Validator. Multiple object types might have Zip code across multiple repositories.  So if this functionality is exposed as an SBO, it can be used by the custom application irrespective of Object types and repositories. This Validator SBO can be used even by different TBO’s for validations.

Here are some bullet points about SBO’s for easy remembering

  • SBO’s are part of Documentum Business Object framework
  • SBO’s are not associated with any repositories
  • SBO’s are not associated with any Documentum object types.
  • SBO information is stored in repositories designated as Global Registry.
  • SBO’s are stored in /System/Modules/SBO/<sbo_name> folder of repository. <sbo_name> is the name of SBO.
  • Each folder in /System/Modules/SBO/ corresponds to an individual SBO

How to implement an SBO using Composer

The steps to create an SBO are these.

1) Create an interface that extends IDfService define your business method
2) Create the implementation class implement write your business logic, This class should extend DfService and implement the interface defined in Step 1
3) Create a jar file for the created Interface and another jar for the implementation class then create Jar Definitions
4) Create an SBO Module and Deploy your Documentum Archive using Documentum Composer (Application builder for older versions)

Let’s see these steps with an Example SBO Zip Code Setter, I am not covering the steps using application builder here. The screenshots and the notes will give you an insight into how to use Documentum Composer to implement a Service Based Object in Documentum version 6 or above.

Step 1: Create an interface and define your Business method

The first step is to create an interface which will define the business functionality. This interface should extend IDfService interface. The client application will use this interface to instantiate the SBO.

Click New –> Interface in Documentum Composer. Click on the Add button of Extended Interfaces and search for IDfService. Select IDfService and click OK

image

Now Add the Business method ValidateZipCode() to an interface. The code should look like the following.

package com.ajithp.studynotes.sbo;

import com.documentum.fc.client.IDfService;
import com.documentum.fc.client.IDfSysObject;
import com.documentum.fc.common.DfException;

public interface IZipValidatorSBO extends IDfService {

public void validateZipCode (IDfSysObject obj, String zipCode, String repository)throws DfException;
}
Step 2: Create the implementation class

All the Service Based Object implementation classes should extend from DfService class and implement the Interface created in the first step.  DfService class is an abstract class There are few methods which were abstract in 5.3 and has provided with a default implementation in 6.0 and later

Method Name Returns More information
getVendorString() String This method’s default implementation returns a empty String. Override to make changes to it.
getVersion() String This method returns a version which is not right, Override this method to return Major.minor version.
isCompatible() boolean The default implementation returns true if the version is an exact match

Let’s see some other important methods of DfService Class before we move further.

Method Name Returns More information
getName() String This returns the fully qualified logical name of the service interface
getSession() IDfSession This method returns IDfsession Object for the docbase name which is passed as argument to this method. You have to make sure that you call releaseSession() after you are done with the operation that involves session.
releaseSession() Releases the handle to the session reference passed to this method.
getSessionManager() IDfSessionManager Returns the session manager.

Managing repository sessions in SBO As We saw the previous table its always good practice to release the repository session as soon as you are done with its use. So the ideal way to do this should be like this.

// Get the session 
IDfSession session = getSession(repoNam);
try {
// do the operation with session
} catch (Exception e){
// Process the exception 
}finally {
// release the session 
releaseSession(session)
}

Transactions in SBO

Another important thing is to know is how to handle transactions in SBO. Note that only session manager transactions can be used in an SBO. The system will throw an Exception when a session based transaction used within an SBO.

beginTransaction() will start a new Transaction and use commitTransaction() to commit it or abortTransaction() to abort a transaction.  Always ensure that you are not beginning a transaction where another transaction is active. You can use isTransactionActive() to find out whether a transaction is active or not.

Another important point is if your SBO doesn’t start a transaction don’t commit it or abort it in the SBO Code instead if you want to abort the transaction use setTransactionRollbackOnly() method.

Other important points

1) Since SBO’s are repository independent, do not hardcode the repository names in the methods. Either pass the repository name as a method parameter or have it as a variable in SBO and use a setter method to populate it after instantiating

2) Always try to make SBO’s stateless (Its a pain to manage state full SBO’s ).

3) Don’t reuse SBO, Always create a new instance before an operation.

Now let’s see how to code our ZipSetterSBO

Click on New –> Class, Click on the Browse button of Superclass and Search and Select DfService and in the Interfaces search for the Interface created in the previous step and Click OK. Also, select the option Inherited Abstract Methods in Which method stubs would you like to create.

image

I had overridden method getVersion() for the illustration purpose. See the code sample for the inline comments.

package com.ajithp.studynotes.sbo.impl;

import com.ajithp.studynotes.sbo.IZipValidatorSBO;
import com.documentum.fc.client.DfService;
import com.documentum.fc.client.IDfSession;
import com.documentum.fc.client.IDfSysObject;
import com.documentum.fc.common.DfException;

public class ZipValidator extends DfService implements IZipValidatorSBO {

public static final String versionString = "1.0";
// overriding the default 
public String getVersion() {
        return versionString ;
      }

public void validateZipCode (IDfSysObject obj, String zipCode, String repository) throws DfException {
     IDfSession session = getSession(repository);
     try {
     if (isValidUSZipcode(zipCode)){
         obj.setString("zipcode",zipCode);
         obj.save();
      }
     } catch (Exception e){
         /* Assuming that transaction is handled outside the code and this says DFC to abort the transaction 
         in case of any error */
        getSessionManager().setTransactionRollbackOnly();
        throw new DfException();
     } finally {
     releaseSession(session);
    }
  }
 private boolean isValidUSZipcode(String zipCode){
     // implement your logic to validate zipcode. 
     // or even call a external webservice to do that 
     // returning true for all zip codes
      return true;
   }
}
Step 3: Generate Jar files and Create Jar Definitions

The next step in SBO creation is to create Jar files which will hold the interface and the implementation classes. These jar files are required to deploy your SBO.

Use Composers/Eclipse Create Jar option or command line jar command to create the jar file

image image

image

Selecting the sbo package to create the interface jar

image

Selecting the com.ajithp.studynotes.sbo.impl for implementation.

Look at the Composers Export Jar screenshots for Interface and implementation (Refer Eclipse Documentation for more details). I think the figures posted above are self-explanatory.

The Command line to create a Jar file is jar cf <name_of_jar>, Please look at the Java Documentation for more details on switches and options of Jar command.

The creation of Jar Definitions is new step added in Composer.

1) In Composer change the perspective to Documentum Artifacts Click New –> Other –> Documentum Artifacts –> Jar Definition

image

2) Click Next  and Enter the name of for the Jar Definition and click Finishimage

3) Select Type as Interface if the jar has only interface, Implementation if the jar has the only implementation of interface or Interface and Implementation if the single jar file has both interface and implementation. Click on the Browse button and browse to the jar created in the last step.

In Our case create two Jar Definitions The first one with type as Interface pointing to Jar Created for SBO and a second one with type Implementation pointing to the implementation jar

untitled

Name the Interface jar def as zipcodevalidator and the implementation jardef as zipcodevalidatorimpl

Step 4: Create a Module and Deploy the SBO

In Composer change the perspective to Documentum Artifacts then Click New –> Other –> Documentum Artifacts –> Module

image

Give a valid name and leave the default folder and Click Finishimage

In the Module, edit window select SBO from the dropdown

image

Now Click on Add Section of Implementation Jars of Core Jars. A new pop up window will appear which will have a list of all the Jar definitions set to Type Implementation and Interface and Implementation. Select the one you wanted to use for ZipCodeValidatorSBO that is ZipCodeValidatorImpl.

image

Click on the Select Button near pointing to Class name and Select the implementation class. In this case ZipValidator

image

Now Click on Add Section of Interface Jars of Core Jars. A new pop up window will appear which will have a list of all the Jar definitions set to Type Interfaces and Interface and Implementation. Select the one you wanted to use for ZipCodeValidatorSBO that is ZipCodeValidator.

image

For more details of other options refer to Documentum Composer Manual. Save the Module.

Now right click on the project and install the Documentum project

image

Click on the Login button after logged in Click on Finish to start the installation.

image

 

Look at the Documentum composer documentation to know more about the Installation options.

How to use SBO from a Client Application

follow the below steps to instantiate an SBO from a client application.

1) Get the Local client

2) Create login info and populate the login credentials.

3) Create an IDfSessionManager object

4) Use the newService () from the Client Object to create an SBO instance

// create client
  IDfClient myClient = DfClient.getLocalClient();
  // create login info
  IDfLoginInfo myLoginInfo = new DfLoginInfo();
  myLoginInfo.setUser("user");
  myLoginInfo.setPassword("pwd");
  // create session manager
  IDfSessionManager mySessionManager = myClient.newSessionManager();
  mySessionManager.setIdentity("repositoryName", myLoginInfo);
  // instantiate the SBO
  IZipValidatorSBO zipValidator = (IZipValidatorSBO) myClient.newService( IZipValidatorSBO.class.getName(), mySessionManager);
  // call the SBO service
  zipValidator.validateZipCode(obj, zipCode, "repositoryName");

Download this Study Note (PDF)

Using Java reflection to reduce Code and Development time in DFS


 

Java reflections are one of the most powerful API’s of Java Language, this can be used to reduce code significantly.

Most of the Current Enterprise application consists of different layers and they use Value objects to transfer data from one layer to another. An inefficient way of using getters and setters of the attributes of Value objects can increase code and development time of application. Effective use of reflection can reduce code and development time significantly.

So let’s take a Scenario,  I have an Object type MyObjectType extending from dm_document with 50 additional attributes, so dm_document as of Documentum 6.5 has 86 attributes adding additional 50 attributes that means we have 139 attributes for this object type. Consider a standard Web Application using DFS behind which needs to manipulate (add or edit) instances of this object type, The Service needs to add all these attributes to the PropertySet  of the DataObject representing that instance. Then need to call the appropriate service.

 

Considering that the bean instance name of MyObjectType is myObjectBean the Standard code will  be something like this

  ObjectIdentity objIdentity = new ObjectIdentity("myRepository");
  DataObject dataObject = new DataObject(objIdentity, "dm_document");
  PropertySet properties = dataObject.getProperties();
  properties.set("object_name", myObjectBean.getObject_Name());
  properties.set("title", myObjectBean.getTitle()); 
  // omited for simplicity


  objectService.create(new DataPackage(dataObject), operationOptions);

 

In the above code you have to explicitly set individual attributes for the object, the more the number of attributes the more complex and messy code.

Take another Example, where you have to retrieve an Object information and pass it over to the UI layer.

 myObjectBean.setObject_name(properties.get("object_name").getValueAsString());
 myObjectBean.setTitle(properties.get("title").getValueAsString());
 myObjectBean.setMy_Custom_Property(properties.get("my_custom_property").getValueAsString());

This operation can be more complex if you decide to use match the Data Type of your bean with the Object type.

 

So what is the best approach to reducing this complexity? the answer is the effective use of reflection API.

Let’s take a step to step approach to handle this issue.

To understand this better consider the below as the attributes of mycustomobjecttype

 

Attribute Name Attribute Type
first_name String
last_name String
age integer
date_purchased time
amount_due double
local_buyer boolean

 

Java Bean

Create a Java Bean that matches the Object Type

 public class Mycustomobjecttype {
  protected String first_name ;
  protected String last_name  ;
  protected int age;
  protected Date date_purchased  ;
  protected double amount_due  ;
  protected boolean local_buyer ;
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  public double getAmount_due() {
    return amount_due;
  }
  public void setAmount_due(double amount_due) {
    this.amount_due = amount_due;
  }
  public Date getDate_purchased() {
    return date_purchased;
  }
  public void setDate_purchased(Date date_purchased) {
    this.date_purchased = date_purchased;
  }
  public String getFirst_name() {
    return first_name;
  }
  public void setFirst_name(String first_name) {
    this.first_name = first_name;
  }
  public String getLast_name() {
    return last_name;
  }
  public void setLast_name(String last_name) {
    this.last_name = last_name;
  }
  public boolean isLocal_buyer() {
    return local_buyer;
  }
  public void setLocal_buyer(boolean local_buyer) {
    this.local_buyer = local_buyer;
  }
}

Getting the Values from PropertySet (Loading Java Bean)

……

List<DataObject> dataObjectList = dataPackage.getDataObjects();
DataObject dObject = dataObjectList.get(0);
Mycustomobjecttype myCustomObject = new Mycustomobjecttype();
populateBeanFromPropertySet(dObject.getProperties(),myCustomObject);

……

// See the Reflection in Action here 
public void populateBeanFromPropertySet(PropertySet propertySet, Object bean)
  throws Exception {
 BeanInfo beaninformation;
 beaninformation = Introspector.getBeanInfo(bean.getClass());
 PropertyDescriptor[] sourceDescriptors = beaninformation.getPropertyDescriptors();
 for (PropertyDescriptor descriptor : sourceDescriptors) {
     Object result = null;
     String name = descriptor.getName();
    if (!name.equals("class")) {
      if (propertySet.get(name) != null) {
        if (descriptor.getPropertyType().getName().equals("int")) {
          result = new Integer(propertySet.get(name)
              .getValueAsString());
        } else if (descriptor.getPropertyType().getName().equals("double")) {
          result = new Double(propertySet.get(name).getValueAsString());
         } else if (descriptor.getPropertyType().getName().equals("boolean")) {
          result = new Boolean(propertySet.get(name).getValueAsString());
         } else if (descriptor.getPropertyType().getName().equals("java.util.Date")) {
          DateProperty dat = (DateProperty)propertySet.get(name);
          result = dat.getValue();
        }else {
          // none of the other possible types, so assume it as String
          result = propertySet.get(name).getValueAsString();
        }
        if (result != null)
          descriptor.getWriteMethod().invoke(bean, result);
      }
     }
  }
}

Setting Values to Property Set

 

public DataPackage createContentLessObject(Mycustomobjecttype myCustomType) throws Exception {
ObjectIdentity objectIdentity = new ObjectIdentity("testRepositoryName");
DataObject dataObject = new DataObject(objectIdentity, myCustomType.getClass().getName());
PropertySet properties = populateProperties(myCustomType);
properties.set("object_name",myCustomType.getFirst_name()+myCustomType.getLast_name() );
dataObject.setProperties(properties);
DataPackage dataPackage = new DataPackage(dataObject);
OperationOptions operationOptions = new OperationOptions();
return objectService.create(dataPackage, operationOptions);
}

 

// Reflection in Action  
public PropertySet populateProperties(Object bean)throws Exception {
BeanInfo beaninfo;
PropertySet myPropertyset = new PropertySet();
beaninfo = Introspector.getBeanInfo(bean.getClass());  
PropertyDescriptor[] sourceDescriptors = beaninfo
      .getPropertyDescriptors();
  for (PropertyDescriptor descriptor : sourceDescriptors) {
    String propertyName = descriptor.getName();
    if (!propertyName.equals("class")) {
        // dont set read only attributes if any
       // example r_object_id 
       if (!propertyName.startsWith("r")) {
        Object value = descriptor.getReadMethod().invoke(bean);
       if (value != null) {
          myPropertyset.set(propertyName, value);
        }
      }
   }
 }
  return myPropertyset;
}

Non Qualifiable properties and Property Bag in Documentum Objects


Before getting into details of Property Bags lets quickly see what are Qualifiable and Non-Qualifiable properties?

 

Qualifiable Properties

Most of the Object attributes are Qualifiable properties. The properties are qualifiable if it is saved (persisted) in a column of that Objects underlying tables (_r or _s table) in the Database. Attributes are Qualifiable by default.  I am not getting into much detail of Qualifiable properties here. See the following link for more on this

 

Object Attribute :- Repeated and Single Value Attributes in Database

 

Non – Qualifiable Properties

These Attributes of objects does not have column of its own in the Object’s underlying _r or s tables. They are saved in the serialized format in the i_property_bag property of the underlying object. See the below noted bullet points that reveal some interesting facts about Non – Qualifiable attributes.

 

·         Though these properties can be returned using a DQL Query, this cannot be used in the Qualifying clause [in Where Clause of the Query]. The Exception to this rule is that Non-Qualifiable properties can be used in the where clause of FTQL queries

·         These properties can be full text indexed.

·         IF the Non-Qualifiable properties are part of the select part of the Query, the query should have r_object_id in the select list.

·         If a property is Non-Qualifiable and it is of type String the length of that attribute must be less than the value of max_nqa_string key in the server.ini (Only if this key has a value set in server.ini) (The default value is 2000)

 

 

Lets See Few Related DQL’s

 

The following DQL creates an object type mycustomtype with first name a Qualifiable Attribute and country a Single Non-Qualifiable attribute and phone a Non Qualifiable Repating attribute.

 

CREATE TYPE “mycustomtype” (“firstname” string(64), country string(64) NOT QUALIFIABLE, phone string(10) REPEATING NOT QUALIFIABLE ) WITH SUPERTYPE “dm_document”

 

The following Query will create an object of type mycustomtype (You may notice that there is no difference in the create Query when compared with Qualifiable Properties

 

CREATE mycustomype OBJECT SET “firstname” = ‘Hello World’, SET “country”= ‘US’, SET phone [0]= ‘1111111111’

 

The following Query will return the Attributes from mycustomtype.
Note:
Make sure that you have r_object_id in the select query if you have non-Qualifiable attributes otherwise you will get following error
DM_QUERY2_E_MISSING_OBJECTID_IN_SELECT_LIST

 

Select r_object_id, firstname, country from mycustomype;

 

What is Property Bag

Property bag is a relatively new term in Documentum. This is a property, which is used to store other properties and values of an Object.  Non Qualifiable properties and its values of an Object is stored in its property bag (both Single and Repeated)

Other than Non-Qualifiable properties Property bag can also hold Properties and values of Aspect if the aspect properties are enabled with OPTIMIZEFETCH.

 

i_property_bag and r_property_bag

 

The i_property_bag property is defined in dm_sysobject , This Attribute is of datatype String and  can hold up to 2000 characters. This makes sure that all the object types that are inheriting from dm_sysobject have the ability to have its own property bag.

 

In the scenarios where you don’t have a Parent type defined in the Object definition and you create a non-Qualifiable attribute this property is automatically added to the object type.

 

If you add property bag to an object type it can never be removed from that object type.

 

The r_property_bag is silently added to the Object’s type definition when we add i_property_bag. This repeating attribute property is used to store the overflow from the i_property_bag. That means if the names and values of properties stored in i_property_bag exceed 2000 chars, the overflow is stored in r_property_bag. This is repeating string property with 2000 characters.

 

Download This Study Note (PDF)

 

Documentum Composer A boon for the Developers !!!!


 Documentum Composer Screenshot

After a long wait Documentum Composer is out. And its time to say goodbye to Application builder, Application Installer I was really excited to see the composer and believe me it was really user friendly, As expected I could see few errors happening in Error log of the Composer but its working fine. Anyways it looks like a good start. Once you download the Composer and unzip it, make sure that you go to <DocumentumComposer>\plugins\com.emc.ide.external.dfc_1.0.0\documentum.config\dfc.properties add your connection broker information to it.  
I created a Aspect using it and deployed it to the Server, The UI of Composer looks pretty much intuitive and easy to use.  I am adding a screenshot of the Composer for people who where waiting to see it. I will be adding more about my composer Experience soon

Installation Issues of Documentum 6 SP1 Content Server on AIX


We had done a D6 SP1 installation few days ago and ran into some issues, I thought I will share my expereince with you all so that you know the issues that you may face during the installation of content server on AIX.

 As we stared with the installation of Content Server on our AIX system (5.3) we were hit with the following error

“The /tmp filesystem needs 1GB where it has 0 GB Available”  We had more than 1 GB space in both /var/tmp and /tmp.

During this I found an interesting thing that even the D6 Installer guide has lots of typos in it. It says /tmp some place then someother place it says /temp should have 1 GB  free space !!!!

If you are hit with this issue there is a work around,  You have to add the tmp directory location as parameter to the installer.  

That means you have to run the installer with following command line

serverAixSuiteSetup.bin -is:tempdir TMP_DIR

Where TMP_DIR should point your tmp directory which has more than 1 GB Space.

Another interesting issue is Though the D6 Installer guide in page number 143 says that if you run dm_launch_server_config_program.sh it will set the environment variables such as LIBPATH etc that doesnt really do that. So if you are installing D6 CS on AIX after completing the installtion make sure sure that you edit the profile of install owner and add these paths to it

Happy Installing !!!

Aspects the new BOF type in Documentum


Aspects

Aspects, the new member in the BOF family is one among the new additions to the Documentum 6 (D6).  This short notes are just to give you insight to the fundamentals of Aspects.

What is Aspects?

In simple words Aspects are like TBO’s but they are not associated with any object types.  That means you can attach or detach an Aspect at runtime to any object type. In other words Aspects are a mechanism for adding behavior and/or attributes to a Documentum object instance without changing its type definition (From DFC Study Guide)

Aspects like any other BOF types are stored in the repository. When a DFC runtime requests for a Aspect it will be downloaded to that system and used. Aspect belongs to the type dmc_aspect_type.

 Aspects are saved in /System/Modules/Aspect in the repository which has a global registry. If any changes are made to any aspects DFC runtime detects that and downloads the latest version to its local cache of BOF.  

What Aspects can do?

Aspects are different from other BOF’s because it is attached to the Object instance, not to the object types.  They are not a per-application customization. Any Persistent object instance can have multiple aspects attached to it if each aspect has a unique name.

Aspects define custom additional fields and it can set custom values to the fields of any object that of type persistent object. There are no restrictions for the type of and number of attributes that you can create on an aspect.  It can be of any supported types and be either a single value or a repeated value attributes.

Another aspect can access the Attributes defined in one Aspect. The Fully qualified aspects attributes are aspect_name.aspect_value. When you fetch an Object all values of attributes of attached aspects are also fetched.  If you destroy an object it also deletes the attributes in the attached aspect.

Where Can I use it?

Aspects are used when you have a cross type functionality to be defined. When you create a application infrastructure or a corporate platform Aspects are the best way to implement business functionality which is common between different object types. When you have some functionality that is per instance based then also Aspects is the solution.

Lets see a real time scenario where you can use Aspect.

Lets imagine a scenario where you have system, which has user base of different countries, depending upon the country where a user belongs the behavior and fields of the application changes. You can create different aspect, which has the country specific behaviors and fields, and attach it as needed. If the user changes from one country to another simply remove the old country aspect and attach the new country aspect.

 To be Continued ….

DFS Data Model Explained


Hi All 

As I am exploring the new DFS  I am noting some points that I can share with you guys. I know I cannot explain everything about DFS here As like you I am also learing but I will try to give an overall  picture of What DFS is all about here. Please visit this blog often as I keep updating this.

 

DFS Explained

Documentum Foundation Services the SOA face of Documentum. The remote invocation of DFS is implemented using SOAP based web-services. The beauty of DFS is that though DFS is exposed for the remote usages as Web Services it can be called locally using DFS Client libraries. DFS allows the migration easy by allowing services to be developed on existing BOF (Documentum Business Object Framework) also.Another interesting point about this is DFS consolidates the numerous inter depended methods into a Single Service. The DFS data model is expressed in both Java client library class and also in Service XML Schemas. This provides a consistent approach to model data that will be exchanged between the various business processes.  As mentioned above the DFS clients can be of two types.

  • Applications (Consumers) written any language that can use WSDL to interact with DFS.
  • Clients written on java that uses DFS Java Client library

 Data Model of DFS  The data passed to and from the Services are encapsulated into DFS Object Model  These are the few important object types on DFS

  • DataPackage
  • DataObject
  • ObjectIdentity
  • Property
  • Content
  • Permissions
  • Relationship

 Lets see what all these does now 

DataPackage 

According to the DFS Reference Guide from EMC The DataPackage class defines the fundamental unit of information that contains data passed to and returned by services operating in the DFS framework.  That means DataPackage is a collection of DataObject Instances, which is passed back and forth by Object Service Operations. In other words when you call services like Create, Get, Update the Data Object Instances are passed using DataPackage class.

It’s like an Envelope for putting various DataObject Instances. Object service operations process all the DataObject instances in the DataPackage sequentially.

 

DataObject

A DataObject is the DFS representation of a Persistent Object in Documentum Repository. DataObject potentially has all the information related to an Object in repository. This includes the Content, properties (Both Single and Repeated), relation with other Objects in repository, Its permissions etc. Due the nature of these objects, Data Objects are very complex.
Optionally these object instances may have instructions to services about how the parts of Objects have to be processed.
The type field of DataObject class represents the underlying typed object type name that corresponds to the Object Instance. For example dm_user, dm_document etc. default type is dm_document. I.e. if no type is specified then service implicitly assign that to type dm_document   

 

DataObject

ProperySet
Content
ObjectIdentity
Permission
Relationship

 The above Figure represents a DataObject.

ObjectIdentity

 As the name says this represents a Unique Object in the Repository. An instance of this class must have the repository name and a unique identifier for that object.  The value that represents a repository object may be any of the following  

  • OBJECT_ID – Contains r_object_id of the Object (Represents both Current Object and Non Current Object)
  • OBJECT_PATH – Contains String expression of the path of the Object in repository
    [Cabinet]/[Folder]/[File_Name]
    (This Represents only Current Object. Since you can create multiple objects with same name in same directory this does not guarantee uniqueness of the object)
  • QUALIFICATION – DQL Snippet that qualify an Object uniquely
    (The DQL Snippet is the Full DQL that follows the keyword FROM. E.G. dm_document where r_object_id=’09xxxxx’)

 Note: During the Creation of the object all you need to populate is only repository name.  

Property

Each Property represents an Object Attribute (Property) in the Documentum Repository. Property Set is a collection, which works as a container of multiple Property Objects

As there are 2 types of Properties for an Object a property can either be a Single property (Single Value Attribute) or Array Property (Repeated Attributes).  Property class has been sub classed to accommodate various data types and they are as follows.  

StringProperty

 
NumberProperty  
BooleanProperty  
DateProperty  
ObjectIdProperty  
ArrayProperty (Abstract Class) ®
  StringArrayProperty
  NumberArrayProperty
  BooleanArrayProperty
  DateArrayProperty
  ObjectIdArrayProperty
Transient Property

These properties are not the part of persistent properties of a repository object. Transient Property can send custom data fields to a service to be used for a purpose other than setting attributes on repository objects.

 

Array Property and Value Action

The Repeating Attributes of an Object type is represented as Array Properties. As you can see in the above table The ArrayProperty is an array of the corresponding single property.  Another Interesting aspect of Array Property is Value Action. Now lets see what value action is all about? This is an optional Action – Index mapping pair. These pair has the instruction as to what is the action to be done on a particular element of the ArrayProperty. The Index is the position in the attribute and Action is what is the action to be performed on that element of that index.  The possible ActionTypeValues are  

  • Append
    When processing ValueAction[p], the value at ArrayProperty[p] is appended to the end of repeating properties list of the persistent repository object. The index of the ValueAction item is ignored.
  • Insert
    When processing ValueAction[p], the value at ArrayProperty[p] is inserted into the repeating attribute list before position index. Note that 1, which must be accounted for in subsequent processing, offsets all items in the list to the right of the insertion point.
  • Delete
    The item at position index of the repeating attribute is deleted. When processing ValueAction[p] the value at ArrayProperty[p] must be set to a empty value.
  • Set
    When processing ValueAction[p], the value at ArrayProperty[p] replaces the value in the repeating attribute list at position index. (From DFS Development Guide)

 

Content

 Content Class or its Subclass instance represents the actual File Content associated with a DataObject.  DataObject can have zero or more Content objects. It can hold Renditions also.   Content class object can be configured to hold following

  • The Whole Document

  • Page of a Document

  • Pages (One or More) which has been represented by the characteristic

 

 

Permissions

 A DataObject has list of Permission Objects, which decides the permission of the object that’s represented by the DataObject. The permission list provides read access to the permission on an object in repository by the user who has been logged in currently. 

Also have to note an interesting point here that You Cannot change permissions on a repository object by changing the Permission list and saving the DataObject.

For changing permissions of a repository object the real ACL of that object has to be edited or replaced.   As mentioned above multiple Permission Objects creates Permission List. The Permission Object has a field named permission Type that sets what type of permission is set. The values possible for these fields are BASIC, EXTENDED or CUSTOM   Another important thing about permissions are if you assign one particular permission for one user to one object, all the lower lever permissions below the assigned permissions will be granted to that user. This is known as Compound or Hierarchical Permissions  PermissionType Enum Constants (From DFS Guide) 

PermissionType

Permission Description
Basic NONE No access is permitted
  BROWSE The user can view attribute values of content
  READ The user can read content but not update.
  RELATE The user can attach an annotation to object.
  VERSION The user can version the object.
  WRITE The user can write and update the object.
  DELETE The user can delete the object.
Extended X_CHANGE_LOCATION The user can change move an object from one folder to another. All users having at least Browse permission on an object are granted Change Location permission by default for that object.
  X_CHANGE_OWNER The user can change the owner of the object
  X_CHANGE_PERMIT The user can change the basic permissions on the object.
  X_CHANGE_STATE The user can change the document lifecycle state of the object.
  X_DELETE_OBJECT The user can delete the object. The delete object extended permission is not equivalent to the base Delete permission. Delete Object extended permission does not grant Browse, Read, Relate, Version, or Write permission
  X_EXECUTE_PROC The user can run the external procedure associated with the object. All users having at least Browse permission on an object are granted Execute Procedure permission by default for that object.

 

 

Relations

Relationship allows creating a Single DataObject that specifies all the relations that it has with other objects existing and new. This also allows single service call to get, update or create the whole set of objects and its relationships.  Relationship has two subclasses             
Object Relationship  
           &           
Reference Relationship
These classes define all the relationships that a (any) object in repository can have.  This represents existing relations, also can add new relations, which can be updated in the repository using service calls.  

According to DFS Developer guide The repository defines object relationships using different constructs, including generic relationship types represented by hardcoded strings (folder and virtual_document); dm_relation objects, which contain references to dm_relation_type objects; and dmc_relationship_def objects, a representation provides more sophistication in Documentum 6. The DFS Relationship object provides an abstraction for dealing with various metadata representations in a uniform manner 

 

ObjectRelationship

ObjectRelationship represents relationship to a new or existing repository object. It can be used by the update operation to either update or create Content objects. This when called with update operation modify/ create the target objects 

ReferenceRelationship

A ReferenceRelationship represents a relationship to an existing repository object and is specified using an ObjectIdentity. This object can (only) be used to create a relationship between two objects. This will not create or update the target objects.

 

 

Download this study note (PDF)