- 浏览: 52787 次
- 性别:
- 来自: 上海
文章分类
最新评论
http://www.bluefishgroup.com/library/2006/getting-started-with-dfc-and-dql/
Introduction
Before I joined Blue Fish Development Group this past year, I had never worked with Documentum. So, my first task was to familiarize myself with the basics of the Documentum Foundation Classes (DFC). Documentum defines DFC as “a set of Java classes that make essentially all EDM server functionality available to client programs through a published set of interfaces.” It may also be described as the Object-Relational-Mapper (ORM) for programmatically accessing and manipulating all of the objects in a docbase.
Whenever I’m learning a new application framework, I typically look for a “Quick Start” or “Getting Started” article either in the official documentation or by performing a Google search. If I’m unable to find one, then I dive straight into whatever documentation is provided with the intent of creating a set of programming exercises which will essentially become my own “Quick Start” guide going forward. Since a docbase is a persistent store, this meant I needed to familiarize myself with the basic CRUD functions: Create, Read, Update, and Delete. Furthermore, since Documentum is a document management system (to say the very least), I decided to explore the basic file system operations of the following:
- Create folder
- Create file
- Link file to folder
- Modify file
- Fetch folder contents
- Query files by attribute (name and author)
- Delete file
- Delete folder
Setting up a DFC project in Eclipse
The complete Eclipse project containing all sample code can be found HERE.
Setting up a basic DFC project in Eclipse was a straightforward task. After installing DFC 5.3 and creating a new Java project in Eclipse, perform the following steps:
- From your Documentum install dir, add dfc.jar, dfcbase.jar, and log4j.jar to your project’s Build Path.
- Create a new folder within your project and link it to the file system folder
<dctm-install>\config.
- Add your new linked
config
folder to your project’s Build Path.
Hello World: Logging into a Docbase
After setting up my Eclipse project, I wanted to verify that I could programmatically access my test docbase. I wrote the following JUnit TestCase, which would serve as the base class for all subsequent TestCases I might write. Its main purpose is to authenticate to our test docbase and obtain an IDfSession object for our tests to use.
package com.bluefish.dfc.test;
import junit.framework.TestCase;
import com.documentum.fc.client.DfClient;
import com.documentum.fc.client.IDfClient;
import com.documentum.fc.client.IDfSession;
import com.documentum.fc.client.IDfSessionManager;
import com.documentum.fc.common.DfLoginInfo;
import com.documentum.fc.common.IDfLoginInfo;
public class Dfc5BaseTest extends TestCase {
// TODO: refactor to pull from a properties file
private static final String DOCBASE = "YOUR DOCBASE";
private static final String USERNAME = "YOUR USERNAME";
private static final String PASSWORD = "YOUR PASSWORD";
private IDfSessionManager sessionMgr = null;
protected IDfSession session = null;
protected void setUp() throws Exception {
super.setUp();
IDfClient client = DfClient.getLocalClient();
sessionMgr = client.newSessionManager();
// Setup login details.
IDfLoginInfo login = new DfLoginInfo();
login.setUser(USERNAME);
login.setPassword(PASSWORD);
login.setDomain(null);
sessionMgr.setIdentity(DOCBASE, login);
session = sessionMgr.newSession(DOCBASE);
}
protected void tearDown() throws Exception {
super.tearDown();
if (session != null) {
sessionMgr.release(session);
}
}
protected void log(String message) {
System.out.println(message);
}
}
And then I tested my login code with the following subclass:
package com.bluefish.dfc.test;
public class LoginTest extends Dfc5BaseTest {
public void testLogin() throws Exception {
// login happens in setUp(), so nothing to do here
assertNotNull("session is null", session);
}
}
There are a couple of important points regarding the above code samples:
- Be sure always to clean up your IDfSessions when you’re finished with them.
- If available, always use the session manager to access and release sessions.
IDfSession.disconnect()
whenever a session was no longer needed. However, the IDfSessionManager supports session pooling, so it is critical that any session acquired through a session manager is released through that session manager as well. Otherwise, bad things can happen and probably will. This is typical Object/Relational Mapper design, so those familiar with a similar persistence framework should find the transition rather painless.
Overview of Documentum Foundation Classes (DFC)
DFC’s object model for managing docbase objects is a deep and complex hierarchy, but we can get started with the basics by looking at only a small subset of these classes:
*Arrows represent object inheritance levels.
IDfClient
IDfSessionManager
IDfSession
IDfQuery
IDfTypedObject --> IDfCollection
IDfPersistentObject --> IDfSysObject --> IDfFolder
IDfDocument
We’ve already been introduced to IDfClient, IDfSessionManager, and IDfSession in the previous section. So what are the remaining classes used for? The DFC Javadoc describes them as follows:
Class | Description |
IDfClient | This interface provides functionality to establish and manage sessions with a Documentum server, and provides information about the server before a session is established. |
IDfCollection | This interface provides access to collection objects. |
IDfDocument | This class provides the functionality for the client to interact with “dm_document” objects in the repository. |
IDfFolder | This interface provides access to folder-related data stored in folder objects. |
IDfPersistentObject | This interface extends IDfTypedObject and is the base class for all Documentum persistent objects. |
IDfQuery | This interface provides functionality for running queries against a repository. |
IDfSession | This interface encapsulates a session with a Documentum repository. |
IDfSessionManager | Manages identities, pooled sessions, and transactions. |
IDfSysObject | This class provides the functionality for the client to interact with “dm_sysobject” objects in the repository. |
IDfTypedObject | This interface provides basic operations for all typed objects. |
We’ll get a better understanding once we see them in action, so let’s put them to use.
CRUD: Create, Read, Update, and Delete
Finally, it’s time to do what we all love: Write code. Let’s revisit our chosen exercises:
- Create folder
- Create file
- Link file to folder
- Modify file
- Fetch folder contents
- Query files by attribute (name and author)
- Delete file
- Delete folder
DfcCrudTest.java
, with test methods present for each of our exercises. For some of our exercises, there turned out to be more than one viable way of accomplishing our goal. For example, to obtain a folder’s contents, you can perform a simple DQL query, or if you have a handle on the IDfFolder object, you can call the getContents(..)
method on the folder object. To demonstrate this, I included both options within my testFolderContents() method.
Please keep in mind that these tests are written for clarity, not for optimal design.
package com.bluefish.dfc.test;
import com.documentum.fc.client.DfQuery;
import com.documentum.fc.client.IDfCollection;
import com.documentum.fc.client.IDfDocument;
import com.documentum.fc.client.IDfFolder;
import com.documentum.fc.client.IDfQuery;
import com.documentum.fc.common.IDfId;
public class DfcCrudTest extends Dfc5BaseTest {
private static String DIR_NAME = "Subdir";
private static String DIR_PATH = "/Temp/" + DIR_NAME;
private static String FILE_NAME = "Getting Started with DFC and DQL.txt";
private static String FILE_PATH = DIR_PATH + "/" + FILE_NAME;
private static String DOC_AUTHOR = "Steve McMichael";
private IDfFolder folder;
private IDfDocument document;
public void testSimpleDfc() throws Exception {
initialize();
// tests are order dependent
createFolder();
createFile();
linkFileToFolder();
modifyFile();
fetchFolderContents();
queryFiles();
deleteFile();
deleteFolder();
}
private void createFolder() throws Exception {
log("** Testing folder creation");
folder = (IDfFolder) session.newObject("dm_folder");
folder.setObjectName(DIR_NAME);
folder.link("/Temp");
folder.save();
log("created folder " + folder.getId("r_object_id"));
assertEquals("unexpected folder path", DIR_PATH, folder.getFolderPath(0));
}
private void createFile() throws Exception {
log("** Testing file creation");
document = (IDfDocument) session.newObject("dm_document");
document.setObjectName(FILE_NAME);
document.setContentType("crtext");
document.setFile("E:/clipboard.txt"); // add content to this dm_document
document.save();
log("created file" + document.getId("r_object_id"));
}
private void linkFileToFolder() throws Exception {
log("** Testing file linking to folder");
document.link(DIR_PATH);
document.save();
log(FILE_PATH);
assertNotNull("unexpected folder path", session.getObjectByPath( FILE_PATH));
}
private void modifyFile() throws Exception {
log("** Testing file modification");
document.checkout();
int numAuthors = document.getAuthorsCount();
document.setAuthors(numAuthors, DOC_AUTHOR);
//doc.checkin(false, "Prevents promotion to CURRENT");
document.checkin(false, null); // When a null version label is provided,
// DFC automatically gives the new version
// an implicit version label (1.1, 1.2, etc.)
// and the symbolic label "CURRENT".
}
private void fetchFolderContents() throws Exception {
log("** Testing folder contents");
// (1) Fetch using IDfFolder object
IDfFolder folder = session.getFolderByPath(DIR_PATH);
assertNotNull("folder is null", folder);
IDfCollection collection = null;
IDfDocument doc = null;
int count = 0;
try {
collection = folder.getContents("r_object_id");
while (collection.next()) {
count++;
IDfId id = collection.getId("r_object_id");
doc = (IDfDocument) session.getObject(id);
log(id + ": " + doc.getObjectName());
}
} finally {
// ALWAYS! clean up your collections
if (collection != null) {
collection.close();
}
}
assertEquals("wrong number of files in folder", 1, count);
assertEquals("unexpected doc name", FILE_NAME, doc.getObjectName());
// (2) Fetch using DQL folder(..)
String dql = "SELECT r_object_id, object_name from dm_document where folder('"+DIR_PATH+"');";
// Or we can fetch the contents of our folder and all of its subfolders using
//
// folder('/Temp/Subdir', descend)
//
// But since we haven't added any subfolders, this will return the same set of dm_documents.
//
// String dql = "SELECT r_object_id, object_name from dm_document where folder('"+DIR_PATH+"', descend);";
IDfQuery query = new DfQuery();
query.setDQL(dql);
collection = null;
String docName = null;
count = 0;
try {
collection = query.execute(session, IDfQuery.DF_READ_QUERY);
while (collection.next()) {
count++;
String id = collection.getString("r_object_id");
docName = collection.getString("object_name");
log(id + ": " + docName);
}
} finally {
// ALWAYS! clean up your collections
if (collection != null) {
collection.close();
}
}
assertEquals("wrong number of files in folder", 1, count);
assertEquals("unexpected doc name", FILE_NAME, docName);
}
private void queryFiles() throws Exception {
log("** Testing file query");
// (1) load by path
IDfDocument doc = (IDfDocument) session.getObjectByPath(FILE_PATH);
assertNotNull("null doc returned", doc);
assertEquals("unexpected doc name", FILE_NAME, doc.getObjectName());
// (2) load by query
// NOTE: Authors is a "repeating attribute" in Documentum terminology,
// meaning it is multi-valued. So we need to use the ANY DQL keyword here.
doc = null;
String dql = "SELECT r_object_id"
+ " FROM dm_document"
+ " WHERE object_name = '" + FILE_NAME + "'"
+ " AND ANY authors = '" + DOC_AUTHOR + "'";
IDfQuery query = new DfQuery();
query.setDQL(dql);
IDfCollection collection = query.execute(session, IDfQuery.DF_READ_QUERY);
try {
assertTrue("query did not return any results", collection.next());
doc = (IDfDocument) session.getObject(collection.getId("r_object_id"));
} finally {
// ALWAYS! clean up your collections
if (collection != null) {
collection.close();
}
}
assertNotNull("null doc returned", doc);
assertEquals("unexpected doc name", FILE_NAME, doc.getObjectName());
}
private void deleteFile() throws Exception {
if (document != null) {
log("** Testing file deletion");
document.destroyAllVersions();
}
}
private void deleteFolder() throws Exception {
if (folder != null) {
log("** Testing folder deletion");
folder.destroyAllVersions();
}
}
private void initialize() {
// If something bad happened during the previous run, this will
// make sure we're back in a good state for this test run.
try {
session.getObjectByPath(FILE_PATH).destroy();
} catch (Exception e) {
// ignore
}
try {
session.getObjectByPath(DIR_PATH).destroy();
} catch (Exception e) {
// ignore
}
}
}
If you have your DFC Javadoc handy, then the above code sample should provide the details required to tie everything together.
However, there is one requirement I’d like to highlight. Whenever you execute a DQL query in DFC, an IDfCollection object is created as a handle to the query results, similar to a ResultSet in JDBC. This collection represents an open resource which must be closed. There are a limited number of collections available, and so it is imperative that collections be closed when they are no longer in use.
So the two best practices we’ve discussed regarding resource cleanup with DFC are:
- Release your IDfSession objects to their parent IDfSessionManager when you’re through with them. If you obtained your session directly from an IDfClient instead of through a session manager, then be sure to disconnect your session when you are finished.
- Close your IDfCollection objects when you are through with them.
Conclusion
Hopefully, this is enough to get you started. There are numerous resources available which provide a deeper dive into some of the concepts presented here. To help you out, I’ve provided a short list of references for further reading. Enjoy!
References
发表评论
-
修改Content Server管理员密码
2012-07-16 14:59 782修改documentum content server 管理员 ... -
Documentum-修改特定Type的显示图标
2012-07-16 14:57 719背景: 根据客户要求,希望能够在Webtop中对自定义的文档 ... -
Documentum-为客户化Type类型Import时添加自定义属性
2012-07-16 14:46 732默认情况下,当我们导入一个自定义Type类型的文档时,系统并不 ... -
Documentum-系统默认文件柜权限要求
2012-07-16 14:41 799在系统实施时,由于客户需求,要求屏蔽掉系统默认文件夹在界面 ... -
How to enable combined dmcl and dfc trace?
2012-04-16 16:17 621http://vsrr2020.blogspot.com/ ... -
解决Workflow Report查询慢的问题
2012-04-16 15:24 753idql: execute make_index with ... -
Documentum解密
2012-04-12 11:24 743System.out.println(com.document ... -
Method
2012-04-12 09:05 791import com.documentum.fc.cli ... -
解决DM_SESSION_E_CLIENT_AUTHENTICATION_FAILURE ---Documentum 6.0/6.5
2012-04-16 10:26 1309Instructions to fix this error: ... -
How to enable combined dmcl and dfc trace?
2012-03-29 20:29 730http://vsrr2020.blogspot.com/ ... -
ContentServer迁移的步骤
2012-03-29 20:25 8141.备份还原数据库,有时候用UI操作不成功的时候可以用命令 ... -
验证contentserver关于发送email的配置
2012-03-29 20:24 663从dm_event_sender.ebs中可以看出,con ... -
查看某个类型的某个字段的key,value
2012-03-23 09:10 701select map_display_string, map_ ... -
Documentum查看某个类型属性页将要显示的属性
2012-03-23 08:58 660select r_object_id, attribute_n ... -
DQL汇总
2012-03-06 22:21 12931. DQL to create user create “ ... -
How to enable combined dmcl and dfc trace?
2012-03-06 22:22 645http://vsrr2020.blogspot.com/20 ... -
怎样取得DQL所对应的Sql
2012-03-06 22:23 629首先先执行DQL,执行完毕后可以调用下边的方法。 pri ... -
调用本地Office应用
2012-03-06 22:23 1241As the title suggests, my last ... -
DFS开发
2012-03-29 13:21 845先送上一段视频 https://community.em ... -
使用dfc运行DQL并取得相应sql的代码
2012-02-26 00:29 846query.setDQL("SELECT r_obj ...
相关推荐
Dcumentum DFC7 API文档
最新Documentum DFC API,用于Documentum的底层接口开发
dfc开发指南,详细的dfc开发介绍,EMC公司出品。
documentum之DFC开发概览 资料不好找,供有需要的朋友下载
Documentum 6.5 DFC Guide. It leaks from the official document library. Enjoy it.
无意中下载的一个PB小程序内夹带的关于PB编程框架DFC类库的说明文档,挺不错的。
sad控制台飞机大战 游戏源码 dfc 不打开图档可替换字符串 sd
基于作业成本法的DFC成本计算模式.doc
天津贝尔 DFC伺服放大器 使用说明书pdf,天津贝尔 DFC伺服放大器 使用说明书
声纹识别中使用dfc方法获取检测代价。简单实用。
adb失效后在dbadapter reserved intergace下刷机取回IMEI号
DFC- 类库开发指南 CHM,简要说明一下,包括DFC类库、最新新增、修改列表、开发指南、开发参考、设置文件、疑难解答、词汇表、技术支持等……
NULL 博文链接:https://kyh8408.iteye.com/blog/1171404
个人无错音乐网文视频分享网站源码,后台登陆地址admin/admin.asp 用户名:admin密码:admin
DFC Operations Whitepaper
How to write the DFC codes
ffmpeg-20200519-74dfc88-win64-static.zip
Beginner for DFC Programmers