Thursday, December 13, 2012

How to create and deploy a TBO

BOF (Business Object Framework) provides an easy way of implementing custom business logic. The advantage of using BOFs over application customization is the custom business logic is always executed, regardless of the client program using Documentum (repository).
The first version of BOF, 1.0 kept all of the TBO information outside the repository: BOF registry (list of BOF modules) was kept in a file dbor.properties, and the implementation jars had to be deployed in the classpath of the client (libraries folder). The big lack of this approach is that each client has to be configured in order to use properly the BOFs.
The new version - 2.0 eliminated this lack by using a different approach: BOF registry, the modules and their implementation is stored in the repository, so there's no need to configure the clients, all of them will benefit of BOF functionality deployed in the repository.
There are 3 types of BOF modules: TBO (Typed-based Business Objects), SBO (Service-based Business Objects) and Aspects. TBOs are the most used and serve for modifying and extending the behavior of persistent repository object (custom) types.

In this article I'll focus on creating and deploying a TBO. The steps to follow are:
1. Create a custom type
2. Write TBO source code
3. Create Jar Definition artifacts
4. Create Java Library artifacts (optional)
5. Create Module artifact
6. Deploy the TBO

1. Create a custom type
The very first thing is to have a custom type which your TBO will map to. You can't map a TBO to a standard Documentum type. Your custom type must extend a persistent type (ie: dm_document, dm_folder, dm_user, etc.).

2. Write TBO source code
The first step is to write the Java code of the TBO, the operations that will be executed when the object of the mapped type is changed. Using Eclipse create a new Java Project, add the DFC libraries (and other required libraries) in the build path.
The code and classes structure depends on complexity, but for the TBO you need at least an Interface and an Implementation class, preferably in different packages. I will list here some trivial samples:

a) Interface IAttach:
package com.company.project.attach.tbo;

import com.documentum.fc.client.IDfBusinessObject;
import com.documentum.fc.client.IDfDocument;
import com.documentum.fc.common.DfException;
import com.documentum.fc.common.IDfDynamicInheritance;

public interface IAttach extends IDfBusinessObject, IDfDocument, IDfDynamicInheritance {
public void setDoctype(String doctype) throws DfException;
public String getDoctype() throws DfException;
}

The interface should extend 3 other interfaces:
- IDfBusinessObject - required for modules management
- IDfPersistentObject (usualy IDfDocument) methods defined for the base type you're extending: if your type is a subtype of dm_document, use IDfDocument, for dm_folder - IDfFolder, etc.
- IDfDynamicInheritance - enable some advanced module handling

As you can see the interface declares only 2 custom methods: setDoctype and getDoctype that set and get values for the custom attribute "prj_doctype".
Compile the interface and add pack it into a jar (attach.jar).

b) Implementation class Attach:
package com.company.project.attach.tbo.impl;

import com.company.project.attach.tbo.IAttach;
import com.documentum.fc.client.DfDocument;
import com.documentum.fc.common.DfException;
import com.documentum.fc.common.DfLogger;

public class Attach extends DfDocument implements IAttach {
public void doSave(boolean saveLock, String versionLabel, Object[] extendedArgs) throws DfException {
DfLogger.info(this, "doSave called for object with id: {0}", new String [] {getObjectId().toString()}, null);
setTitle(this.getDoctype());
super.doSave(saveLock, versionLabel, extendedArgs);
}

public void setDoctype(String doctype) throws DfException {
setString("prj_doctype", doctype);
}

public String getDoctype() throws DfException {
return getString("prj_doctype");
}
@Override
public String getVendorString() {
return "Copyright Documentum Guy";
}
@Override
public String getVersion() {
return "1.0";
}
@Override
public boolean isCompatible(String version) {
return getVersion().equals(version);
}
@Override
public boolean supportsFeature(String arg0) {
return false;
}
}

The implementation class contains the implementation for the 2 custom methods, for doSave - overriding method from DfPersistentObject (method called when an object of this type is saved), and also implementation for other 4 methods declared in IDfBusinessObject interface.
According to best practices you should override only methods beginning with do (doSave, doCheckin, doCheckout, etc.), not save, checkin, etc. Usualy you need to add some functionality and not change the default one, so remember to call also the superclass method: super.[Overriden_Method].
Compile the implementation class(es) and pack it into a jar (attach-impl.jar): ensure that interface and implementation are in different jars.

3. Create Jar Definition artifacts
In the past DAB (Documentum Application Builder) was used to manage Documentum artifacts, but it was replaced by Composer since version 6.5.
In composer create a new Documentum project and give it a relevant name. Then right click on the Artifacts folder of your project and choose New->Jar Definition (if you don't have it in the list, choose New->Other and choose Jar Definition under Documentum Artifact category). Type the name of the artifact exactly as the name of the jar file (it's not a restriction, but it's a good habit in order to avoid confusion).
You must create 2 jars: interface and implementation. So for this sample we create attach.jar with Type: Interface and attach-impl.jar with Type: Implementation.

4. Create Java Library artifacts (optional)
All the libraries used by your TBO code must be deployed in the repository and related to the TBO module. These jars are packed in artifacts called Java Libraries.
First you must create a Jar Definition per each required jar. Then right-click Artifacts folder and choose New->Java Library, enter a name, then in the JARs field add the jars you need (all jar artifacts from current project are available for selection).

5. Create Module artifact
Now we can proceed to create the TBO module. Right click the Artifacts folder, select New->Module and type the name of the custom type you want to assign the TBO (it won't work if the module name does not match the type name). In the Type combo choose TBO. Next to Implementation Jars field click Add and select the attach-impl.jar, for Interface Jars click Add and select attach.jar, for Class name click Select and choose the class: com.company.project.attach.tbo.impl.Attach (the list of available classes wil be loaded from the implementation jar you've selected). If your TBO implementation code uses some other modules (TBOs, SBOs, etc.) add them in the Required Modules field. In the bottom-left corner choose Deployment tab and add the required Java Libraries (libraries referenced by your TBO code).

6. Deploy the TBO
Ok, now all the artifacts required for the TBO are ready to be deployed into the repository. Build the composer project (if Build Automatically flag is not checked) by choosing Project->Clean from the menu bar. The output will be a DAR file located in bin-dar folder of the project. You can either install the project directly from Composer (right-click on the project and chooose Install Documentum Project) or using DarDeployer (previous name - DarInstaller).
Select the DAR file, repository, enter user name and password and click Install. After the DAR/project is installed, you can restart the JMS and Application Server (and any other client using this repository) and clean BOF cache to ensure that the last versions of jars will be downloaded from the repository.

That's all, now you can test your TBO (To find how to test your TBO changes without re-deploying, check this article: How to test BOF (TBO/SBO) code changes without re-deployment). It will be called when objects of the mapped type will be changed either by DFC code or DQL queries.
If you'll have these steps in front of you, the creation of TBOs will be pretty easy.