Ajith Prabhakar’s Weblog

A beginner’s guide to Documentum

Posts Tagged ‘Ajiths Notes’

Service Based Objects (SBO’s) in Documentum

Posted by Ajith Prabhakar on July 20, 2009


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 important member of Documentum BOF family.  Lets try to see what makes Service Based Objects very popular and how can you implement it.

What is a SBO

In simple terms SBO in Documentum can be compared to session beans of 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 biggest advantage of a BOF that its deployed in a central repository. The repository maintains this module and DFC ensures that he 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 a LDAP server. Prior to 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 different study note)

A very simple to understand example for a 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 a 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 a individual SBO

How to implement a SBO using Composer

The steps to create a SBO are these.

1) Create a 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 a SBO Module and Deploy your Documentum Archive using Documentum Composer (Application builder for older versions)

Lets 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 about 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 a interface which will define the business functionality. This interface should extend IDfService interface. 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 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

Lets 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 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 a SBO. System will throw an Exception when a session based transaction used within a 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 independed do not hard code the repository names in the methods. Either pass the repository name as 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 a operation.

Now lets 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 Overriden 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 are 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 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 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 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 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 a SBO from a client application.

1) Get the Local client

2) Create a login info and populate the login credentials.

3) Create a IDfSessionManager object

4) Use the newService () from the Client Object to create a 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)

Posted in BOF, DFC, Documentum | Tagged: , , , , , , , , , , , , , , , , , , , , | Leave a Comment »

Using Java reflection to reduce Code and Development time in DFS

Posted by Ajith Prabhakar on March 11, 2009


Java reflections is 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 uses Value objects to transfer data from one layer to another. 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 lets take a Scenario,  I have a 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());

………

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 reduce this complexity? the answer is effective use of reflection API.

Lets 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;
}

Posted in DFS, Documentum | Tagged: , , , , , , , , , , , , , , , , | 1 Comment »

Chaining of Custom Services in DFS

Posted by Ajith Prabhakar on January 25, 2009


 

There is an interesting drawback in Documentum Foundation Services Version 6.5,

Issue:

When you chain custom services and try to build the Services the build fails lets see a Scenario from the DFS sample code itself

@DfsPojoService(targetNamespace = http://common.samples.services.emc.com&#8221;, requiresAuthentication = true

) public class HelloWorldService

{

public String sayHello(String name)

{

ServiceFactory serviceFactory = ServiceFactory.getInstance();

IServiceContext context = ContextFactory.getInstance().getContext();

try {

IAcmeCustomService secondService = serviceFactory.getService(IAcmeCustomService.class, context);

secondService.testExceptionHandling();

} catch (ServiceInvocationException e) {

e.printStackTrace();

} catch (CustomException e) {

e.printStackTrace();

} catch (ServiceException e) {

e.printStackTrace();

}

return “Hello “ + name;

}

}

Here in the sample code of DFS I am chaining the services, Here everything looks fine and when you now you build this service during the genarateArtifacts ant task the Build will fail with a will get a ClassNotFound compiler error at

IAcmeCustomService secondService = serviceFactory.getService(IAcmeCustomService.class, context);

What happens here is when the build does the initial clean up all the generated Client interfaces are deleted and DFS currently not checking for any dependencies.

Let me take the example of dfs-build.xml that’s the part of CoreDocumentumProject in composer

<generateArtifacts serviceModel=“${gen.src.dir}/${context.root}-${module.name}-service-model.xml” destdir=“${gen.src.dir}/”>

<src location=“${src.dir}” />

<classpath>

<path refid=“projectclasspath.path” />

</classpath>

</generateArtifacts>

</target>

 

In this we cannot set any exclusion path in <src location=“${src.dir}” />

Simply because it even if you provide <fileset/> or <direst/> with pattern set its not recognizing it.

I had raised a support case with EMC and they told me that this is not currently supported!!!! And they will add this as a feature request

This means we cannot Chain Custom Services unless EMC fix this or we do a semi manual workaround to overcome this issue.

The Work-around that I found

Follow these steps to overcome this issue

Step 1,

Identify the Services those will call the custom services, and create a new source directory for it in composer, here I am calling them as depended_src and move the services that calls the custom services to there, the depended src should be in a separate path than the webservices- src

src-img1

Step 2

1) Now Edit the Build file and add these two properties

 

<property name=“my.core.services.classes” value=“${service.projectdir}/Web Services/bin/classes” />

 

<property name=“dep.src.dir” value=“${service.projectdir}/depended_src” />

The dep.src.dir should point to the depended src location mentioned in step 1

2) Create an additional target for generatemodel and generate artifacts

<target name=“generateDependencies” depends=“generate”>

<echo message=“Calling generateDependencies” />

<generateModel contextRoot=“${context.root}” moduleName=“${module.name}” destdir=“${gen.src.dir}/”>

<services>

<fileset dir=“${dep.src.dir}”>

<include name=“**/*.java” />

</fileset>

</services>

<classpath>

<pathelement location=“${my.core.services.classes}” />

<path refid=“projectclasspath.path” />

</classpath>

</generateModel>

<generateArtifacts serviceModel=“${gen.src.dir}/${context.root}-${module.name}-service-model.xml” destdir=“${gen.src.dir}/”>

<src location=“${dep.src.dir}” />

<classpath>

<pathelement location=“${my.core.services.classes}”/>

<path refid=“projectclasspath.path” />

</classpath>

</generateArtifacts>

<!– signal build is done –>

<!– used by DFSBuilder.java –>

<copy todir=“${src.dir}/../” file=“${basedir}/dfs-builddone.flag” />

</target>

3) Now edit dfs-build.properteis and add the following property

service.projectdir= <absolute path to the project>

Step 3

1) Run the generate task,

2) Copy all the service entries from (between <module> and </module><context-root>-<module-name>-service-model.xml you can find this in <project_dir>\Web Services\bin\gen-src folder

3) Now run the generateDependencies task that was created on Step 2

4) Now Edit <context-root>-<module-name>-service-model.xml and add the copied services to this file

5) If you want to create the jar files now you can call the package task after this.

This should help you to chain custom services , and if you found any alternate ways please comment.

 

Posted in DFS, Documentum | Tagged: , , , , , , , , | Leave a Comment »

Federation in Documentum

Posted by Ajith Prabhakar on June 17, 2008


Federation is one among the most common distributed Documentum model. This means multiple Documentum repositories run as a federation. There will be a Governing repository and multiple member repositories in this model. Lets try to find out more about Federation

 

Take this typical scenario A Major Pharmaceutical Company ABC Corporation has multiple research centers and production plants across the glob and they have multiple Documentum repositories used for storing various information. A user logged into a corporate application needs to fetch documents from these various repositories in a Single session. Each repository in this scenario should have same set of users, groups and ACL for this architecture to work, manually managing these kind of scenario is trouble some and error prone.

 

Now lets see what a federation can do to make it less complex.

As I mentioned above Federations consists of Governing and Member repositories all the changes that has been made to global users and groups and external ACLS in the governing repository are automatically reproduced in the member Repository.

 

Requirements for Federation

·         Object types definition should be same in the all participating repositories.

·         User and group definition should be same in all participating repositories.

·         The server on which governing repository runs must project to the connection brokers at the servers where member repository runs

·         The server on which member repositories runs must project to the connection brokers at the servers where governing repository runs

·         If any of the participating Content Servers are with trusted server licenses Either
The servers should be configured to listen on both secure and native port or
The secure connection default for clients allows the clients to request a connection on a native or secure port

 

Few Bullet points about Federation

·         Any alteration done to any of the object type will not be automatically pushed to the participating repositories

·         Only users or groups marked as Global while creating them will be pushed / synchronized with participating repositories

·         The users those are part of any object types that are extended from dm_user will not automatically pushed. This will happen only if you specify this type in the Federation configuration.

·         Each repositories can be part of a single federation

·         A federation may contain different Content Server versions

·         A federation may contain a mix of trusted and non-trusted Content Servers.

 

 Download this Study Note (PDF)

Posted in Content Server, Documentum, Genaral | Tagged: , , , , , , , , , , , , , | 1 Comment »

Non Qualifiable properties and Property Bag in Documentum Objects

Posted by Ajith Prabhakar on April 11, 2008


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)

 

Posted in Content Server, Documentum, Genaral | Tagged: , , , , , , , , , , , , , , , , , | 1 Comment »

Object Types involved in WorkFlow

Posted by Ajith Prabhakar on March 26, 2008


Below is the table with different object types that has some role in workflow (5.3) with its description from Documentum Object Reference Manual

Object Type

Short Description

Detailed Information

dm_workflow

Contains the runtime information about a workflow.

A workflow object contains the runtime information about a workflow.

dm_activity

An activity object defines a workflow activity.

The attributes in an activity object define who performs the activity and the packages and work items generated from the activity.

dm_process

A process object contains the definition of a workflow process.

A process object is created when a user creates a workflow definition in either Workflow Manager or Business Process Manager. There are three inherited attributes that are reserved for internal use for process objects: a_special_app, a_status, and a_application_type.

dmi_workitem

Stores information about a task for a human or automatic performer.

Work items are generated by Content Server from an activity object. Users cannot create work items. Users can modify only the following attributes: a_held_by, a_wq_doc_profile, a_wq_flag, a_wq_name, and a_wq_policy_id.

dmc_workqueue

Represents a work queue for work items generated from a workflow

A work queue object represents a work queue for workflow tasks. The workqueue object type is installed by a script when Content Server is installed. However, work queues (instances of the type) are created and managed using Webtop.

dmc_workqueue_category

Defines a category for a work queue.

A work queue category object represents a category of work queues. The object type has no attributes defined for it. It inherits all its attributes from its supertype, dm_folder. It uses only the object_name, acl_name, and acl_domain attributes. The object_name attribute stores the work queue category name

dmc_workqueue_policy

Defines configuration information for a work queue.

A work queue policy object defines configuration parameters for handling a task in a  workqueue. The parameters control how the items are handled. Each work queue has one associated work queue policy. If a document associated with a task has a defined work queue policy, that policy overrides the work queue’s policy.

dmi_wf_timer

Records the configuration of a timer for a workflow activity.

A wf timer object describes a timer for a workflow activity. The wf timer objects are created automatically when the timer is instantiated.

Download This Study Note (PDF)

Posted in Content Server, DFC, Documentum, Genaral | Tagged: , , , , , , , , , , , , | Leave a Comment »

Registered Tables in Documentum

Posted by Ajith Prabhakar on January 24, 2008


Registered tables are the tables that are present database which are registered in Documentum, so that it can be accessed using DQL. Basically Registered tables are used when the application needs to access data from the RDBMS within the Documentum. This can be either a Table or a View.  The Scenarios where I mostly used registered tables are for providing value assistance for Object attributes.  I am not getting into too much of details about Value Assistance here, Value assistance is a list of values that a client program (such as Webtop or a Custom WDK Application) displays at runtime for an object attribute. A user can select a value from this list (or, if allowed, add a new one to it). You can set the Value assistance for an Attribute using DAB (Documentum Application Builder).

As I mentioned above uou can register a Table or a view as a Registered Table, The Registered tables are stored as dm_registered objects in repositories. This extends dm_sysobject. And the r_object_id of this type always starts with 19. The following table lists the attributes of dm_registered

Name Info Description
column_count Integer  – Single Number of columns in the table.
column_datatype string(64) – Repeating List of the datatypes of the columns.
column_length. integer R Lengths of the columns that have a string data type
column_name. string(64) – Repeating List of the names of the columns in the table
group_table_permit integer  – Single Defines the RDBMS table permit level assigned to the registered table’s group.
is_key. Boolean Repeating Indicates if an index is built on the column
owner_table_permit integer  – Single Defines the RDBMS table permit level assigned to the registered table’s owner
synonym_for string(254) – Repeating Name of the table in the underlying RDBMS (can be an Oracle table synonym, or an MS SQL Server or Sybase table alias)
table_name string(64) Single Name of the table.
table_owner string(64) Single Name of the owner of the RDBMS table (the person who created the RDBMS table).
world_table_permit integer  – Single Defines the RDBMS table permit level assigned to the world

You should either own the table or have super user privileges to register a table. And since this object is linked with /system cabinet you should have write permission on /system cabinet. This is applicable only if the folder security is enabled in Repository

You cannot version a dm_registered object. And also the changes made to the table are not automatically updated in dm_registered object.  So if any changes has been made to the structure of the table or view you should unregister it first and register the table again with changes.

How to Register a Table?

Use the following DQL to register a table. REGISTER TABLE [owner_name.]table_name (column_def {,column_def}) [[WITH] KEY (column_list)][SYNONYM [FOR] ‘table_identification‘] This DQL will return the r_object_id of the newly created dm_registered object. In this owner_name is the name of the table owner. table_name is the name of the RDBMS table. column_def defines the columns in the registered table.

column_def arguments should have following syntax column_name datatype [(length)] the valid values for types are float, double, integer, int, char, character, string, date, time.

Length should be specified for character, char, or string data type.

column_list Identifies the columns in the table on which indexes have been built. column_list is usually separated with commas. table_ identification is the name of the table in the Database Example:

REGISTER TABLE “hr.users” (first_name CHAR(30), last_name (char 40), emp_id INT)KEY (“emp_id”)

Granting Rights

You need to give the permission to the users to access the registered tables.  The values for various permission levels are as follows 0 (None): No access 1 (Select): The user can retrieve data from the registered table 2 (Update): The user can update existing data in the registered table4 (Insert): The user can insert new data into the registered table8 (Delete): The user can delete rows from the registered table If a user wants update and insert permissions the value should be 2+4 = 6 , The repository owner also should have the same level of permission in the underlying database to grand those permission to those users. Granting Rights full permission to users in the above example

update dm_registered object set world_table_permit = 15 where object_name = ‘users’;

update dm_registered object set owner_table_permit = 15 where object_name =  ‘users’;

update dm_registered object set group_table_permit = 15 where object_name = ‘users’;

How to Unregister a Table?

Use the following DQL to Unregister a Table.

UNREGISTER [TABLE] [owner_name.]table_name In this owner_name is the name of the table owner. table_name is the name of the RDBMS table. You should be the owner of table or super user to do this

Accessing Data from Registered Table

Just like in RDBMS you can access registered table using the following syntax

Select [ATTRIBUTES] from dm_dbo.[REGISTERED_TABLE_NAME] where [CLAUSE]

The Operations such as update/ delete also has the same RDBMS syntax that’s used for a ordinary SQL, Only difference is prefixing dm_dbo to the table name

Example:
Select first_name, last_name, emp_id from dm_dbo.users ;

Updating Data in a Registered Table

Example
Update dm_dbo.users set first_name=’John’ where first_name=’Smith’

Deleting from a Registered Table

Example

Delete from dm_dbo.users  where first_name=’Smith’

Download this note on Registered Table (PDF)

Posted in Content Server, Documentum | Tagged: , , , , , , , , , | Leave a Comment »

Aspects the new BOF type in Documentum

Posted by Ajith Prabhakar on January 18, 2008


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 ….

Posted in BOF, DFC, Documentum | Tagged: , , , , , , , , , , , , , , , , | 2 Comments »