Escolar Documentos
Profissional Documentos
Cultura Documentos
Copyright 1994-2003 Documentum, Inc. 6801 Koll Center Parkway All rights reserved. Printed in USA.
Pleasanton, CA 94566
DOCUMENTUM, NOW YOU KNOW, UNITING THE WORLD THROUGH CONTENT, GMPHARMA, GXPHARMA, GDPHARMA, GSPHARMA and the Documentum corporate logo are trademarks or registered trademarks of Documentum, Inc. in the United States and throughout the world. All other company and product names are used for identification purposes only and may be trademarks of their respective owners.
Table of Contents
Preface ......................................................................................................................... Chapter 1 Getting Started With DFC .............................................................. Organization of the Manual ............................................................................. What is DFC? .............................................................................................. Where is DFC? ............................................................................................. Programming with DFC ................................................................................. Interfaces ................................................................................................ Client/Server Model .................................................................................. IDfPersistentObject ................................................................................... Processing a Docbase Object ....................................................................... Using DFC From Application Programs ............................................................ Java........................................................................................................ Visual Basic ............................................................................................. C++........................................................................................................ Syntax Differences .................................................................................... Creating DFC Client Objects ........................................................................... Java Example ........................................................................................... Visual Basic Example ................................................................................ Using DFC Tracing ....................................................................................... Packages ..................................................................................................... Using the DFC Online Reference Documentation ................................................ Working With Documents .............................................................. Introduction to Documents.............................................................................. Virtual Documents .................................................................................... XML Documents ...................................................................................... Introduction to Operations .............................................................................. Types of Operations....................................................................................... Basic Steps for Manipulating Documents........................................................... Steps for Manipulating Documents ............................................................... Details of Manipulating Documents .............................................................. Operations for Manipulating Documents ........................................................... Importing ................................................................................................ Exporting ................................................................................................ Checking Out ........................................................................................... Checking In ............................................................................................. Cancelling Checkout ................................................................................. Copying .................................................................................................. Moving ................................................................................................... Deleting .................................................................................................. Validating an XML Document Against a DTD or Schema ................................. Performing an XSL Transformation of an XML Document ...............................
9 11 11 12 13 13 13 14 14 14 15 16 16 16 17 17 17 18 18 18 20 21 21 21 23 23 24 24 24 26 28 28 30 31 32 34 34 36 36 38 39
Chapter 2
Table of Contents
Handling Document Manipulation Errors .......................................................... The add Method Cannot Create a Node ......................................................... The execute Method Encounters Errors ......................................................... Operations and Transactions ...........................................................................
41 41 41 45 47 47 47 48 48 49 49 50 50 51 52 55 55 55 56 56 57 57 57 58 58 61 61 61 62 62 62 63 63 64 64 65 65 65 66 66 66 67 67 67 68 69 69 69 71 72
Chapter 3
Working With Docbase Sessions ................................................ Introduction ................................................................................................. Managed and Unmanaged Sessions .............................................................. Session Manager ....................................................................................... Session Pool ............................................................................................ Using a Session Manager................................................................................ Lifetimes of Sessions and Managers ............................................................. Multiple Docbases .................................................................................... AuthenticationSetting and Managing Identities ................................................ Using Manual Identities ............................................................................. Using Principal Identities ........................................................................... Managing Docbase Queries with DFC ....................................... Queries ....................................................................................................... Flow of Query Processing ........................................................................... IDfQuery................................................................................................. IDfCollection ........................................................................................... Basic Query Examples ................................................................................... execQuery in Visual Basic .......................................................................... displayResults in Visual Basic ..................................................................... execQuery in Java ..................................................................................... displayResults in Java ................................................................................ ........................................................... Checking Objects Against Validation Rules........................................................ validate in Java ......................................................................................... Changing Permissions.................................................................................... changeBasicPermissions in Visual Basic........................................................ changeExtendedPermissions in Visual Basic .................................................. changeBasicPermissions in Java .................................................................. changeExtendedPermissions in Java ............................................................. Using Private ACLs ...................................................................................... privateACLs in Visual Basic ....................................................................... privateACLs in Java .................................................................................. ACL Utility Methods ..................................................................................... permissionToString in Visual Basic .............................................................. extendedPermissionToString in Visual Basic .................................................. displayBasicPermissions in Visual Basic ....................................................... displayExtendedPermissions in Visual Basic .................................................. permissionToString in Java ......................................................................... extendedPermissionToString in Java ............................................................. displayBasicPermissions in Java .................................................................. displayExtendedPermissions in Java ............................................................. Understanding Business Objects ............................................... Introduction to Business Objects ...................................................................... Overview of BOF ..................................................................................... Benefits of Using BOF ............................................................................... BOF Architecture ..................................................................................... Using Validation and ACLs
Chapter 4
Chapter 5
Chapter 6
Table of Contents
Service Based Business Objects ....................................................................... Architecture ............................................................................................. Rules and Guidelines ................................................................................. Type Based Business Objects .......................................................................... Introduction ............................................................................................. Architecture ............................................................................................. Implementation Rules, Guidelines, and Examples ........................................... Calling Rules, Guidelines, and Examples ....................................................... Error Handling ......................................................................................... Best Practices ........................................................................................... Documentum Business Object Registry (DBOR)................................................. Overview of DBOR .................................................................................. Architecture of DBOR ............................................................................... Using DBOR at Runtime ............................................................................ Managing DBOR ...................................................................................... Handling DBOR Errors ..............................................................................
77 78 79 83 83 83 85 88 88 88 89 89 90 91 91 93 95 95 96 96 96 97 97 99 99 105 106 108 112 112 112 113 115 116 119 121 121 121 121 128 131 132 132 132 134 135 136 136 137 137 138 138
Chapter 7
Developing Business Objects ...................................................... Getting Started with BOF ............................................................................... Overview of the Sample Business Objects ......................................................... The Simple_TBO Example ......................................................................... The Simple_SBO Example ......................................................................... A Simple TBO Example ................................................................................. Introduction ............................................................................................. Creating the IAutoNumberType Interface ...................................................... Creating the AutoNumberType Class ............................................................ Creating the com_accelera_autonumber Docbase Type ................................... Registering the TBO with DBOR ............................................................... Testing the TBO ..................................................................................... A Simple SBO Example ............................................................................... Introduction ........................................................................................... Defining the IAutoNumber Interface........................................................... Defining the AutoNumber Class ................................................................ Deploying and Registering the Service ........................................................ Implementing the Simple_SBO Test program ............................................... Running the Simple_SBO Test Program ...................................................... Using and Deploying Business Objects .................................. Using Business Objects ................................................................................ Overview .............................................................................................. Managing Sessions for Business Objects ..................................................... How to use a Business Object from WDK ................................................... How to use a Business Object from Visual Basic using IDispatch ..................... Deploying Business Objects .......................................................................... Overview .............................................................................................. Packaging .............................................................................................. Business Object Registration ..................................................................... Documentation ....................................................................................... Custom Installer/Uninstaller ...................................................................... AutoNumber Components ........................................................................ Overview of the DFC Interface Hierarchy ................................ Documentum Object Hierarchy ..................................................................... Subtypes and Supertypes .......................................................................... Persistence.............................................................................................
Chapter 8
Chapter 9
Table of Contents
Typed Objects ............................................................................................ Session and Identifier .............................................................................. Getting and Setting Attribute Values ........................................................... Additional Methods for Operating on Repeating Attributes ............................. Attribute Information ............................................................................... Persistent Objects........................................................................................ Methods Relating to the Basic Properties of Persistent Objects ........................ Basic Operations on an Object ................................................................... Audit Trail ............................................................................................. Convenience Methods for Creating Object Relations ..................................... Validation Methods ................................................................................. Pass-Through Methods to the DMCL API ................................................... Persistent Objects Without Associated Content ................................................. IDfACL ................................................................................................ IDfFormat ............................................................................................. IDfUser and IDfGroup ............................................................................. IDfType ................................................................................................ SysObjectsPersistent Objects With Content .................................................. Basic Operations on SysObjects ................................................................. Types That Derive From IDfSysObject........................................................ IDfSession ................................................................................................. Provide Information ................................................................................ Create Objects and Obtain Object References ............................................... Configuration Information ........................................................................ Transaction Support ................................................................................ Docbase Scope ....................................................................................... Multithreading Support ............................................................................ API Calls .............................................................................................. Inbox and Workflow ................................................................................ Administration ....................................................................................... Session State .......................................................................................... Miscellaneous ........................................................................................ IDfClient ................................................................................................... Creating Sessions and Obtaining References to Existing Sessions..................... Maps and Config Information .................................................................... Service Methods ..................................................................................... Common Package .......................................................................................
142 143 143 145 145 146 146 147 147 148 148 149 149 149 150 150 150 152 153 154 154 154 155 156 156 156 157 157 158 158 159 159 159 159 159 160 160 163 163 165 165
Chapter 10
DFC and DMCL ............................................................................... Relationship to DMCL ................................................................................. Calling DMCL Directly ............................................................................... DMCL to DFC Correspondence .....................................................................
Table of Contents
List of Figures
Figure 31. Figure 32. Figure 61. Figure 62. Figure 63. Figure 64. Figure 65. Figure 66. Figure 67. Figure 68. Figure 71. Figure 72. Figure 73. Figure 74. Figure 75. Figure 81. Figure 91. Figure 92. Figure 101.
Implementing the getSession method of IDfPrincipalSupport .................................... Principal Identity Diagram .................................................................................. Documentum Business Objects N-Tier Model ........................................................ BOF is integral to DFC ...................................................................................... TBO Interaction Diagram ................................................................................... Business Object Using Another Business Object ..................................................... SBO Interaction Diagram ................................................................................... Any Business Object calling an SBO .................................................................... Class Diagram for Service based Business Objects .................................................. Class Diagram for Type-based Business Objects ..................................................... AutoNumber Schema......................................................................................... Installing a new Docbase Type .......................................................................... Installing a new Docbase Type .......................................................................... Run the test TBO program ................................................................................ Sample running test SBO program ..................................................................... Customer Service User Interface WDK Form ....................................................... DFC Hierarchy Corresponds to Documentum Object Hierarchy ............................... DFC Interface Hierarchy .................................................................................. DFC Builds Business Logic Above DMCL ..........................................................
Table of Contents
List of Tables
Table 11. Table 12. Table 13. Table 21. Table 61. Table 62. Table 63. Table 71. Table 81. Table 82. Table 101. Table 102.
Manual Organization ......................................................................................... COM equivalents of DFC datatypes...................................................................... Classes and Interfaces of DFC Packages ................................................................ DFC Operation Types and Nodes ......................................................................... IDfBusinessObject Methods to Implement ............................................................ TBO Factory Method Exceptions ......................................................................... Methods of IDfDbor .......................................................................................... Sample com_accelera_autonumber Objects and Their Values ................................... WDK Component getDfSession methods ............................................................ DBOR Entry Attribute Samples For "service" And "type" ....................................... DFC Methods and DMCL API Commands ..........................................................
................................................................................................................... 165
Preface
Purpose of the Manual
This manual describes Documentum Foundation Classes (DFC), an object-oriented framework for accessing and extending the capabilities of products based on Documentum Content Server.
Intended Audience
This manual is for programmers who understand how to use Java and are generally familiar with the principles of object oriented design.
Revision History
Revision History Revision Date 2003 Mar 31 Description Initial Document Release
Conventions
Conventions Convention Italics Description Represents a variable name for which you must provide a value, or a defined term. Represents code samples, commands, user input, and computer output. When used for a command lines to launch a program, they represent command line arguments that are optional. In code, they are used as the language rules dictate, such as array subscript in Java or C++. For command lines that launch programs, curly braces indicate optional arguments that can be repeated. For code, they represent statement blocks, such as methods and loop blocks in Java and C++.
{curly braces}
Preface
Product Documentation
When a product is released, we post product documentation to the support area of documentum.com. You can order any of our documentation in the form of bound manuals. We print and stock widely-used manuals, usually several months after we publish the online version. We print other documentation to order. To place an order or to ask about prices, call the documentation order line at (925) 600-6666. You can pay with a purchase order, check, or credit card. We do not sell bound manuals through documentum.com.
10
This chapter introduces DFC. It contains the following major sections: What is DFC?, page 12 Where is DFC?, page 13 Programming with DFC, page 13 Using DFC From Application Programs, page 15 Creating DFC Client Objects, page 17 Using DFC Tracing, page 18 Packages, page 18 Using the DFC Online Reference Documentation, page 20
Chapter 3, Working With Docbase Sessions Chapter 4, Managing Docbase Queries with DFC Chapter 5, Using Validation and ACLs Chapter 6, Understanding Business Objects
How to work with the servers validation and permission mechanisms. The role of the business objects framework (BOF) in middleware. Rules and guidelines for developing BOF services and for extending DFC classes to implement BOF types. Architecture of the business objects registry (DBOR) and how to access and manage it.
11
Chapter
Contents A tutorial for developing, deploying and using business objects. Working examples.
Using business objects from WDK and Visual Basic. Requirements for deploying business objects to execution platforms. How DFC gives you an object oriented interface to the Documentum object hierarchy. An explanation of DFC in terms of the methods that previous Documentum client products use to access server capabilities. The architecture of the framework and the enhancements to DFC that made the framework possible. Types of business objects, the session manager, and other definitions.
Chapter 9, Overview of the DFC Interface Hierarchy Chapter 10, DFC and DMCL
What is DFC?
Documentum Foundation Classes (DFC) is an object oriented application programming interface (API) and framework for accessing, customizing, and extending Documentum functionality. Documentum has implemented DFC as a set of Java interfaces and implementation classes. DFC also provides a bridge to make the interfaces available in Microsofts Component Object Model (COM) environment. The business objects framework (BOF) is a key part of DFC. BOF enables you to embody business rules and patterns in reusable elements, called type-based objects (TBOs) and service based objects (SBOs). BOF makes it possible to extend some of DFCs implementation classes. As a result, you can introduce new functionality in such a way that unmodified existing programs begin immediately to deliver the new functionality. You can use DFC in any of the following ways: Access Documentum functionality from within one of your companys enterprise applications. For example, your corporate purchasing application can retrieve a contract from your Documentum system. Customize or extend Documentum products like Desktop Client or WDK. For example, you can modify the Desktop Client functionality to implement one of your companys business rules. Write a method or procedure for Content Server to execute as part of a workflow or document lifecycle. For example, the procedure that runs when you promote an XML document might apply a transformation to it and start a workflow to subject the transformed document to a predefined business process.
12
The Documentum Content Server Fundamentals manual provides a conceptual explanation of the capabilities of Content Server and how they work. DFC provides a framework for accessing those capabilities. Using this framework makes your code much more likely to survive future architectural changes in the Documentum system. The core of DFC is a set of Java classes, but it includes other elements as well: A collection of DLLs to provide the DFC functionality. A type library for accessing DFC via COM from Visual Basic or Visual C++.
Where is DFC?
DFC runs on a Java virtual machine (JVM), which can be on: The machine that runs Content Server. For example, to execute a method as part of a workflow or document lifecycle. A middle-tier system. For example, to support WDK on an application server. An end users computer. For example, to support Desktop Client.
Interfaces
Because DFC is large and complex, and because its underlying implementation is subject to change, you should use DFCs public interfaces wherever possible. DFC provides factory methods to instantiate objects that implement specified DFC interfaces. If you bypass these methods to instantiate implementation classes directly, your programs may fail to work properly, because the factory methods often do more than simply instantiate the standard implementation class. Documentum does not generally support direct access to DFCs implementation classes. Nor does Documentum generally support replacement or extension of DFC implementation classes. The principal exception to these rules is the business object framework (BOF), a mechanism and development pattern for extending selected implementation classes.
13
Client/Server Model
The Documentum architecture generally follows the client/server model. DFC-based programs are client programs, even if they run on the same machine as a Documentum server. DFC encapsulates its client functionality in the IDfClient interface, which serves as the entry point for DFC code. IDfClient handles basic details of connecting to Documentum servers. It loads the necessary shared libraries. You obtain the initial IDfClient interface by calling the static getLocalClient method of the DfClient implementation class. The IDfClient interface then serves as a factory for IDfSession objects. If you are familiar with the standard Java database connectivity package (JDBC), you can see an analogy between that programming model and this one. An IDfSession object represents a connection with the Documentum server and provides services related to that session. DFC programmers create new Docbase objects or obtain references to existing Docbase objects through the IDfSession interface.
IDfPersistentObject
With DFC you usually dont create objects directly. Instead, you obtain objects by calling the methods of other objects. Those methods create or obtain the requested object. Methods that create new Docbase objects or fetch existing ones return objects that implement IDfPersistentObject.
1. 2. 3. 4.
Obtain an IDfClient object by calling the static getLocalClient method of DfClient. Obtain a session manager by calling the newSessionManager method of the IDfClient object. Use the session manager to obtain a session with the Docbase, that is, a reference to an object that implements the IDfSession interface. If you do not have a reference to the Docbase object, call an IDfSession method (for example, newObject or getObjectByQualification) to create an object or to obtain a reference to an existing object. Use routines of the operations package (see Chapter 2, Working With Documents) to manipulate the objectcheck it out, check it in, and so forth. Release the session if you are done with it.
5. 6.
14
The following fragment from a Java program that uses DFC illustrates this procedure.
IDfClient client = DfClient.getLocalClient(); //Step 1 IDfSessionManager sMgr = client.newSessionManager(); //Step 2 IDfLoginInfo loginInfo = new DfLoginInfo(); loginInfo.setUser( "Mary" ); loginInfo.setPassword( "ganDalF" ); loginInfo.setDomain( "" ); sMgr.setIdentity( strDocbaseName, loginInfo ); IDfSession session = sMgr.newSession( strDocbaseName ); //Step 3 IDfDocument document = null; document = (IDfDocument) session.newObject( "dm_document" ); //Step 4 document.setObjectName( "Report on Wizards" ); document.setContentType( "crtext" ); document.setFile( "C:\Temp\Wiz.txt" ); document.save(); sMgr.release( session ); //Step 6
Steps 1 through 3 obtain an IDfSession object, which encapsulates a session for this application program with the specified Docbase. Step 4 creates an IDfDocument object. Notice that the newObject method of the IDfSession object manufactures the IDfDocument object. Rather than introducing operations at this point, the example code populates and saves the IDfDocument object by calling some of its low level methods. Note that the newObject method returns an IDfPersistentObject object. The program explicitly casts it to an IDfDocument object, then uses the document objects save method, a method that IDfDocument inherits from IDfPersistentObject. Step 6 releases the session, that is, places it back under the control of the IDfSessionManager object. The IDfSessionManager object can reassign it the next time the application calls the objects newSession method. Most DFC methods report errors by throwing a DfException object. Java code like that in the above example normally appears within a try/catch/finally block, with an error handler in the catch block. Visual Basic code uses the On Error Goto statement to handle exceptions. Note: When writing code that calls DFC, it is a good idea to include a finally block to ensure that you can release storage and sessions.
15
Java
From Java, use the Java interface. Add the DFC class and interface files (for example, C:\Program Files\Documentum\Shared\dfc.jar) to your CLASSPATH. In your Java source code, import the classes you wish to use.
Visual Basic
Using DFC from Visual Basic requires a small setup procedure. The DFC installer establishes the software environment to allow Visual Basic to access DFC using COM. From a Visual Basic project, you need only establish a reference to dfc.jar.
To establish a reference to dfc.jar:
1.
Choose PropertiesReferences.
The References dialog box appears. 2. Check the checkbox for Documentum Foundation Classes.
C++
From C++, use COM directly, or, if you use MFC, you can use classes, called wrapper classes, that Documentum provides to hide some of the complexities of the COM interface. To use these classes with MFC, include the following files in your Visual C++ project: DfClientX.h, DfClientX.cpp, dfc.h, and dfc_i.c If you dont use MFC or if you wish to write your own wrapper classes, include only dfc.h and dfc_i.c. Note: Interface inheritance requires a workaround if you access DFC from C++, because the Microsoft Java virtual machine does not support COM interface inheritance. See the example in the previous section. Follow these rules for objects and pointers: Always assign a DFC object to a new pointer. First delete the old pointer, then create a new CDfSysObject, as in the following C++ example:
//Get a DFC object CDfSysObject sobj1 = session.getObject(id); CDfSysObject *pSysObj = null; //Delete the old pointer if (pSysObj) delete pSysObj; //Create new CDfSysObject pSysObj = new CDfSysObject(sobj1);
A procedure that returns a DFC object should return a pointer to the object, as demonstrated in the following Visual C++ example:
CDfSysObject *myFunction();
16
{ CDfSysObject sobj1 = session.getObject(id); CDfSysObject *retval = new CDfSysObject (sobj1); return retval; }
Syntax Differences
COM and Java give you access to the same DFC classes and interfaces, but COM datatypes differ slightly from Java datatypes. The following table shows the COM equivalents of DFC datatypes.
Table 12. COM equivalents of DFC datatypes Java (DFC datatype) Visual Basic (and Docbasic) Boolean Long String Double IDfinterfacename or Object C++ with MFC wrapper classes BOOL long CString double CDfinterfacename C++ directly to COM
1.
The DFC client object must reside in the same process as the Documentum client library, DMCL. DFC client objects are also called local DFC clients. Java and COM use different interfaces to create the DFC client object, as shown in the examples. 2. Provide login information and use the session manager to establish a DFC session.
Java Example
Use the DfClient.getLocalClient method.
IDfClient myclient = DfClient.getLocalClient();
This line of code creates an IDfClient object. The IDfClient methods provide access to the services of the local DFC client.
17
The fact that these methods are static allows you to set up tracing before establishing sessions or creating objects. COM programs must access these methods through the IDfClientX interface. Trace levels range are integers in the range 010. The level controls the amount of information DFC places into the trace file. The level 0 means no tracing, and each increment asks DFC to provide more information. Each level includes all of the information of the smaller numbered levels See the Javadocs for details. If you dont set a trace file, the information goes to the standard output.
Packages
DFC comprises a number of packages, that is, sets of related classes and interfaces. The names of DFC Java classes begin with Df (for example, DfCollectionX). Names of interfaces begin with IDf (for example, IDfSessionManager).
Interfaces expose DFCs public methods and constants. Each interface contains a set of related methods. The following table describes the purpose of the classes and interfaces of DFC packages.
18
Table 13. Classes and Interfaces of DFC Packages Java Package Name com.documentum.fc.client Purpose Provides basic functionality: Establishing DFC sessions Retrieving and validating data Managing workflows Manipulating virtual documents Working with document versions com.documentum.operations Provides high-level functionality, such as checking documents or virtual documents in and out. Provides XML support. Constructs and runs queries and SmartLists. Facilitates constructing Docbase queries that return results in an XML format. Supplies utility methods for other DFC classes. Maintains Documentum information on the clients system, using the Windows registry on Win32 platforms, and .ini files otherwise. Provides factory methods for constructing DFC objects. Facilitates access to DFC through COM.
common.documentum.fc.client.qb com.documentum.xml.xdql
com.documentum.fc.common com.documentum.registry
com.documentum.com
Note: The com.documentum.operations package and the IDfSysObject interface in the com.documentum.fc.client package have some methods for the same basic tasks (for example, checkin, checkout). The IDfSysObject methods are mostly for internal use and for supporting legacy applications. The methods in the operations package perform the corresponding tasks at a higher levelkeeping track of client-side files and implementing Content Server XML functionality. The name of the com.documentum.com interface might lead you to believe that it is only for accessing DFC through COM. In fact, you can use its factory methods (all of its getxxx methods, except for those dealing with the DFC version or trace levels) from Java code as well.
The DFC interfaces form a hierarchy; some derive methods and constants from others. Use the Tree link from the home page of the DFC online reference (see Using the DFC Online Reference Documentation, page 20) to examine the interface hierarchy. Click any interface to go to its definition. Each interface inherits the methods and constants of the interfaces above it in the hierarchy. For example, IDfPersistentObject has a save method. IDfSysObject is a subclass of IDfPersistentObject, so it inherits the save method (see Persistent Objects, page 146 and SysObjectsPersistent Objects With Content, page 152).
19
In Java, you can call the save method of an object of type IDfSysObject.
1.
If you wish to operate on an object in the Docbase, determine the most general interface that should support the operation, and look there.
For example, you can save any persistent object, so look for a save method in IDfPersistentObject. If the functionality involves content, security, versioning, or checkout/checkin, look at IDfSysObject or interfaces derived from it. 2. If you wish to create an object, obtain a reference to an object, or perform a general operation, a. b. If the operation depends on having a session, look in IDfSession. Otherwise, look in IDfClientX.
20
This chapter describes the way to use DFC to perform the most common operations on documents. It contains the following main sections: Introduction to Documents, page 21 Introduction to Operations, page 23 Types of Operations, page 24 Basic Steps for Manipulating Documents, page 24 Handling Document Manipulation Errors, page 41
Introduction to Documents
The Documentum Content Server Fundamentals manual explains the Documentum facilities for managing documents. This section provides a concise summary of what you need to know to understand the remainder of this chapter. Documentum maintains a repository of objects that it classifies according to a type hierarchy. For this discussion, SysObjects are at the top of the hierarchy (see SysObjectsPersistent Objects With Content, page 152). A document is a specific kind of SysObject. Its primary purpose is to help you manage content.
Virtual Documents
A virtual document is a container document that includes one or more objects called components structured as an ordered hierarchy. A component is another virtual document or any SysObject subtype except folders, cabinets, or subtypes of folders and cabinets. A virtual document can have any number of components, nested to any level. Documentum imposes no limit on the depth of nesting in a virtual document. Documentum uses two sets of terminology for virtual documents. In the first set, a virtual document that contains a component is called the components parent, and the component is called the virtual documents child. Children, or children of children to any depth, are called descendants. Note: Descendants are sometimes called descendents in internal variables, Javadoc comments, and registry keys.
21
The second set of terminology derives from graph theory. The virtual document and each of its descendants is called a node. The directed relationship between a parent node and a child node is called an edge. In both sets of terminology, the original virtual document is sometimes called the root. Documentum maintains more than one version of a document. A version tree is an original document and all of its versions. Every version of the document has a unique object ID, but every version has the same chronicle IDthe object ID of the original document. You can associate a particular version of a component with the virtual document (this is called early binding) or you can associate the components entire version tree with the virtual document. The latter allows you to select which version to include at the time you assemble the document (this is called late binding). Documentum provides an extremely flexible set of rules for controlling the way it assembles documents. An assembly is a snapshot of a virtual document. It consists of the set of specific component versions that result from assembling the virtual document according to a set of binding rules. To preserve it, you must attach it to a SysObjectusually either the root of the virtual document or a SysObject created to hold the assembly. A SysObject can have at most one attached assembly. Documentum represents the components of virtual documents by containment objects and the components of assemblies by assembly objects. An assembly object refers to the SysObject to which the assembly is attached, and to the virtual document from which the assembly came. If an object appears more than once as a node in a virtual document or assembly, each node has a separate associated containment or assembly object. No object can appear as a descendant of itself in a virtual document. You can version a virtual document and manage its versions just as you do a simple document. Deleting a virtual document version also removes any containment objects or assembly objects associated with that version. When you copy a virtual document, the server can make a copy of each component or it can create an internal reference or pointer to the source component. It maintains information in the containment object about which of these possibilities to choose. One option is to require the copy operation to specify the choice. Whether it copies a component or creates a reference, Documentum creates a new containment object corresponding to that component. Note: DFC allows you to process the root of a virtual document as an ordinary document. For example, suppose that doc is an object of type IDfDocument and also happens to be the root of a virtual document. If you tell DFC to check doc out, it does not check out any of the descendants. If you want DFC to check out the descendants along with the root document, you must first execute an instruction like
IDfVirtualDocument vDoc = doc.asVirtualDocument(CURRENT, false)
If you tell DFC to check vDoc out, it processes the current version of doc and each of its descendants. The DFC Javadocs explain the parameters of asVirtualDocument.
22
XML Documents
When you import an XML document, DFC creates a virtual document. It imports other documents that the XML document refers to as entity references or links, and makes them components of the virtual document. It uses attributes of the containment object associated with a component to remember whether it came from an entity or a link and to maintain other necessary information. Assembly objects have the same XML-related attributes as containment objects do. Documentums XML support has many more features. It also requires you to provide a controlling XML application. Information about those subjects appears in Documentum Content Server Fundamentals and in Managing XML Content in Documentum.
Introduction to Operations
To manipulate documents in Documentum, you must understand operations. Operations are like the document carriers you use to put small pieces of paper through the feeder of a copying machine. Operations provide interfaces and a processing environment to ensure that Documentum can handle a variety of documents and collections of documents in a standard way. You obtain an operation of the appropriate kind, place one or more documents into it, and run it through the machine, that is, execute the operation. The operations apply to objects of type IDfSysObject, not just the subtype IDfDocument, but all of the examples in this chapter pertain only to documents. For example, to check out a document, take the following steps: 1. 2. 3. Obtain a checkout operation. Add the document to the operation. Execute the operation.
DFC carries out the behind-the-scenes tasks associated with checking out a document. For a virtual document, for example, DFC adds all of its components to the operation and ensures that links between them are still valid when it stores the documents into the checkout directory on the file system. It corrects filename conflicts, and it keeps a local record of which documents it checked out. This is only a partial description of what DFC does when you check out a document. Because of the number and complexity of the underlying tasks, DFC wraps seemingly elementary document-manipulation tasks in constructs called operations. An IDfClientX object provides methods for creating operations. For this reason, we call it a factory for operations. Once you have the factory object (say cX) and a SysObject representing the document (say doc), the code for the checkout looks like this:
// Obtain a checkout operation IDfCheckoutOperation checkout = cX.getCheckoutOperation; // Add the document to the checkout operation checkout.add(doc); //This might fail and return a null // Check the document out checkout.execute(); //This might produce errors without
23
//throwing an exception
In real code, you would check to see if the add method returns a null or the execute method returns errors.
Types of Operations
DFC provides operation types and corresponding nodes (to be explained in subsequent sections) for many tasks you might wish to perform on documents or, where appropriate, files or folders. The following table summarizes these.
Table 21. DFC Operation Types and Nodes Task Import into a Docbase Export from a Docbase Check into a Docbase Check out of a Docbase Cancel a checkout Delete from a Docbase Copy from one Docbase location to another Move from one Docbase location to another Validate an XML document against a DTD or Schema Transform an XML document using XSLT Operation Type IDfImportOperation IDfExportOperation IDfCheckinOperation IDfCheckoutOperation IDfCancelCheckoutOperation IDfDeleteOperation IDfCopyOperation Operation Node Type IDfImportNode IDfExportNode IDfCheckinNode IIDfCheckoutNode IDfCancelCheckoutNode IDfDeleteNode IDfCopyNode
IDfMoveOperation
IDfMoveNode
IDfValidationOperation
IDfValidationNode
IDfXMLTransformOperation
IDfXMLTransformNode
1.
Use the appropriate factory method of IDfClientX to obtain an operation of the type appropriate to the document-manipulation task.
24
For example, if you wish to check documents into a Docbase, start by calling getCheckinOperation. 2. Set parameters to control the way the operation performs the task.
Each operation type has setXxx methods for setting its parameters. The operation behaves in predefined (default) ways if you do not set optional parameters. Some parameters (the session for an import operation, for example) are mandatory. 3. Add documents to the operation: a. Use its inherited add method to place a document, file, or folder into the operation. Note: Each operation has a type (for example, IDfCheckinOperation) that inherits most of its methods (in particular, its add and execute methods) from IDfOperation. The add method returns the newly created node (or a null if it fails). b. Set parameters to change the way the operation handles this item and its descendants.
Each type of operation node has methods for setting parameters that are important for that type of operation. These are generally the same as the methods for the corresponding type of operation. If you do not set parameters, the operation handles this item according to the setXxx methods. c. 4. Repeat the previous two substeps for all items you wish to place into the operation.
Invoke the operations inherited execute method to perform the task. Note: Each operation has a type (for example, IDfCheckinOperation) that inherits most of its methods (in particular, its add and execute methods) from IDfOperation.
Note that this step may add and process additional nodes. For example, if part of the execution entails scanning an XML document for links, DFC may add the linked documents to the operation. 5. Process the results. a. Handle errors.
If it detects errors, the execute method returns the boolean value false. You can use the operations inherited getErrors method to obtain a list of failures. Note: Each operation has a type (for example, IDfCheckinOperation) that inherits most of its methods (in particular, its add and execute methods) from IDfOperation. For details of how to process errors, see Processing the Results, page 27. b. Perform tasks specific to the operation.
For example, after an import operation, you may wish to take note of all of the new objects that the operation created in the repository. You might wish to display or modify their properties.
25
26
27
These methods return nodes as objects of type IDfOperationNode, not as the specific node type (for example, IDfCheckinOperationNode). The getId method of an IDfOperationNode object returns a unique identifier for the node, not the object ID of the corresponding document. IDfOperationNode does not have a method for obtaining the object ID of the corresponding object. Each operation node type (for example, IDfCheckinOperationNode) has its own getObjectID method. You must cast the IDfOperationNode object to a node of the specific type before obtaining the object ID.
The examples use the term file to refer to files on the file system and the terms document and folder to refer to Docbase documents and folders, as represented by DFC objects of type IDfDocument and IDfFolder.
Importing
The execute method of an IDfImportOperation object imports files into the repository. It creates objects as required, transfers the content to the repository, and removes local files if appropriate. If any of the nodes of the operation refer to existing objects (for example, through XML or OLE links), it imports those into the repository too.
Example 21. Importing an XML document void testImport1( IDfClientX clientx, // factory for operation IDfSessionManager sMgr, // to obtain a session String strDocbaseName, // to obtain a session IDfId idFolder, // dest folder id IDfFile idFile ) // file to import throws DfException { IDfSession session = sMgr.getSession( strDocbaseName ); try { // Construct a new import operation IDfImportOperation opImport = clientx.getImportOperation();
28
// Set operation object properties opImport.setSession( session ); opImport.setDestinationFolderId( idFolder ); // Add file to import and downcast it to the specific type IDfImportNode node = (IDfImportNode)opImport.add( idFile ); if( node == null ) { // See Handling Document Manipulation Errors, page 41 } // Set node properties node.setXMLApplicationName( "CellPhoneCatalog" ); // Execute the operation if( !opImport.execute() ) { // See Handling Document Manipulation Errors, page 41 } // Optionally, get a list of object IDs IDfList list = opImport.getNewObjects(); IDfSysObject obj; int iCount = list.getCount(); for( int i = 0; i < iCount; ++i ) { obj = (IDfSysObject)list.get( i ); System.out.println( obj.getObjectId().toString() ); System.out.println( obj.getObjectName() ); } } finally { sMgr.release( session ); } }
29
XML Processing
The statement in the example under the comment Set node properties tells DFC not to determine the controlling XML application automatically but instead to use the application called CellPhoneCatalog. You can import XML files without doing XML processing. If nodeImport is an IDfImportNode object, you can turn off XML processing on the node and all its descendants by calling
nodeImport.setFormat(dm_document);
This also turns off content detection, so the operation does not recognize embedded OLE objects. Turning off these kinds of processing can shorten the time it takes DFC to perform the operation.
The list contains the object IDs of the newly created SysObjects. In addition, the IDfImportNode objects associated with the operation are still available after you execute the operation (see Working With Nodes, page 27). You can use their methods to find out many other facts about the new SysObjects associated with those nodes. For example, you can find out object IDs, object names, version labels, file paths, and formats.
Exporting
The execute method of an IDfExportOperation object creates copies of documents on the local file system. If the operations add method receives a virtual document as an argument, it also adds all of the documents descendants (determined by applying the applicable binding rules), creating a separate node for each.
Example 22. Exporting a document to the default checkout directory
This example does not create registry information about the resulting file.
void testExport1( IDfClientX clientx, // factory for operation IDfId idDoc, // id of document to export String strDir ) // destination directory throws DfException { // Construct a new export operation IDfExportOperation opExport = clientx.getExportOperation(); // Add the document and cast the node to the appropriate type IDfExportNode node = (IDfExportNode)opExport.add( idDoc ); // Set properties on the node node.setFilePath( strDir );
30
node.setRecordInRegistry( IDfExportOperation.DONT_RECORD_IN_REGISTRY ); if( node == null ) { // See Handling Document Manipulation Errors, page 41 // Execute the operation if( !opExport.execute() ) { // See Handling Document Manipulation Errors, page 41
Checking Out
The execute method of an IDfCheckoutOperation object checks out the Docbase documents in the operation. Checking out a document is like exporting one, but the checkout operation: Locks the document Always creates registry entries to enable DFC to manage the files it creates on the file system
If the operations add method receives a virtual document as an argument, it also adds all of the documents descendants (determined by applying the applicable binding rules), creating a separate node for each.
Example 23. Checking out a virtual document
31
doc.asVirtualDocument( "CURRENT", false ); // Add the vDoc and all of its nodes IDfCheckoutNode node = (IDfCheckoutNode)checkout.add( vDoc ); if( node == null ) { // See Handling Document Manipulation Errors, page 41 } // Execute the operation if( !checkout.execute() ) { // See Handling Document Manipulation Errors, page 41 }
Checking In
The execute method of an IDfCheckinOperation object checks documents into the repository. It creates new objects as required, transfers the content to the repository, and removes local files if appropriate. It checks in existing objects that any of the nodes refer to (for example, through XML links).
Example 24. Checking in a document
Check in a document as the next minor version, setting the version labels to DRAFT and WIP, and taking the content from C:/myfile.doc.
void testCheckinDoc( IDfClientX clientx, // factory for operation IDfDocument doc, // checked out doc to version String strFileName ) // Check in "From" file throws DfException // Construct a new checkin operation IDfCheckinOperation checkin = clientx.getCheckinOperation(); // Set operation properties checkin.setCheckinVersion( IDfCheckinOperation.NEXT_MINOR ); checkin.setVersionLabels( "DRAFT,WIP" ); // Add the document to the operation IDfCheckinNode node = (IDfCheckinNode)checkin.add( doc ); if( node == null ) { // See Handling Document Manipulation Errors, page 41 } // Set the node properties (same as "Check In From File") node.setFilePath( strFileName ); // like: "C:/myFile.doc" // Execute the operation if( !checkin.execute() ) { // See Handling Document Manipulation Errors, page 41 }
32
IDfList list = checkin.getNewObjects(); int count = list.getCount(); if( count == 1 ) { IDfId idObj = node.getNewObjectId(); } else { for( int i = 0; i < count; ++i ) processObject( list.getId( i ) ); { } } }
After executing this code, you can obtain the ID of the document you just checked in:
IDfId newId = node.getNewObjectId();
The list contains the object IDs of the newly created SysObjects. In addition, the IDfCheckinNode objects associated with the operation are still available after you execute the operation (see Working With Nodes, page 27). You can use their methods to find out many other facts about the new SysObjects associated with those nodes.
33
Cancelling Checkout
The execute method of an IDfCancelCheckoutOperation object cancels the checkout of documents by releasing locks, deleting local files if appropriate, and removing registry entries. If the operations add method receives a virtual document as an argument, it also adds all of the documents descendants (determined by applying the applicable binding rules), creating a separate operation node for each.
Example 25. Cancelling checkout
Copying
The execute method of an IDfCopyOperation object copies the current versions of documents or folders from one repository location to another. If the operations add method receives a virtual document as an argument, it also adds all of the documents descendants (determined by applying the applicable binding rules), creating a separate node of the operation for each. If the add method receives a folder (unless you override this default behavior), it also adds all documents and folders linked to that folder. This continues recursively until
34
the entire hierarchy of documents and subfolders under the original folder is part of the operation. The execute method replicates this hierarchy at the target location.
Example 26. Copying a folder void testCopyDocbaseFolder( IDfClientX clientx, // factory for op IDfSession session, // used to fetch objs IDfFolder folderSource, // copy from IDfId idDestinationFolder ) // copy to throws DfException { IDfCopyOperation copy = clientx.getCopyOperation(); copy.setDestinationFolderId( idDestinationFolder ); // copy.setDeepFolders( true ); // same as default // copy.setCopyPreference( IDfCopyOperation.COPY_COPY ); IDfCopyNode node = (IDfCopyNode)copy.add( folderSource ); if( node == null ) { // See Handling Document Manipulation Errors, page 41 } node.setNewObjectName( null ); // same as default = same name // Execute the operation if( !copy.execute() ) { // See Handling Document Manipulation Errors, page 41 } // Process the copy operation results... IDfList list = copy.getNodes(); int count = list.getCount(); IDfSysObject sysobj; IDfId idNewFolder; String strNewFolder; IDfId idNewObject; String strIdNewObject; String strNewObjectName; IDfFolder folder; for( int i = 0; i < count; ++i ) { node = (IDfCopyNode)list.get( i ); idNewObject = node.getNewObjectId(); strIdNewObject = idNewObject.toString(); strNewObjectName = node.getNewObjectName(); idNewFolder = node.getDestinationFolderId(); folder = (IDfFolder)session.getObject( idNewFolder ); strNewFolder = folder.getObjectName(); System.out.println( i + ". " ); System.out.print( strIdNewObject + ", " ); System.out.print( strNewObjectName + ", " ); System.out.println( strNewFolder ); System.out.println( System.getProperty ( "line.separator" ) ); } }
35
Moving
The execute method of an IDfMoveOperation object moves the current versions of documents or folders from one repository location to another by unlinking them from the source location and linking them to the destination. Versions other than the current version remain linked to the original location. If the operations add method receives a virtual document as an argument, it also adds all of the documents descendants (determined by applying the applicable binding rules), creating a separate node for each. If the add method receives a folder (unless you override this default behavior), it adds all documents and folders linked to that folder. This continues recursively until the entire hierarchy of documents and subfolders under the original folder is part of the operation. The execute method links this hierarchy to the target location.
Example 27. Moving a virtual document void testMoveVDoc( IDfClientX clientx, // for operation factory IDfDocument doc, // doc to move IDfId idSrcFolder, // move from folder IDfId idDestFolder ) // move to folder throws DfException { IDfMoveOperation move = clientx.getMoveOperation(); move.setSourceFolderId( idSrcFolder ); move.setDestinationFolderId( idDestFolder ); // Convert the document to a node tree IDfVirtualDocument vDoc = doc.asVirtualDocument( "CURRENT", false ); IDfMoveNode node = (IDfMoveNode)move.add( vDoc ); if( node == null ) { See Handling Document Manipulation Errors, page 41 } // Execute the operation if( !move.execute() ) { // See Handling Document Manipulation Errors, page 41 } }
Deleting
The execute method of an IDfDeleteOperation object removes documents and folders from the repository.
36
If the operations add method receives a virtual document as an argument, it also adds all of the documents descendants (determined by applying the applicable binding rules), creating a separate node for each.
Example 28. Deleting a document void testDeleteDoc( IDfClientX clientx, // for operation factory IDfDocument doc ) // doc to delete throws DfException { IDfDeleteOperation opDelete = clientx.getDeleteOperation(); IDfDeleteNode node = (IDfDeleteNode)opDelete.add( doc ); if( node == null ) { See Handling Document Manipulation Errors, page 41 } // Execute the operation if( !opDelete.execute() ) { // See Handling Document Manipulation Errors, page 41 } } Example 29. Deleting all versions of all documents
Delete all versions of all documents in a folder. Assume that folder is an object of type IDfFolder and cX, an IDfClientX object, is a factory for operations.
void testDeleteFolder( IDfClientX clientx, // for operation factory IDfFolder folder ) // folder to delete throws DfException { IDfDeleteOperation opDelete = clientx.getDeleteOperation(); // Tell DFC to delete all version of the objects. // Note: Set this before you add the documents or folders. opDelete.setVersionDeletionPolicy( IDfDeleteOperation.ALL_VERSIONS ); IDfDeleteNode node = (IDfDeleteNode)opDelete.add( folder ); if( node == null ) { // See Handling Document Manipulation Errors, page 41 } // Execute the operation if( !opDelete.execute() ) { // See Handling Document Manipulation Errors, page 41 } }
37
38
Transform the file C:/NewsMLNewsletter.xml into an HTML file C:/ NewsMLNewsletter.htm, using an XSLT stylesheet from the Docbase.
void testTransformXml2HtmlUsingStylesheetObject( IDfClientX clientx, // for operation factory IDfSession session, // required for transformation IDfDocument docStylesheet ) // XSL stylesheet in Docbase throws DfException, IOException { IDfXMLTransformOperation transform = clientx.getXMLTransformOperation(); transform.setSession( session ); transform.setTransformation( docStylesheet ); FileOutputStream out = new FileOutputStream( "C:\NewsMLNewsletter.htm" ); transform.setDestination( out ); IDfXMLTransformNode node = (IDfXMLTransformNode) transform.add( "C:\NewsMLNewsletter.xml" ); if( node == null ) { // See Handling Document Manipulation Errors in
Transform the file C:/NewsMLNewsletter.xml into a new HTML document in the repository, using the XSLT stylesheet C:/NewsMLStylesheet.xsl, and import it into the Docbase.
void testTransformationXml2UsingStylesheetFile( IDfClientX clientx, // for operation factory IDfSession session, // required for transformation IDfId idDestFolder ) // dest folder id throws DfException { IDfXMLTransformOperation opTransform = clientx.getXMLTransformOperation(); opTransform.setSession( session ); opTransform.setTransformation( "C:/NewsMLStylesheet.xsl" ); IDfImportOperation opImport = clientx.getImportOperation(); opImport.setSession( session );
39
opImport.setDestinationFolderId( idDestFolder ); opTransform.setDestination( opImport ); IDfXMLTransformNode nodeTransform = (IDfXMLTransformNode) opTransform.add( "C:/ContractInfo.xml" ); if( nodeTransform == null ) { // See Handling Document Manipulation Errors in
Transform an XML document into an HTML rendition, using an XSLT stylesheet from the Docbase.
void testTransformationXml2HtmlRendition( IDfClientX clientx, // for operation factory IDfSession session, // required for transformation // String strOutputDir, // directory to put HTML file in IDfDocument docXml, // root of the XML document IDfDocument docStylesheet ) // XSL stylesheet in Docbase throws DfException { IDfXMLTransformOperation opTransform = clientx.getXMLTransformOperation(); opTransform.setSession( session ); opTransform.setTransformation( docStylesheet ); IDfXMLTransformNode nodeTransform = (IDfXMLTransformNode) opTransform.add( docXml ); if( nodeTransform == null ) { // See Handling Document Manipulation Errors in
40
You must use the operations setSession method to specify a Docbase session. This operation requires a session, even if all of the files it operates on are on the file system. The add method of an IDfXMLTransformOperation object accepts Java types as well as Documentum types. It allows you to specify the file to transform as an object of any of the following types: IDfDocument IDfFile String (for example C:/PhoneInfo.xml) InputStream Reader URL
41
42
node = error.getNode(); idNodesObj = this.getObjectId( session, node ); if( null == idNodesObj ) continue; strNodeId = idNodesObj.getId(); strNodeName = session.apiGet( "get", strNodeId + ",object_name" ); message += "Node: [" + strNodeId + "], " + strNodeName + ", " + error.getMessage() + ", " + error.getException().toString(); } } catch( Exception err ) { message += err.toString(); } finally { // Create a DfException to report the errors e = new DfException(); e.setMessage( message ); } return e; }//end: generateOperationException(...) /** * Obtains the IDfId of the object represented by this node. * * IDfOperationNode publicly exposes a getId() method but * it only the id of the node, not the object_id of the * sysobject represented by the node. * * To obtain the object_id of the nodes sysobject, * you can write this method and then call it as follows: * * Assume you have obtained a node reference from other means * like, iterating through the operation errors, or op.getNodes() * list, etc... * * IDfId id = this.getObjectId( node ); * if( id == null ) * { // skip this node // * { * // use the id... * */ IDfId getObjectId( IDfSession session, IDfOperationNode node ) { try { return node instanceof IDfImportNode ? ((IDfImportNode)node).getObjectId() : node instanceof IDfExportNode ? ((IDfExportNode)node).getObjectId() : node instanceof IDfCheckoutNode ? ((IDfCheckoutNode)node).getObjectId() : node instanceof IDfCheckinNode ? ((IDfCheckinNode)node).getObjectId() : node instanceof IDfCancelCheckoutNode ? ((IDfCancelCheckoutNode)node).getObjectId() : node instanceof IDfDeleteNode ? ((IDfDeleteNode)node).getObjectId() : node instanceof IDfCopyNode ? ((IDfCopyNode)node).getObjectId()
43
node instanceof IDfMoveNode ? ((IDfMoveNode)node).getObjectId() : null; } catch( Exception e ) { } return null; } // end: getObjectId() IDfId getNodesObjId( IDfOperationNode node ) { try { return node instanceof IDfImportNode ? ((IDfImportNode)node).getObjectId() : node instanceof IDfExportNode ? ((IDfExportNode)node).getObjectId() : node instanceof IDfCheckoutNode ? ((IDfCheckoutNode)node).getObjectId() : node instanceof IDfCheckinNode ? ((IDfCheckinNode)node).getObjectId() : node instanceof IDfCancelCheckoutNode ? ((IDfCancelCheckoutNode)node).getObjectId() : node instanceof IDfDeleteNode ? ((IDfDeleteNode)node).getObjectId() : node instanceof IDfCopyNode ? ((IDfCopyNode)node).getObjectId() : node instanceof IDfMoveNode ? ((IDfMoveNode)node).getObjectId() : null; } catch( Exception e ) { } return null; } // end: getObjectId() IDfSysObject getNodesSysObject( IDfSession session, IDfOperationNode node ) { try { IDfId idNodesObj = node instanceof IDfImportNode ? ((IDfImportNode)node).getObjectId() : node instanceof IDfExportNode ? ((IDfExportNode)node).getObjectId() : node instanceof IDfCheckoutNode ? ((IDfCheckoutNode)node).getObjectId() : node instanceof IDfCheckinNode ? ((IDfCheckinNode)node).getObjectId() : node instanceof IDfCancelCheckoutNode ? ((IDfCancelCheckoutNode)node).getObjectId() : node instanceof IDfDeleteNode ? ((IDfDeleteNode)node).getObjectId() : node instanceof IDfCopyNode ? ((IDfCopyNode)node).getObjectId() : node instanceof IDfMoveNode ? ((IDfMoveNode)node).getObjectId() : null; if( idNodesObj != null ) { return (IDfSysObject)session.getObject( idNodesObj ); } } catch( Exception e ) { } return null; }// end getNodesSysObject()
44
You can undo most operations by calling an operations abort method. The abort method is specific to each operation, but generally undoes Docbase actions and cleans up registry entries and local content files. Some operations (for example, delete) cannot be undone. If you know an operation only contains objects from a single Docbase, and the number of objects being processed is small enough to ensure sufficient database resources, you can wrap the operation execution in a transaction.
45
46
47
Session Manager
To use managed sessions, you must obtain a session manager, that is, an object that implements the IDfSessionManager interface. Use the newSessionManager method of IDfClient to obtain a session manager. The session manager you obtain is for your application only. You can destroy or abandon it when you are done with it. Once you have a session manager, you must provide it with the appropriate authentication information. You can do this in either of the following ways: Supply login credentials for each Docbase with which you expect the session manager to provide sessions. Supply a principal identity. A principal identity is a user account recognized by all Docbases with which you expect the session manager to provide sessions. In order to use this facility you must provide a mechanism to allow the named user account to authenticate itself with the session manager. Thereafter, the session manager uses its own highly privileged user account to establish sessions on the named accounts behalf. The IDfSessionManager interface provides methods and exception classes to enable you to: Acquire and release sessions Process transactions Authenticate users Temporarily prevent reassignment of sessions Obtain diagnostic data (statistics). Catch checked and unchecked exceptions.
Session Pool
The Documentum server provides a connection pooling capability to minimize the overhead of connecting and disconnecting sessions. The Server Fundamentals and Server Administration Guide manuals explain how connection pooling works and how to configure it. When you enable connection pooling, a session manager controls a pool of sessions to Docbases. In general, it maintains one session per Docbase, sharing that session among all callers that refer to that Docbase. When you release a session that the session manager gives you, it waits a specified interval before disconnecting it. If you request another session within that interval, you will in general get back the session you releasedwith negligible processing overhead. Transactions and multi-threading cause exceptions to this rule. The fact that obtaining and releasing sessions entails negligible processing overhead leads to the following best practice for working with managed sessions: Tip Ask the session manager for a session when you need one, and release the session back to the session manager as soon as you finish the Docbase interaction for which you obtained the session.
48
When the Java garbage collector collects a session manager object, it checks for pending sessions and writes a message to the log file if it finds any. Once you release a session, you should not refer to persistent objects that you obtained from that session. This is true of both unmanaged and managed sessions. With unmanaged sessions, you catch this bug immediately, because the session disappears as soon as you disconnect it. With managed sessions, however, you can sometimes run into a hard to detect bug. Because the session manager does not immediately disconnect a session that you release, you can successfully refer to a persistent object attached to a released session for an indeterminate interval of time after you release the session. For example:
1 private void Method1( String DocbaseName, IDfId idDoc, 2 IDfSessionManager sMgr ) 3 { 4 IDfSession session = sMgr.getSession( strDocbaseName ); 5 IDfPersistenObject doc = session.getObject( idDoc ); 6 sMgr.release(session); 7 Method2( DocbaseName, doc ); 8 } 9 private void Method2( String DocbaseName, 10 IDfPersistentObject doc ) 11 { 12 String name = doc.getObjectName();
49
13 }
Sometimes line 12 works and sometimes it does not. During debugging, you can detect problems of this sort by setting the DebugSessionManager system property of the Java virtual machine.
java -D DebugSessionManager -classpath %classpath% YourProgram
This causes the session manager to disconnect the session as soon as you release it, or after a short interval even if you dont release it (to simulate server timeouts). Setting this property ensures that line 12 always fails.
Multiple Docbases
The session manager is able to manage connections to different Docbases transparently. For this behavior, the client application must register different identities (IDfLoginInfo / Docbase pairs) for the different Docbases, in which case the session manager uses the appropriate IDfLoginInfo object for each Docbase. The following example shows calling the same service for different Docbases:
IDfClient client = IDfSessionManager sMgr.setIdentity( sMgr.setIdentity( DfClient.getLocalClient(); sMgr = client.newSessionManager(); strDocbase1, loginInfo ); strDocbase2, loginInfo );
The following example shows calling services in different Docbases using a principal:
IDfClient client = DfClient.getLocalClient(); IDfSessionManager sMgr = client.newSessionManager(); sMgr.setPrincipalName( principal ); IMyService anyService = (IMyService) client.newService( IMyService.class.getName(), sMgr); anyService.call(strDocbase1); anyService.call(strDocbase2);
50
the same, and has the same password, in every Docbase you wish to connect to. You must provide an authentication mechanism to deliver the user name and password to the session manager. The session manager then acts on the principals behalf to obtain the necessary sessions. After you define identitiesmanual or principalyou pass only the Docbase name to the session manager. It handles authentication with the Docbase transparently.
You can specify one identity per Docbase. Note: Consecutive calls to the setIdentity method specifying the same Docbase cause the method to throw DfServiceException. If you need to change the identity associated with a Docbase, call the clearIdentity method first. You can use the authenticate method of IDfSessionManager to authenticate an identity. In some cases, you may want to authenticate users immediately (for example, in a login dialog). In this case, you can call the authenticate method after you define the identity. The session manager tries to connect to the Docbase and throws DfAuthenticationException if the Docbase rejects the login information. For example:
IDfClient client = DfClient.getLocalClient(); IDfSessionManager sMgr = client.newSessionManager(); sMgr.setIdentity( strDocbase, loginInfo ); sMgr.authenticate( strDocbase );
Note: When using a session manager in a web application, protect security by using a separate session manager instance for each user session. Use the clearIdentity method to remove the identity for a Docbase or clearIdentities to remove the identities for all Docbases. To check for a specific user identity registered in the Session Manager for a given Docbase, use the hasIdentity method, or you can retrieve all the identities for a specified Docbase by using the getIdentities method. You can obtain a list of Docbases for which the session manager has identities by using the getDocbases method of IDfSessionManagerStatistics. You can obtain a
51
The following example demonstrates how to set a Docbase identity, call a method, and disconnect from that Docbase using the session manager:
void test() { IDfClient client = DfClient.getLocalClient(); IDfSessionManager sMgr = client.newSessionManager(); sMgr.setIdentity( strDocbase, loginInfo ); IMyService anyService = (IMyService) client.newService( IMyService.class.getName(), sMgr ); anyService.serviceMethod( strDocbase ); sMgr.clearIdentity( strDocbase ); }
52
4 5 6 7 8 9 10 11 12 13 14 }
strPrincipalName ); IDfLoginInfo loginUser = new DfLoginInfo(); loginUser.setUser( strPrincipalName ); loginUser.setPassword( strTicket ); IDfSession sessionUser = client.getSession( strDocbaseName, loginUser ); return sessionUser; // good for about 5 minutes. (depending on // server settings you might not control)
DFC does not turn on principal support by default. To enable principal support, you must call the setPrincipalSupport method:
client.setPrincipalSupport ( new YourPrincipalSupport(loginSuper) );
When calling the setPrincipalSupport method, supply a reference to an active IDfLoginInfo of a superuser or system administrator. The principal support object can save this login information object in its memory:
IDfLoginInfo loginInfo = new DfLoginInfo(); loginInfo.setUser(superuser); loginInfo.setPassword(superuserPasswd); DfSessionManager sMgr = new DfSessionManager(); client.setPrincipalSupport(new SamplePrincipalSupport(loginInfo));
DFC uses principal support to generate a session for the principal. The principal service support interface IDfPrincipalSupport defines a method getSession that returns the DFC session for a given Docbase/principal combination. It is up to the implementation to obtain the trusted identity. Documentum provides a class, SamplePrincipalSupport, that implements the IDfPrincipalSupport interface. The constructor takes the login information of a user with sufficient permissions to generate login tickets for users. That user must have the same login credentials for all Docbases, and the service must obtain those credentials to get started. This class is for illustration purposes only. Documentum recommends that for production use you implement a class that meets all of your companys security criteria.
53
Setting a Principal Identity The setPrincipalName method sets the principal name. The method takes the principal name as a string, not as a Principal object. Once you register a principal name, DFC uses it for all Docbases that you access. It is not possible to define a principal for a specific Docbase. Each call to setPrincipalName replaces the previous value. Pass null to reset the principal name. The following code shows how to set the principal name:
IDfClient client = DfClient.getLocalClient(); IDfSessionManager sMgr = client.newSessionManager(); sMgr.setPrincipalName( strPrincipalName );
Note: When you set both principal and manual identities, DFC uses the manual identity for user authentication. The getPrincipalName method returns the principal name, or null if no principal is defined.
54
This chapter describes the way to use DFC to create and perform queries and to process the results. The examples in it are based on the class DfExSimpleQuery, which is available in Java and Visual Basic versions on http://www.documentum.com/developer/samplecode.htm. You can find out more about queries by examining the DfExFullTextQuery class. This manual does not contain examples from that class.
Queries
DFC provides an easy-to-use mechanism for querying the Docbase and processing the query results. You use a query object to submit the query, and receive the results in a collection object.
1. 2. 3.
Obtain an IDfClient interface by calling DfClient.getLocalClient. Create a session, sess, by calling newSession or getSharedSession on the IDfClient object. Obtain an IDfQuery object, q: For Java-based DFC programs, call new DfQuery. For Visual Basic and C++ programs, call the getQuery method of IDfClientX.
4. 5. 6.
Create a DQL query as a text string, dq. Call q.setDQL(dq) to set the DQL string into the query object. Call q.execute(sess, querytype) to execute the query.
The arguments of the execute method include a session reference, because the query is not tied to the session, and a code for the type of query to execute. The method returns an IDfCollection, col. The session remains locked until the execute method returns.
55
7.
Obtain values from an IDfCollection by calling the various get methods of IDfTypedObject (the parent type of IDfCollection). For example, if you know that attribute 0 of the object at the current row of the collection is a string, the following code prints it:
IDfAttr attr = col.getAttr(0) System.out.println(typedObj.getString(attr.getName()))
If you dont know that the attribute is a string, you can find out what it is by calling
attr.getDataType()
and changing the second line above according to what getDataType returns. 8. Close the IDfCollection and IDfSession objects.
IDfQuery has no close method, because a query object is not tied to a session. Note: The number of sessions available to an application is limited. If you do not close them, you make it more likely that you will exhaust the supply. Be careful to close open collections and sessions even in the event of an exception. The best place for a Java program to call close is in a finally block, because Java executes a finally block whether there is an exception or not.
IDfQuery
An IDfQuery object holds a DQL query string and allows you to perform that query in any session. You pass the session and the query to the execute method, and it returns results as an IDfCollection object.
IDfCollection
An IDfCollection object is like an SQL cursor. It contains references to the objects that the query returns, in an ordered sequence of rows. The collection points to one row of data at a time. You must call next before accessing the first row (if the collection is empty, the first call to next returns False). Note: An IDfCollection is a typed object. You access the current rows data by calling the IDfTypedObject methods getBoolean, getInt, getString, and so forth, as if the collection were the same as its current row. You should not, and do not need, to call the collections getTypedObject method unless you want to save the current row for later use (compare the code in IDfCollection, page 56, which does not call getTypedObject, with the code in displayResults in Visual Basic, page 57, which does call getTypedObject).
56
Initialize return value Create query object Give it the query string Execute the query and get back a collection Set the return value
57
Else ERROR ACTION End If Next i Wend col.Close Exit Sub ErrorHandler: writeDiagnostic Err.Description, False End Sub
execQuery in Java
IDfCollection execQuery(IDfSession sess, String queryString) { IDfCollection col = null; //For the result try { IDfQuery q = new DfQuery(); //Create query object q.setDQL(queryString); //Give it the query col = q.execute(sess, DfQuery.DF_READ_QUERY); //Execute synchronously } catch (DfException dfe) { System.out.println("\n" + dfe.toString()); } return col; }
displayResults in Java
//Step through a collection and display results void displayResults(IDfCollection col) throws IOException { try { int resItems = 1; while (col.next()) { System.out.println("\nResult row: " + resItems++); for (int i = 0; i < col.getAttrCount(); i++) { IDfAttr attr = col.getAttr(i); System.out.print("\t" + attr.getName() + ": "); if (attr.getDataType() == attr.DM_BOOLEAN) { System.out.println( col.getBoolean(attr.getName())); } else if (attr.getDataType() == attr.DM_DOUBLE) { System.out.println( col.getDouble(attr.getName())); } else if (attr.getDataType() == attr.DM_ID) { System.out.println( col.getId(attr.getName()).toString()); } else if (attr.getDataType() == attr.DM_INTEGER) { System.out.println( col.getInt(attr.getName())); } else if (attr.getDataType() == attr.DM_STRING) { System.out.println( col.getString(attr.getName())); } else if (attr.getDataType() == attr.DM_TIME) { System.out.println( col.getTime(attr.getName()).toString()); } else { //ERROR ACTION
//Count rows //Display row num //For attribute // Display name // Display value // using method // for its type
58
//Close collection
59
60
This chapter describes the way to work with Documentum features that help you automate your business rules. The examples in it are based on the classes DfExSimpleValidation andDfExACL, which are available in Java and Visual Basic versions at http://www.documentum.com/developer/ samplecode.htm. Documentum provides other ways to automate business rules (for example workflows and document lifecycles). The Documentum Content Server Fundamentals manual describes those facilities. This manual does not contain examples of using DFC to work with workflows and document lifecycles. This chapter contains the following main sections: Checking Objects Against Validation Rules, page 61 Changing Permissions, page 62 Using Private ACLs, page 64 ACL Utility Methods, page 65
61
// validate the value of the specific attribute validator.validateAttrRules(attrName, null, null); } } catch (DfException dfe) { System.out.println("\n" + dfe.toString()); } }
Changing Permissions
changeBasicPermissions in Visual Basic
Change and display object permissions Sub changeBasicPermissions( sess As IDfSession, Session objId As String, ID of obj for which to change permissions anotherUser As String) A user to whom to assign permissions Dim clientx As New DfClientX Dim sysObjId As IDfId Dim sysObj As IDfSysObject Dim pObj As IDfPersistentObject On Error GoTo ErrorHandler Use ID string to obtain the ID, then the object Set sysObjId = clientx.getId(objId) Set sysObj = sess.GetObject(sysObjId) displayBasicPermissions sysObj Display the objects permissions sysObj.grant anotherUser, 6, "" Grant the user and dm_world sysObj.grant "dm_world", 6, "" WRITE permission Set pObj = sysObj Make the object persistent pObj.save then save it displayBasicPermissions sysObj Display the objects permission sysObj.revoke anotherUser, "" Revoke the users permissions sysObj.grant "dm_world", 3, "" Grant dm_world READ permission Set pObj = sysObj Make the object persistent pObj.save then save it displayBasicPermissions sysObj Display the objects permission Set sysObjId = Nothing Free memory Set sysObj = Nothing Exit Sub ErrorHandler: writeDiagnostic Err.Description, False End Sub
62
Use ID string to obtain the ID, then the object Set sysObjId = clientx.getId(objId) Set sysObj = sess.GetObject(sysObjId) displayExtendedPermissions sysObj sysObj.grant anotherUser, 6, "CHANGE_STATE" Set pObj = sysObj pObj.save displayExtendedPermissions sysObj sysObj.revoke anotherUser, "CHANGE_STATE" sysObj.revoke anotherUser, "" Set pObj = sysObj pObj.save displayExtendedPermissions sysObj Set sysObjId = Nothing Set sysObj = Nothing Exit Sub ErrorHandler: writeDiagnostic Err.Description, False End Sub
Display the ext Grant WRITE and Make the object then save it Display the ext
Make the object persistent then save it Display the ext permissions Free memory
changeBasicPermissions in Java
//Change and display object permissions void changeBasicPermissions( IDfSession sess, //Session String objId, //ID of obj for which to change permissions String anotherUser) //A user to whom to assign permissions throws IOException { try { //Use ID string to obtain the ID, then the object IDfId sysObjId = new DfId(objId); IDfSysObject sysObj = (IDfSysObject)sess.getObject(sysObjId); displayBasicPermissions(sysObj); //Display the objects permissions //Grant the user and dm_world WRITE permission sysObj.grant( anotherUser, 6, ""); sysObj.grant("dm_world", 6, ""); sysObj.save(); //Save the object displayBasicPermissions(sysObj); //Display the objects permissions //Revoke the users permissions and grant dm_world READ permission sysObj.revoke(anotherUser, ""); sysObj.grant ("dm_world", 3, ""); sysObj.save(); //Save the object displayBasicPermissions(sysObj); //Display the objects permissions } catch (DfException dfe) { System.out.println("\n" + dfe.toString()); } }
changeExtendedPermissions in Java
//Change and display extended object permissions void changeExtendedPermissions( IDfSession sess, //Session String objId, //ID of obj for which to change permissions String anotherUser) //A user to whom to assign permissions throws IOException { try { //Use ID string to obtain the ID, then the object
63
IDfId sysObjId = new DfId(objId); IDfSysObject sysObj = (IDfSysObject)sess.getObject(sysObjId); displayExtendedPermissions(sysObj); //Display the ext permissions //Grant the user WRITE and CHANGE_STATE permissions sysObj.grant(anotherUser, 6, "CHANGE_STATE"); sysObj.save(); displayExtendedPermissions(sysObj); sysObj.revoke(anotherUser, "CHANGE_STATE"); sysObj.revoke(anotherUser, ""); sysObj.save(); displayBasicPermissions(sysObj); } catch (DfException dfe) { System.out.println("\n" + dfe.toString()); } } //Save the object //Display the ext permissions //Revoke users CHANGE_STATE //Revoke users basic perms //Save the object //Display the ext permissions
64
Set oldACL = Nothing Set newACL = Nothing Exit Sub ErrorHandler: writeDiagnostic Err.Description, False End Sub
privateACLs in Java
//Create a private ACL and apply it to an object void privateACLs( IDfSession sess, //Session String objId //Object with which to associate the ACL String permission, //Permission to grant to world and owner String extPermission, //Ext permissions to grant world and owner String aclName //Name of ACL to create ) throws IOException { try { //Use ID string to obtain the ID, then the object IDfId sysObjId = new DfId(objId); IDfSysObject sysObj = (IDfSysObject)sess.getObject(sysObjId); //Create a new ACL object and give it the specified name IDfPersistentObject pObj = (IDfPersistentObject)sess.newObject("dm_acl"); pObj.apiSet("set", "object_name", aclName); //Grant the specified permissions to owner and world pObj.apiExec("grant", "dm_owner," + permission + "," + extPermission); pObj.apiExec("grant", "dm_world," + permission + "," + extPermission); pObj.save(); //Save the new private ACL IDfACL oldACL = sysObj.getACL(); //Save the objects current ACL // Instantiate an instance of the new private ACL IDfACL newACL = sess.getACL(sess.getLoginUserName(), aclName); sysObj.setACL(newACL); //Apply new ACL to the sysobject sysObj.save(); //Save sysobject with its new ACL displayBasicPermissions(sysObj); //Display new permissions displayExtendedPermissions(sysObj); sysObj.setACL(oldACL); //Apply old ACL to the sysobject sysObj.save(); //Save sysobj with restored ACL displayBasicPermissions(sysObj); //Display restored permissions displayExtendedPermissions(sysObj); } catch (DfException dfe) { System.out.println("\n" + dfe.toString()); } }
65
ElseIf permission = "6" Then permissionToString = "WRITE" ElseIf permission = "7" Then permissionToString = "DELETE" End If Exit Function ErrorHandler: writeDiagnostic Err.Description, False End Function
66
writeDiagnostic " ACL Name: " + sysObj.getACLName, False For i = 0 To (sysObj.getAccessorCount - 1) writeDiagnostic " Accessor: " + sysObj.getAccessorName(i) + " Extended Permissions: " + sysObj.getAccessorXPermitNames(i), False Next i Exit Sub ErrorHandler: writeDiagnostic Err.Description, False End Sub
permissionToString in Java
//Convert permission code to name String permissionToString(String permission) { String retVal = null; if (permission.equals("1")) retVal = else if (permission.equals("2")) retVal = else if (permission.equals("3")) retVal = else if (permission.equals("4")) retVal = else if (permission.equals("5")) retVal = else if (permission.equals("6")) retVal = else if (permission.equals("7")) retVal = return retVal; }
extendedPermissionToString in Java
//Convert extended permission code to name String extendedPermissionToString(String permission) { String retVal = null; if (permission.equals("1")) retVal = "CHANGE_STATE"; else if (permission.equals("2")) retVal = "CHANGE_PERMIT"; else if (permission.equals("3")) retVal = "CHANGE_OWNER"; else if (permission.equals("4")) retVal = "EXECUTE_PROC"; else if (permission.equals("5")) retVal = "CHANGE_LOCATION"; return retVal; }
displayBasicPermissions in Java
//Display object permissions void displayBasicPermissions(IDfSysObject sysObj) { try { System.out.println( "\tACL Name: " + sysObj.getACLName());
//ACL name
67
for (int i = 0; i < sysObj.getAccessorCount(); i++) { //For each accessor System.out.println( "\tAccessor: " + //Name sysObj.getAccessorName(i) + " Permission: " + //Permission permissionToString(sysObj.getAccessorPermit(i))); } } catch (DfException dfe) { System.out.println("\n" + dfe.toString()); } }
displayExtendedPermissions in Java
//Display the objects extended permissions void displayExtendedPermissions(IDfSysObject sysObj) { try { System.out.println( "\tACL Name: " + sysObj.getACLName()); for (int i = 0; i < sysObj.getAccessorCount(); i++) { System.out.println( "\tAccessor: " + sysObj.getAccessorName(i) + " Extended Permissions: " + sysObj.getAccessorXPermitNames(i)); } } catch (DfException dfe) { System.out.println("\n" + dfe.toString()); } }
68
The Documentum business objects framework (BOF) provides a framework and a methodology for developing reusable middleware server components, called business objects, to embody and enforce business logic. This chapter introduces business objects and the benefits they provide. It contains the following major sections: Introduction to Business Objects, page 69 Service Based Business Objects, page 77 Type Based Business Objects, page 83 Documentum Business Object Registry (DBOR), page 89
69
The business logic layer implements customer specific rules and policies. These usually change infrequently, so it makes sense to separate them from code that changes more frequently. If they do change, their central location in the business logic layer ensures that dependent applications and components automatically conform to the new policy. The business logic layer is the focus of BOF. You can implement the business logic and leave session management and transaction handling to DFC. Data The data layer stores objects, content, and other information. It uses one or more content servers, with their associated relational database servers. The data layer has the following logical sublayers: Content and data schema The object hierarchy and physical schema used to store business data. The business logic layer provides an abstraction of the details of the DFC interfaces to the content and data schema. Business objects manipulate content and its metadata on behalf of the presentation layer, thereby isolating presentation logic from storage details. This leads to portable, scalable applications. Core content management services Documentum Content Server provides library services, process automation, and content authentication to the business logic layer.
Figure 61. Documentum Business Objects N-Tier Model
BOFs business objects are of the following types: Type based objects (TBOs) A TBO corresponds to a subtype of a Documentum persistent type, usually dm_document. Its DFC implementation extends the implementation class for the
70
base type. For example, com_accelera_catalog might extend dm_document and enforce its business logic by overriding methods (for example, save, checkinEx and checkoutEx) of the DFC class DfDocument. Create a TBO to provide new behavior for custom object types (for example, get or set custom attributes) or to override Documentums standard behavior (for example, override the save and checkinEx methods to enforce data validations, referential integrity and object specific business rules). Service based objects (SBOs) An SBO provides methods that are not necessarily bound to a specific object type or repository and can operate on different Documentum object types or other business objects. For example, the Documentum IInbox service manages an inbox. Use public BOF interfaces and DFC implementation classes and factory methods to build SBOs. BOF enables you (or Documentum, or a third party) to develop pluggable components, implementing middle-tier business rules. Figure 62, page 71 shows how BOF relates to the rest of DFC. Notice that the DFC core layer implements most of BOF.
Figure 62. BOF is integral to DFC
71
Use business objects to implement business logic that is: Object oriented, modular, and reusable Compatible with existing DFC code Independent of presentation
BOF Architecture
BOF provides an environment for stateless access to Docbase data from middle-tier business objects that implement business rules. Using BOF, you can write content management services that other applications begin to use automatically. You dont need to modify existing applications to ensure that they follow the business rules you embody in your business objects. Business objects can use other business objects and benefit from their implementation of other business rules. The aspects of DFC that provide business object support are compatible with existing applications. Because BOF is part of DFC, everyone accesses business objects the same way. The DFC core integrates the object factory and object registry. It also manages sessions, transactions, and user authentication. This section describes the elements of DFC that support BOF. It contains the following main subsections: Object Factory, page 72 Accessing Business Objects, page 73 Session Manager, page 75 Documentum Business Objects Registry (DBOR), page 76 Business Objects Class Hierarchy, page 76
Object Factory
The object factory constructs type based objects (TBOs) at runtime. You define TBOs to extend Docbase types (for example, dm_document), and you define their behavior by extending the corresponding DFC classes (for example, DfDocument). When you develop and deploy a TBO on your system, the framework guarantees that all software accessing this object through previous means now obtains the new extended object. For example, when a servlet uses the session.getObjectByQualification method, DFC fetches the object from the Docbase. If the FROM clause of the associated query specifies dm_sysobject, but the WHERE clause indicates instances of the TBO, the method returns an instance of your extension of DfSysObject. This happens even when the servlet accesses the Docbase with code written before you defined the TBO. When the servlet calls methods like checkout and save, and the TBO overrides these methods (for example, to add validation logic to the save method, DFC invokes the overridden methods. The object factory depends on the Documentum business objects registry (DBOR). When you create a TBO, you must register it with DBOR. Whenever you use DFC to instantiate a custom type, DFC asks DBOR if the type has an associated Java class. If so, DFC loads
72
and instantiates that class. Documentum Business Objects Registry (DBOR), page 76 provides more details about DBOR. Figure 63, page 73 shows getting access to a Docbase object through a TBO after DFC has checked with DBOR to find the Java class to construct to represent the TBO.
Figure 63. TBO Interaction Diagram
Accessing TBOs
Figure 64, page 73 shows a type based business object (TBO) becoming the client of another TBO.
Figure 64. Business Object Using Another Business Object
73
Accessing SBOs
Figure 65, page 74 shows how an SBO differs from the TBOs shown in Figure 63, page 73. Each SBO provides an interface to a group of related operations. The IDfClient interface provides a factory for SBOs. The IDfClient method checks DBOR for the service name and instantiates its associated Java class. SBOs can access objects across several Docbases. You can implement an SBO so that an application server component can call and the SBO, and the SBO can obtain and release Docbase sessions dynamically as needed.
Figure 65. SBO Interaction Diagram
74
Session Manager
DFC provides more than one way to establish sessions with Documentum servers. When accessing business objects, however, always use the DFC session manager. This facility manages resources so that you dont have to. You can (and should) acquire sessions when you need them and release them as soon as you are finished with the immediate task. If you subsequently open another session, DFC avoids the session handling overhead by invisibly managing the session pool. It also provides several ways to handle authentication, including principal identity support to enable you to implement a single login for multiple Docbases. It also provides support for transactions that can involve more than one Docbase. For web programmers, it also provides methods to associate state with the session to make session management more straightforward. An SBO should request a DFC session through the session manager and release it as soon as it no longer needs to access a Docbase. A TBO has a reference to its session as a data member. That reference can become invalid if the requesting method releases the pooled session. You can explicitly separate the TBO from the current DFC session and put the TBO under control of the session manager. This is required in cases where a stateless SBO creates a TBO, which is stateful, to return to the caller. The session manager provides a transaction facility that supports acquiring and releasing sessions quickly. For example, a program might call upon two business objects, one to create folders and a second to place files in them. Placing these two calls into a
75
transaction ensures that the entire operation, not just the individual operations, becomes atomic. DFC accomplishes this invisibly, even though each business object might use a different physical session. DFC sessions use a single-phase commit, because the underlying relational databases do not support two-phase commits. The Using DFC manual provides details of using the session manager.
At runtime, DBOR provides the appropriate class name to the DFC method, which loads and instantiates the Java class and returns the reference.
76
Figure 68, page 77 show a class diagram for a type based business object. The custom Product class extends the DFC DfSysObject class. The IProduct interface generalizes access to the Product object. The client gains access to the Product object by using the getObject, method of IDfSession, which causes the IDfClient of the framework to query DBOR registry for the class to instantiate.
Figure 68. Class Diagram for Type-based Business Objects
77
An example of an SBO is a Documentum Inbox object. It retrieves items from a users inbox and performs operations like removing and forwarding items. SBOs are similar to session beans in an Enterprise Java Beans (EJB) environment. TBOs are more like entity beans. This chapter contains the following main sections: Architecture, page 78 Rules and Guidelines, page 79
Architecture
This section describes the design time and runtime aspects of SBO architecture.
Design Time
To create an SBO, extend the com.documentum.fc.client.DfService class and implement its corresponding IDfService interface. DfService is an abstract class that implements some common methods for services. The service interface IDfService and service abstract class DfService define the following methods: getName returns a logical service name The default implementation in DfService returns the fully qualified interface name (for example, com.documentum.services.inbox.IInbox). getVersion returns the current version of the service as a string The version is a string and must match the pattern: majorVersion.minorVersion (for example, "1.0"). The method getVersion is an abstract method of the DfService class. Each service implementation must override it. getVendorString returns a stringnormally the vendors copyright statement (for example, "Copyright 1994-2002 Documentum, Inc. All rights reserved.") isCompatible checks whether the class is compatible with a specified service version This allows you to upgrade service implementations without breaking existing code. Java does not support multiple versions of interfaces. supportsFeature checks whether the class supports a specified feature. The default implementation in DfService always returns false. getSessionManager returns the services session manager handle getSession returns a DFC session object Each time you call getSession, you must subsequently call releaseSession. The default implementation in DfSession calls the session manager to return a DFC session for the given Docbase name.
78
releaseSession releases a session that you obtained with getSession. cleanupResources releases the specified resources without waiting for the Java garbage collector to do so. The default implementation does nothing.
Runtime
An SBO client application uses the newService factory method of IDfClient to instantiate a service:
public IDfService newService( String name, IDfSessionManager sMgr ) throws DfServiceException;
The factory takes the service name and a session manager as parameters, and returns the service interface, which you must downcast to the specific service interface. The newService method uses the service name to look up the Java implementation class in DBOR. It stores the session manager as a member of the service, so that the service implementation can access the session manager when it needs a DFC session. Before you create a service, you must use the newSessionManager method of IDfClient to construct an IDfSessionManager object to use as a session handle for all services.
Naming Conventions
BOF does not impose constraints on service names. However, names must be unique within a DBOR, so Documentum recommends that you use the fully qualified service interface name as the service name. This prevents naming conflicts and is more convenient for calling the factory methods. The following code shows how you can simply pass the class name to the factory method if you use the interface name as the service name:
IAutoNumber autonumber = (IAutoNumber)client.newService( IAutoNumber.class.getName(), sMgr);
79
Remember that the Java COM Bridge supports the IDispatch interface for COM programs.
80
Notice how the third example combines the stateless approach with the convenience of the first example. An ICheckinConfig object holds all parameters required for checkin and provides methods to get and set them. This is a convenient way to design a stateless interface when the calling program must provide more than a few parameters to the service.
In most cases, however, you cant anticipate the environments in which your service will be used, so it is a good practice to make the Docbase name a parameter of every method.
81
The session factory method may throw an exception to indicate one of the following problems: DfDborNotFoundException DFC cannot find DBOR. DfServiceNotFoundException DFC found DBOR, but it did not find the specified service. DfServiceInstantiationException
82
DFC found the service in DBOR, but it could not instantiate the specified Java class. This may happen if the Java class is not in the CLASSPATH or is an invalid data class. Security for Java classes on an application server may also cause this exception.
Architecture
TBOs allow you to create and enforce business rules for custom Docbase types. For this to succeed, all programs that access Docbase objects of the given type must use the methods that implement those rules. Whenever a program calls methods like newObject or getObject, DFC performs the following steps: Determine the objects Docbase type, and fetch that object along with its supertype parts. Check DBOR for a mapping between the custom type and a Java class. If such a mapping exists, instantiate the Java class, and return it to the caller. You need not downcast to the subtype to use overridden methods of IDfPersistentObject (for example, getObjectId, getString, or save), but you must downcast to the interface of the new subtype in order to call any new methods (or methods of subclasses of IDfPersistentObject). If no such mapping exists, instantiate and return the standard DFC class (for example, DfDocument).
83
Caution DFC does not perform the preceding steps if you use UPDATE queries to modify the attributes of a TBO. Thus, using UPDATE queries circumvents the business logic that the TBO implements and can lead to inconsistencies and errors. The following code samples all retrieve the same com_accelera_autonumber Docbase object and execute the code in the overridden checkout method of AutoNumberType (see ).
String strDQL = "com_accelera_autonumber where r_object_id = 091a64c18001b382"; IDfDocument number = (IDfDocument) session.getObjectByQualification( strDQL ); number.checkout(); String strDQL = "dm_document where r_object_id = 091a64c18001b382"; IDfDocument number = (IDfDocument) session.getObjectByQualification( strDQL ); number.checkout(); String strDQL = "dm_document where r_object_id = 091a64c18001b382"; IAutoNumberType number = (IAutoNumberType) session.getObjectByQualification( strDQL ); number.checkout();
Object Factory
Use the standard DFC factory methods to construct an instance of a TBO. For example,
ICatalog catalog = (ICatalog)session.newObject( "catalog" ); ICatalog catalog = (ICatalog)session.getObject( idDoc );
The session.newObject method constructs an instance of the Java class for the TBO. The factory method checks DBOR to determine which Java class to instantiate (see Documentum Business Object Registry (DBOR), page 89). For example, DBOR might map the catalog type to the com.documentum.catalog. Catalog Java class, which implements the ICatalog interface. The client application can use this interface to handle and control a catalog object. DBOR may contain multiple entries for a type. This can happen when different applications handle the same object type differently. For this reason, the IDfSession interface provides factory methods that take the interface that represents the desired behavior as an argument. For example,
ICatalog2 catalog = (ICatalog2)s.getObjectWithInterface( idDoc, ICatalog2.class.getName() );
84
String strDql = "dm_document where r_object_id = " + idDoc.getId() + ""; ICatalog2 catalog = (ICatalog2)s.getObjectByQualificationWithInterface( strDql, ICatalog2.class.getName() );
These methods look up the interface name in DBOR and instantiate the appropriate Java class. Documentum Business Object Registry (DBOR), page 89 explains how to register and access alternate implementations for a TBO.
Implement the abstract methods of the IDfBusinessObject class: getVersion, getVendorString, isCompatible, supportsFeature.
85
Table 61. IDfBusinessObject Methods to Implement IDfBusinessObject methods getVersion Description Return a constant String that describes the version (for example, "1.0") of the Java class for this object type. Return a constant String that provides copyright information (for example, "Copyright 2002, Documentum, Inc") Return True if the String passed as an argument matches a supported version. Otherwise return False. Return True if the String passed as an argument matches a supported feature. Otherwise return False.
getVendorString
isCompatible
supportsFeature
Implement new or overridden methods that embody the TBOs business rules Remember that a future TBO might extend (subclass) the class you write. Be sure to document any problems that programmers might encounter in extending your class. If you must prevent subclassing, consider defining the class to be final.
To override a method of the superclass, it is usually simplest to include a call to the method you are overriding as part of your code. For example,
public void save() { validate(); super.save(); }
Be sure to understand how DFC and other applications use the methods you are overriding. For example, DfSysObject.checkout, calls DfSysObject.checkoutEx(null, null, null). To prevent the kinds of problems that might arise if you override both, DFC declares checkin, checkout, getContent, and several other methods to be final, so that you cannot override them. Use the following guidelines to make your code as close to stateless as possible: An instance of a TBO holds a reference to a specific DFC session object, which it uses during its entire life. Keep the session manager locked to ensure that DFC does not return the session to the pool for reuse. Initiate Client Control using the beginClientControl method before obtaining or creating a TBO instance. Release Client Control using the endClientControl method when finished.
public void doSomething( IDfId idDoc ) { IDfSession session = getSession(); IDfSessionManager sMgr = getSessionManager(); try { sMgr.beginClientControl(); IDfPersistentObject obj = session.getObject( idDoc ); IAutoNumberType autoNumber = (IAutoNumberType)obj; passingObjectToAnotherMethod( obj ); }
86
finally { sMgr.endClientControl(); } }
Use the session manager for Docbase sessions whenever possible. Use the IDfTypedObject.setSessionManager method when serializing a TBO or when returning a TBO from a method of an SBO. The following example shows how to return a TBO from within an SBO method. Client Control and setSessionManager are alternative approaches to doing basically the same thing.
public IDfDocument borrow( String strDocbase, IDfId idDoc ) { IDfSession session = null; IDfDocument doc = null; try { session = getSession( strDocbase ); doc = (IDfDocument)session.getObject( idDoc ); doc.setSessionManager( getSessionManager() ); } finally { releaseSession( session ); } return doc; }
When a program calls setSessionManager, DFC performs the following actions: Copy all attributes of the object into a DFC cache on the Java side Sever the persistent object from its original DFC session Store a reference to the specified session manager object in the persistent object
The setSessionManager method allows a program to get and set attributes without communicating with the Docbase. When the program executes a method that requires such communication (for example, save, checkin, checkout), DFC automatically performs the following sequence of actions: Request a session from the session manager Fetch the persistent object Update the attributes from the DFC cache Execute the requested action Release the session
87
When calling an SBO method that returns a TBO object, use the client control mechanism (see Client Control, page 125) before and after the call.
Error Handling
The factory methods getObjectWithInterface and getObjectByQualificationWithInterface may throw the execptions shown in the following table.
Table 62. TBO Factory Method Exceptions Exception DfDborNotFoundException Cause DFC cannot find the dbor.properties file. (Check the DFC_DATA environment variable.) DFC cannot find the service in the dbor.properties file. DFC cannot instantiate the class that the dbor.properties file refers to. (If the class is valid, check the CLASSPATH and the permissions on the class.)
DfServiceNotFoundException
DfServiceInstantiationException
Best Practices
This section lists best practices for developing TBOs.
88
Overview of DBOR
The Documentum business object registry (DBOR) is a broker for business objects. Developers register business objects with DBOR, and DFC looks for registered objects at runtime. DBOR maps the Java interfaces of SBOs and the Docbase object types of TBOs to the Java classes that implement the associated business logic. DBOR lets you change implementations without changing the client applications that use the business logic. At runtime, the factory methods for TBOs and SBOs use DBOR to identify the classes to instantiate.
89
The IDfDbor interface provides methods for for adding business objects to the registry and for removing them. It provides methods for looking up TBOs by name and SBOs by interface name.
Architecture of DBOR
The files that DFC uses to implement DBOR are in a subdirectory of the directory specified by the environment variable DFC_DATA (usually C:\Documentum). Caution The information in this manual about the current implementation is subject to change without notice. It is to help you in troubleshooting your business applications. Always use the Java interfaces to work with DBOR from your application. The current implementation of DBOR uses the dbor.properties file in the DFC_DATA\config directory. You can override this location by defining a Java system property dfc.data, as follows:
java.exe -Ddfc.data="c:\Documentum" YourProgram
Deploying DBOR
You must deploy DBOR to every computer that runs DFC-based applications that might use a TBOs or SBO. For example, if you use a TBO or SBO to customize Desktop Client, you must deploy DBOR to each computer running Desktop Client. For WDK, ASP, and JSP environments, you need only deploy DBOR on the application server computers. In the current implementation, deploy DBOR by copying the dbor.properties file into the config subdirectory of the directory defined by the environment variable DFC_DATA. Developing business objects includes the following actions: Incorporate logic to ensure that future updates to your business objects do not introduce version conflicts. Construct a COM interface if a business object adds new methods to a TBO.
90
The IDispatch interface makes the classes and methods of business objects available to COM. You can also create an IDL file or a TypeLib file (.TLB). For TBOs, add the new Docbase types to the Docbase. Deploy the business objects: Copy the JAR or WAR file (archive) containing the business objects to the file system. Modify the CLASSPATH to include the archive. Update DBOR to map the associated interfaces or Docbase types to the business object Java classes.
Managing DBOR
Use the methods of the IDfDbor interface to add or remove DBOR items. You can obtain a reference to an IDfDbor object by calling the IDfClient.getDbor method. The table lists the methods of IDfDbor.
Table 63. Methods of IDfDbor Dbor Method register Description Add an IDfDborEntry for an SBO or TBO to DBOR. Throw an exception if the entry name duplicates that of an existing entry. Remove from DBOR the IDfDborEntry whose name you specify. Return the fully qualified name of the Java class that implements the specified SBO. Return the fully qualified name of the Java class that implements the specified TBO. Return an IDfEnumeration of all DBOR entries.
unregister
lookupService
lookupObject
getAll
The following Java code shows how to create and configure an IDfDborEntry:
91
boolean mapBusinessObjectToClassName( String strDborName, boolean bDborService, String strJavaClass, String strVersion ) throws DfServiceException, DfDborNotFoundException { boolean bRetVal = false; boolean bAlreadyExists = false; IDfDbor dbor = m_client.getDbor(); String strLookup = null; try { strLookup = dbor.lookupService( strDborName ); bAlreadyExists = true; } // This catch list eats all the exceptions because it expects // that any of the following conditions should still allow us // to continue. catch( DfDborNotFoundException e ) { // dbor.properties file not found } catch( DfServiceCriticalException e ) { // service found, but its a "type" } catch( DfServiceNotFoundException e ) { // service not found } // You should get here...the service should not exist if youre adding. if( !bAlreadyExists ) { try { strLookup = dbor.lookupObject( strDborName ); bAlreadyExists = true; } // This catch list eats all the exceptions because it expects // that any of the following conditions should still allow us // to continue catch( DfDborNotFoundException e ) { // dbor.properties file not found } catch( DfServiceCriticalException e ) { // "type" found, but its a "service" } catch( DfServiceNotFoundException e ) { // type not found } } if( bAlreadyExists ) { System.out.println( strDborName + " already mapped to " + strLookup ); } else { // You should expect to get here... try { String s; // if not already registered... IDfDborEntry entry = new DfDborEntry(); entry.setName( strDborName );
92
entry.setServiceBased( bDborService ); entry.setJavaClass( strJavaClass ); entry.setVersion( strVersion ); dbor.register( entry ); System.out.println( "Successful:" ); dbor = null; // unlock DBOR so lookup() can use it. beginList( strDborName ); // displays the entry bRetVal = true; } catch( DfServiceCriticalException e2 ) { // You get here if MSG_DBOR_NOT_DEFINED or MSG_SERVICE_EXISTS System.out.println( "Unable to map dbor entry" ); System.out.println( e2.toString() ); e2.printStackTrace(); bRetVal = false; } catch( DfServiceException e2 ) { // You get here if there is an (DM_VEL_DBOR_IO_ERROR) error // on the registry. System.out.println( "Unable to map dbor entry" ); System.out.println( e2.toString() ); e2.printStackTrace(); bRetVal = false; } } return bRetVal; }//end mapBusinessObjectToClassName()
93
DFC throws either a DfServiceCriticalException or a DfServiceException. The DfServiceException indicates a problem performing IO on the registry. The DfServiceCriticalException indicates bad arguments to the method, such as an empty name. The DfServiceCriticalException is a runtime exception and does not appear in the throws clause of the method signature.
94
This chapter provides step-by-step instructions for developing and deploying a type based object (TBO) and a service based object (SBO). Together, these business objects provide a simple autonumbering capability. The Simple_TBO and Simple_SBO test applications comprise a simplified solution to a real-world business problem, that of maintaining a business-wide sequential numbering system for a variety of purposes, (for example, purchase orders and invoices). This implementation maintains the numeric value used to calculate the next number in a central location and serializes access to the number so that it safely increments sequentially. Client programs that are compatible with this version of DFC immediately begin to use the implementation classes and overridden methods that you develop and deploy. This section contains the following main subsections: Getting Started with BOF, page 95 Overview of the Sample Business Objects, page 96
95
4.
Ensure that the CLASSPATH environment variable of your IDE or JVM contains dfc.jar and that the PATH variable contains the directory that contains dmcl40.dll. By default, DFC installs these files in c:\Program Files\Documentum\shared on Windows systems. If you run from within an IDE, for example, IntelliJ or Fort, you must usually make additional CLASSPATH settings.
5.
The DFC_DATA system variable must refer to the directory containing Documentum configuration information (for example, c:\Documentum).
Note: After you develop your business objects, you must make them accessible. You can place them in a jar file and add it to CLASSPATH.
To implement these extensions, you must override such methods of dm_sysobject as checkin, checkout, and save for the custom type.
96
The most important method of this service is the getUniqueNumber method, which fetches and increments the number according to the number type (PO, INV, etc.). The other methods of this service are mainly for management purposes. Another method is setNumber, used internally to set the initial number value for a given number type and to save the calculated value back to the Docbase. A fully functional service of this type provides number formatting patterns and other filters.
Figure 71. AutoNumber Schema
97
A Java class called AutoNumberType to provide methods for incrementing the number. The AutoNumberType class inherits from (extends) DfSysObject and overrides DfSysObject methods like checkin and save to guarantee that the number is always within the bounds set for its type. The class implements all of the DfSysObject methods that it overrides and also implements its own methods (getUniqueNumber, checkRange, and so forth). The classs methods use the current_number value of the Docbase object to calculate the next number in the sequence defined for the given numbering type. The class also defines members to store any other necessary persistent information (see Table 71, page 98). The AutoNumberType class has a static method, addNewAutoNumberType, that can create com_accelera_autonumber Docbase objects. This method uses the newObject factory method of IDfSession factory method to create a new instance of the com_accelera_autonumber type.
An interface, IAutoNumberType, that AutoNumberType implements. This interface exposes the public behavior of the AutoNumberType class. The interface could extend IDfSysObject, but Documentum recommends against this (see Implementation Rules, Guidelines, and Examples, page 85).
Table 71. Sample com_accelera_autonumber Objects and Their Values r_object_id name type_name current_ number 590124 30822 944 max_number
090000000101a8b7 Purchase Order 090000000101a8cb Invoice 090000000101af58 Patent Application 090000000101b032 Contract Document
PO INV DCMPAT
DCMCON
730822
99999999
The Simple_TBO class is a standalone Java application that tests AutoNumberType by obtaining and outputting the current number, causing the number to increment and storing it back into the Docbase. Simple_TBO calls the static addNewAutoNumberType method to create a new instance of the com_accelera_autonumber type if it cant find the specified type. A Simple_TBO test application is stateless from the TBO perspective, in that it executes and ends with each invocation. Running Simple_TBO from different computers will retrieve numbers in sequence relative to the com_accelera_autonumber Docbase object, independently of the computer or the Simple_TBO instance. In order to develop the TBO described here, carry out the following steps: 1. 2. 3. Create the IAutoNumberType Java interface. Create the AutoNumberType Java class. Create the com_accelera_autonumber Docbase type
98
4. 5.
Register the AutoNumberType class with DBOR. Create the Simple_TBO Java program to test the TBO.
A Simple SBO Example, page 112 shows how to develop a service-based business object (SBO) to access this TBO.
The IDfBusinessObject interface defines four abstract methods. Classes that implement the interface must provide concrete versions of these. 2. In IAutoNumberType, prototype the getUniqueNumber method.
The AutoNumberType TBO class definition wraps a Docbase object of type com_accelera_autonumber and provides methods to get and set the objects attributes. It implements methods to override the checkin and save methods of .DfSysObject The AutoNumberType class inherits all methods and properties of DfSysObject and IAutoNumberType. Through IAutoNumberType it also inherits the methods and properties of IDfBusinessObject. You need not rewrite or override inherited methods whose behavior you do not wish to alter. For example, the IAutoNumberType interface allows users of the object to call the checkin method on the interface, but does not provide new behavior.
99
Thus it declares the checkin method in the interface, but lets the class inherit the method from DfSysObject. The AutoNumberType class extends DfSysObject by changing the behavior of two of its methods, save and checkinEx, and by adding six new methods related to autonumbering. The new methods are getUniqueNumber, setNextNumber, setNumber, checkRange, validate, and addNewAutoNumberType.
/* AutoNumberType.java */ package com.accelera.autonumber; import com.documentum.fc.client.*; import com.documentum.fc.common.*; public class AutoNumberType extends DfSysObject implements IAutoNumberType { }
2.
Implement the methods of IDfBusinessObject a. In the AutoNumberType class, add the String constants to use with the getVersion and getVendorString methods.
public static final String strCOPYRIGHT = "Copyright (c) Documentum, Inc., 2003"; public static final String strVERSION = "1.0";
b.
Implement overrides for each of the four abstract methods of IDfBusinessObject, namely, getVersion, getVendorString, isCompatible, and supportsFeature, as follows:
public class AutoNumberType extends DfSysObject implements IAutoNumberType { public static final String strCOPYRIGHT = "Copyright (c) Documentum, Inc., 2002"; public static final String strVERSION = "1.0";
public String getVersion() { return strVERSION; } public String getVendorString() { return strCOPYRIGHT; } public boolean isCompatible( String s ) { return s.equals("1.0");
100
} public boolean supportsFeature( String s ) { String strFeatures = "uniquenumber, subclassing"; if( strFeatures.indexOf( s )== -1 ) return false; return true; } }
3.
Inside the AutoNumberType class, override the save and checkinEx methods of DfSysObject to call the validate method before forwarding the call to its superclass implementation.
The service, and any other user of the Docbase object modifies it using combinations of the checkout method with save or checkin. The checkin method calls checkinEx, so checkinEx is a better method to override than checkin. In any event, the checkin method is final, so you cannot override it.
public void save() throws DfException { validate(); super.save(); } public IDfId checkinEx( boolean fRetainLock, String strVersionLabels, String strOldCompoundArchValue, String strOldSpecialAppValue, String strNewCompoundArchValue, String strNewSpecialAppValue ) throws DfException { validate(); return super.checkinEx( fRetainLock, strVersionLabels, strOldCompoundArchValue, strOldSpecialAppValue, strNewCompoundArchValue, strNewSpecialAppValue ); }
Note: Certain DFC methods call other methods to perform their basic tasks. When overriding methods, try to avoid performing the same override twice by overriding the lowest level routine that performs the task you wish to alter. DFC declares some methods to be final to help you avoid overriding the wrong method. The checkin, checkout, and getContent methods of IDfSysObject are examples. When in doubt about which method to override, you might wish to perform a trace to see which methods call which in all of the environments from which you expect people to access your business object. For example, the Documentum products WDK and Desktop Client use DFC in different ways. 4. Implement the new methods of the AutoNumberType class: a. Implement the getUniqueNumber, setNextNumber, and setNumber methods.
101
The getUniqueNumber method fetches the value of its current_number attribute. The setNextNumber method increments its current_number attribute, validates that its value is within the business rules, and saves the new number into its current_number attribute. The setNumber method establishes the initial value of the current_number field. By default, Simple_TBO sets current_number to 1. Lines 22, 23, and 24 of the following example must comprise an atomic operation to ensure that the method never supplies duplicate numbers. Because Documentum does not support nested session transactions, this code requires the caller to open a managed transaction. The code on lines 13 through 18 tests for this and throws an exception if the caller has not called from within a managed transaction. Implement the methods as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public String getUniqueNumber( IDfSessionManager sMgr ) throws DfException { return setNextNumber( sMgr ); }
private String setNextNumber( IDfSessionManager sMgr ) throws DfException { String strRetVal = null; if( ! sMgr.isTransactionActive() ) { DfException e = new DfException(); e.setMessage( "no transaction available" ); throw e; } try { checkout(); // lock strRetVal = setNumber( null ); save(); // unlock and update } catch( DfException e ) { sMgr.setTransactionRollbackOnly(); e.setMessage( strRetVal + e.getMessage()); throw e; } return strRetVal; }//end setNextNumber()
public String setNumber( String strNewNumber ) throws DfException { if( strNewNumber != null ) { setString( "current_number", strNewNumber );
102
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
} else { strNewNumber = getString( "current_number" ); long n = Long.parseLong( strNewNumber ); checkRange( n+1 ); strNewNumber = String.valueOf( ++n ); setString( "current_number", strNewNumber ); } return strNewNumber; }
b.
The checkRange method checks a numeric value for validity before attempting to save it into the Docbase object. The validate method fetches the "current_number" from the object and forwards it to the checkRange method for validation. These methods throw an exception if the number does not follow the business rules.
protected void validate() throws DfException { String s = getString( "current_number" ); checkRange( Long.parseLong(s) ); }//end validate() protected void checkRange( long n ) throws DfServiceException { String strMsg = "checkRange() Docbase error"; try { long lMax = this.getLong( "max_number"); if( ( n < 0 ) || ( n > lMax ) ) { strMsg = "bad number or number out of range: " + String.valueOf( n ) + ", " + String.valueOf( lMax ); DfServiceException ex = new DfServiceException( this, strMsg ); DfLogger.error( this, strMsg, null, ex ); throw ex; } } catch( DfException e ) { DfLogger.error( this, strMsg, null, e ); throw new DfServiceException( e, strMsg ); } }//end checkRange()
c.
This is a static member of the AutoNumberType class. Call it to create instances of the class. Each instance of the AutoNumberType is tied to a version of a Docbase object with its own r_object_id. Call the addNewAutoNumberType method whenever
103
you need to start a new numbering sequence. It sets the starting number and the maximum range to the specified values.
public static void addNewAutoNumberType( IDfSessionManager sMgr, String strDocbase String strTableName, String strObjectName, // long name String strAutoNumberType, String strStartingNumber, String strMaxNumber, String strDocbaseFolder ) throws DfException { IDfSession session; try { session = sMgr.getSession( strDocbase ); AutoNumberType number = (AutoNumberType) session.newObject( strTableName ); number.setObjectName( strAutoNumberType ); number.setString( "number_type", strAutoNumberType ); number.setString( "max_number", strMaxNumber ); number.setNumber( strStartingNumber ); number.save(); DfLogger.error(number, "new %s instance added:%s", new String[]{ strTableName, strAutoNumberType }, null); } catch( Exception e ) { // failed to create if( e instanceof DfException ) throw (DfException)e; throw new DfException( DfException.DM_NOTDFC_E_JAVA, e.toString() ); } }//end addNewAutoNumberType()
5.
The new custom type is a subtype of dm_sysobject. Each different auto-numbering type will have its own instance of this new type. There are several ways to create the new com_accelera_autonumber custom type. Use Documentum Developer Studio to develop a portable DocApp:
104
Use the IDQL tool to use DQL to manually create the new com_accelera_autonumber type to a Docbase.
create type com_accelera_autonumber (number_type char(128), current_number char(18), max_number char(18)) with supertype dm_sysobject
6.
105
Use the IDQL tool to create and execute the following DQL statement:
create type com_accelera_autonumber ( number_type char(128), current_number char(18), max_number char(18) ) with supertype dm_sysobject
106
This registers the new business object with Documentum 5.1 so that any time any Docbase objects from this new table are fetched, the Docbase object is used to populate the AutoNumberType object. Caution The current implementation of DBOR uses the dbor.properties file in the DFC_DATA\config directory. Documentum will change this in future releases. Both the implementation of the object registry and the use of the config directory will change. The information regarding the use of the dbor.properties file is included in this manual in case you need to debug your business applications. Always use the DBOR maintenance tool to edit this file. You should write a program that uses the IDfDbor and IDfDborEntry interfaces to register the AutoNumberType business object.
boolean mapDocbaseTypeToClassName( IDfSession session, boolean bDborService, String strDocbaseTypeName, String strJavaClass ) { boolean bRetVal = true; IDfClient client = session.getClient(); IDfDbor dbor = client.getDbor(); String strLookup = null; try { System.out.println( "mapping " + strDocbaseTypeName ); if( ! bDborService ) { strLookup = dbor.lookupObject( strDocbaseTypeName ); } else { strLookup = dbor.lookupService( strDocbaseTypeName ); } System.out.println( strDocbaseTypeName + " already mapped to " + strLookup ); bRetVal = true; } catch( Exception e ) { try { String s = e.toString(); // if not already registered... IDfDborEntry entry = new DfDborEntry(); entry.setName( strDocbaseTypeName ); entry.setServiceBased( bDborService ); entry.setJavaClass( strJavaClass ); entry.setJavaClass( AutoNumberType.class.getName() ); entry.setVersion( "1.0" ); dbor.register( entry ); System.out.println( "New dbor registry entry successfull" ); } catch( Exception e2 ) { System.out.println( "Unable to map dbor entry" ); System.out.println( e2.toString() ); e2.printStackTrace(); bRetVal = false;
107
return bRetVal; }
In the mapDocbaseTypeToClassName method above, the dbor.register method signals that there is already an entry by throwing an exception. In other words, duplicate entries are not possible when the IDfDbor interface and should be the only mechanism used to manipulate the registry. An entry is duplicated when the name is the same. For TBOs, a duplicate entry when two or more entries have the same values left of the equals for the Docbase type. For services, it is the service interface name that must be unique. Editing DBOR by hand is strongly discouraged. Doing so could create serious runtime problems with the other Documentum based applications on your system. If the dbor.properties file does not exist, the register method will cause one to be created.
public class Simple_TBO { private private private private String String String String m_strDocbaseName; m_strUserName; m_strPassword; m_strDomain;
3.
Write the main and begin methods and instantiate the Simple_TBO class. This involves parsing the command line arguments into variables, instantiating the
108
Simple_TBO class to prevent writing all the methods and variables as static, establishing a session manager identity, and calling the test routine. 4. In the begin method, construct a new session manager object using the newSessionManager method of IDfClient. Then register a users credentials as an identity in the session manager, using the IDfSessionManager.setIdentity method.
public static void main( String[] args ) { new Simple_TBO().begin( args ); //xfer control to a non-static method } void begin( String[] args ) { try { // check cmd args if( !parseCmdLine( args ) ) return; IDfClient client=null; client = DfClient.getLocalClient(); IDfClientX clientx = new DfClientX(); IDfLoginInfo login = clientx.getLoginInfo(); login.setUser( m_strUserName ); login.setPassword( m_strPassword ); if( m_strDomain != null ) login.setDomain( m_strDomain ); // connect to session mgr IDfSessionManager sMgr = client.newSessionManager(); sMgr.setIdentity( m_strDocbaseName, login); test( sMgr, m_strDocbaseName, m_strAutoNumberTable, m_strAutoNumberType ); } catch( Exception e ) { DfLogger.error(this, e.toString(), null, e); } }
5.
109
catch( Exception e ) // array bounds exceptions, etc. { System.out.println( "Error parsing command line arguments.\n" ); System.out.println( "Usage: java Simple_TBO " + "<docbase> <newAutoNumberType> " + "<user> <password> [<domain>]\n\n" ); System.out.println( "Be sure that the following DMCL.INI file " + "has the following settings:" ); System.out.println( " [DMAPI_CONFIGURATION]" ); System.out.println( " connect_pool_enabled=T\n\n" ); } return true; }
6. 7.
Test the new object type. To test the new business object, fetch a specified instance of a "com_accelera_ autonumber" type (like PO, or INV). If no matching "number_type" exists, then a new one is added for you with its starting number set to "1". Then call the getUniqueNumber method. Display the number you retrieved.
8. 9.
10. Set the next number back into the Docbase and release any locks you may have established on the object. 11. Save the object with the overridden save method.
void test( IDfSessionManager sMgr, String strDocbaseName, String strAutoNumberTable, String strAutoNumberType ) throws DfException { sMgr.beginTransaction(); try { IAutoNumberType number = null; IDfSession session = sMgr.getSession( strDocbaseName ); try { String strDQL = strAutoNumberTable + " where number_type=" + strAutoNumberType + ""; // GOOD EXPERIMENT! // Find the r_object_id of the AutoNumberType record and use it in // the query below as follows: // String strDQL = "dm_sysobject where r_object_id = 09...."; number = (IAutoNumberType) session.getObjectByQualification( strDQL ); // If it doesnt exist, tell the class to add one for you. if( number == null ) { AutoNumberType.addNewAutoNumberType( sMgr, strDocbaseName, strAutoNumberTable, strAutoNumberType, strAutoNumberType,
110
"1", "999999999999", "/System/com_accelera_autonumber" ); number = (IAutoNumberType) session.getObjectByQualification( strDQL ); } String strNewNumber = number.getUniqueNumber( sMgr ); System.out.println( "Current number for " + strAutoNumberType + " is: " + strNewNumber ); } finally { sMgr.release( session ); } sMgr.commitTransaction(); } catch( Exception e ) { DfLogger.error(this, "failed to update", null, e); DfLogger.error(this, e.toString(), null, e); sMgr.abortTransaction(); // failed to create or update if( e instanceof DfException ) throw (DfException)e; DfException e2 = new DfException(); e2.setMessage( e.toString() ); throw e2; } }
Executing this command line several times for different numbering types will prove that the service is producing sequential numbers by type:
Figure 74. Run the test TBO program
111
112
The AutoNumber SBO class definition provides a very simple generalized interface to the TBOs stored in the Docbase. Aside from Docbase session and synchronization issues, the caller need not be aware of the underlying details as to how the service performs its duty. The caller just calls getNextNumber and the service takes care of the rest. Before implementing the getNextNumber method, override the three abstract methods from DfService that you must implement.
public class AutoNumber extends DfService implements IAutoNumber { public static final String strCOPYRIGHT = "Copyright (c) Documentum, Inc., 2003";
113
public static final String strVERSION = "1.0"; public String getVersion() { return strVERSION; } public String getVendorString() { return strCOPYRIGHT; } public boolean isCompatible( String strVersion ) { int i = strVersion.compareTo( getVersion() ); if( i <= 0 ) return true; else return false; } } //end: class AutoNumber
114
String strDql = strbDql.append( strPrefix ) .append( strAutoNumberType ) .append( strSuffix ) .toString(); IDfSessionManager sMgr = getSessionManager(); if( ! isTransactionActive() ) { sMgr.beginTransaction(); bNewTransaction = true; } try { session = getSession( strDocbase ); //managed session try { IAutoNumberType numType = (IAutoNumberType) session.getObjectByQualification( strDql ); strRetVal = numType.getUniqueNumber( sMgr ); } finally { releaseSession( session ); } if( bNewTransaction ) sMgr.commitTransaction(); } catch( Exception e ) { if( bNewTransaction ) sMgr.abortTransaction(); } return strRetVal; }
In order to allow the newService method to know that it should instantiate the AutoNumber class for this service, the DBOR must contain an association between the IAutoNumber interface and the AutoNumber class. You can register this association by using the IDfDbor interface. The beginInstall method registers TBO or SBO entries. If you call it with bService set to true, the strNewDocbaseType parameter represents the service interface (for example, com.accelera.autonumber.IAutoNumber).
private boolean beginInstall( IDfSessionManager sMgr, boolean bService, String strDocbaseName, String strNewDocbaseType,
115
String strJavaClass ) { boolean bRetVal = true; IDfSession session = null; try { //setupLog(); session = sMgr.getSession( strDocbaseName ); if( ! bService ) { if( addDocbaseType( sMgr, session, strNewDocbaseType ) ) { bRetVal = mapDocbaseTypeToClassName( session, bService, // TBO strNewDocbaseType, strJavaClass ); addDocbaseFolder( session, strNewDocbaseType, "/System" ); } } else { bRetVal = mapDocbaseTypeToClassName( session, bService, // SBO strNewDocbaseType, strJavaClass ); } } catch( Exception e ) { bRetVal = false; } finally { if( session != null ) sMgr.release( session ); } return bRetVal; }
116
import java.util.Collection; import com.documentum.fc.client.*; import com.documentum.fc.common.*; import com.documentum.com.*; import com.accelera.autonumber.*;
public class Simple_SBO { private String m_strDocbaseName; private String m_strUserName; private String m_strPassword; private String m_strDomain; private String m_strAutoNumberType; private static final String m_strAutoNumberTable = "com_accelera_autonumber"; public static void main( String[] args ) { //xfer control to a non-static method new Simple_SBO().begin( args ); } void begin( String[] args ) { try { // check cmd args if( !parseCmdLine( args ) ) return; IDfClient client = DfClient.getLocalClient(); IDfClientX clientx = new DfClientX(); IDfLoginInfo oLogin = clientx.getLoginInfo(); oLogin.setUser( m_strUserName ); oLogin.setPassword( m_strPassword ); if( m_strDomain != null ) oLogin.setDomain( m_strDomain ); // connect to session mgr IDfSessionManager oSMgr = client.newSessionManager(); oSMgr.setIdentity( m_strDocbaseName, oLogin); // fetch, display, then increment the num from service test( oSMgr, m_strDocbaseName, m_strAutoNumberTable, m_strAutoNumberType ); } catch( Exception e ) { System.out.println( e.toString() ); e.printStackTrace(); } } }// end: class Simple_SBO
117
private boolean parseCmdLine( String[] args ) { try { m_strDocbaseName = args[0]; // check DocbaseName m_strAutoNumberType = args[1]; m_strUserName = args[2]; // check AutoNumberType m_strPassword = args[3]; // check Java class name if( args.length > 4 ) { m_strDomain = args[4]; } } catch( Exception e ) // array bounds exceptions, etc. { System.out.println( "Error parsing command line arguments.\n" ); System.out.println( "Usage: java Simple_SBO " + "<docbase> <newAutoNumberType> " + "<user> <password> [<domain>]\n\n" ); System.out.println( "Be sure that the following DMCL.INI file " + "has the following settings:" ); System.out.println( " [DMAPI_CONFIGURATION]" ); System.out.println( " connect_pool_enabled=T\n\n" ); e.printStackTrace(); } return true; }
The test method gets a session for the given Docbase from the session manager and ensures that it releases the session before exiting. The code for the test method is as follows:
void test( IDfSessionManager sMgr, String strDocbaseName, String strAutoNumberTable, String strAutoNumberType ) throws DfException { try { IDfSession session = sMgr.getSession( strDocbaseName ); IDfClient client = DfClient.getLocalClient(); IAutoNumber svcNumber = null; try { String s = IAutoNumber.class.getName(); svcNumber = (IAutoNumber)client.newService( s, sMgr ); } finally { sMgr.release( session ); } String strNewNumber = svcNumber.getNextNumber( strDocbaseName, strAutoNumberType ); System.out.println( "Current svcNumber for " + strAutoNumberType + " is: " + strNewNumber ); }
118
catch( Exception e ) { System.out.println( "failed to update" ); // failed to create or update if( e instanceof DfException ) { throw (DfException)e; } DfException e2 = new DfException(); e2.setMessage( e.toString() ); throw e2; }
}//end test()
Executing this command line several times for different numbering types tests whether the service produces a different sequence of numbers for each type:
Figure 75. Sample running test SBO program
119
120
Overview
When implementing a service BO, the session manager is inherently available to the service methods. The session manager object is a member of the DfService class that you extend and can be accessed from any method of a service. In most cases however, the implementation does not directly use the session manager but uses the two convenience methods in DfService (getSession, and releaseSession) which are used to obtain a DFC session handle and return it when finished.
121
Transaction Processing
DFC now supports two different transaction-processing mechanisms to assist in management of the granularity of batch updates, session transactions (also called "DFC transactions" using session.beginTrans) and session manager transactions (also called "managed transactions" using sMgr.beginTransaction). DFC session transactions are not allowed inside service methods because they may interfere with transactions controlled by its caller if used. Therefore, a standard DFC session transaction call will throw an exception while inside a BOF transaction. Exercise caution when using transaction processing within a business object service.
122
Never begin a transaction if one is already active. Use the sMgr.isTransactionActive() method to determine this. Always use managed transactions within a business object. This is because the isTransactionActive method will not return true if a DFC session transaction is active. It only works with managed transactions. If the service did not begin the transaction, commitTransaction and abortTransaction should not be used within the service method. If abortTransaction() is required, use sMgr.setTransactionRollbackOnly.
When you need the flow of a program to continue when transaction errors occur, use the sMgr.setTransactionRollbackOnly method to ensure transactions will be aborted without throwing an exception; even if the calling program attempts to commit their transaction. Use the setTransactionRollbackOnly method as you would use sMgr.abortTransaction. Any attempt to commit that transaction afterward will be ignored and no error will be generated. In other words, the owner of the transaction would not be aware that one of its method calls aborted the transaction for it unless it calls the getTransactionRollbackOnly method, which returns true if some part of the program ever called setTransactionRollbackOnly. The way it actually works is that when the sMgr.commitTransaction method is eventually called, internally it is redirected to sMgr.abortTransaction. A key point about this is that setTransactionRollbackOnly does NOT throw an exception, so the program continues as if the batch process is valid. When more than one thread is involved in session manager transactions, calling sMgr.beginTransaction from a second thread causes the session manager to automatically create a new session for the new thread.
void serviceMethodThatRollsBack( String strDocbase, IDfId idDoc ) throws DfNoTransactionAvailableException { IDfSessionManager sMgr = getSessionManager(); IDfSession = getSession( strDocbase ); if( ! isTransactionActive() ) { throw DfNoTransactionAvailableException(); } try { IDfPersistentObject obj = session.getObject( idDoc ); obj.checkout() modifyObject( obj ); obj.save(); } catch( Exception e ) { // setTransactionRollback() acts like an abortTransaction() // so that even if they commit after this, this checkout() // and save() are omitted. setTransactionRollbackOnly(); throw new DfException(); } }
123
Transaction Handling
The session manager supports transaction handling across multiple services. The session manager handles session pooling details and prevents sessions from being disconnected or released while transactions are pending. When session pooling is used, it is possible that DFC sessions could timeout and be recycled back to the pool between individual service calls. For example, lets say there are two services: one service creates a few folders and then the second service stores some documents in these folders. To make sure the folders are only created when all the document creation has succeeded there must be one transaction around the two service calls. The DFC session transaction is bound to one DFC session so it is important to use the same DFC session across the two services calls. Each service performs its own atomic operation. At the start of each operation, they request a DFC session and at the end they release this session back to the session pool. In between these calls, the service session could have been recycled back to the session pool and released, due to a session timeout. Calling session.beginTrans / session.commitTrans / session.abortTrans could fail. To "lock" a managed session to prevent it from being recycled due to timeouts, the session Manager defines methods that allow transactions to work across multiple service calls and even across Docbases. The Session Manager automatically determines when a session can be put back into the pool. A managed session will not be recycled back into the session pool as long as there is a pending transaction. The sMgr.beginTransaction method is used to start a new transaction, sMgr.commitTransaction commits all changes to the Docbases and ends the transaction lock. In case of an error, sMgr.abortTransaction is used as a rollback to reverse any changes made so far in the transaction. You must call getSession AFTER beginTransacion or the session object will not be able to participate in the transaction. Use the isTransactionActive method to ask whether a "managed transaction" has already begun and the session manager currently has a transaction active that you can join. (You would not want to interfere with an outer transaction by blindly attempting to start a nested transaction, which is not allowed). The implementation of the transaction mechanism handles the following issues: With multiple threads, transaction handling operates on the current thread only. For example, if there is an existing DFC session for one thread, a new DFC session is created for the second thread automatically. This also means it is not possible to begin a transaction in one thread and commit it in a second thread. The transaction mechanism guarantees that the Session Manager provides a separate DFC session for each thread that calls beginTransaction. For those threads that already have a DFC session before the transaction begins a transaction, a new DFC session is provided and required to be used once beginTransaction is called. When a client starts a transaction using the sMgr.beginTransaction method, the Session Manager will not allow any other DFC-based transactions to occur (neither session.beginTrans nor sMgr.beginTransaction). It is not possible to nest transactions.
124
The following example illustrates a client application calling two services that must be inside a transaction in which case both calls must succeed or nothing is done:
IDfClient client = DfClient.getLocalClient(); IDfSessionManager sMgr = client.newSessionManager(); sMgr.setIdentity(docbase, loginInfo); IMyService1 s1 = (IMyService1) client.newService(IMyService1.class.getName(), sMgr); IMyService2 s2 = (IMyService2) client.newService(IMyService2.class.getName(), sMgr); s1.setDocbase( strDocbase1 ); s2.setDocbase( strDocbase2 ) ; sMgr.beginTransaction(); try { s1.doDocbaseUpdate(); s2.doDocbaseUpdate(); sMgr.commitTransaction(); } catch (Exception e) { sMgr.abortTransaction(); }
If either of these service methods throws and exception, commit is bypassed and abort is executed. Each of the doDocbaseUpdate methods call sMgr.getSession. An interesting point to note in the above example is that the two services are updating different Docbases. The session manager, internally, automatically handles the real sessions and their real Docbase transactions (which translate to RDBMS transactions). Since the session manager is aware of all these Docbase handles within its own scope, committing or aborting the managed transaction causes the session manager to loop through its real session list and commit or abort those. The session manage supports transactions in this manner across multiple Docbases. However, if, for example, there are three Docbases, and the first two commit successfully, but the third does not update correctly during its commit, the session manager will not be able to undo the already committed transactions on those Docbases. Doing so would be a "two-phased commit" and is not supported by DFC.
Client Control
Client Control is a mechanism used to control how the session manager handles session pooling. Session manager sessions are managed by the session manager object. The client application is not able to directly control the lifetime of those sessions. (There are no methods to increase or decrease the timeout). All it can do is to set the identity and then either authenticate immediately or leave it to the service methods to obtain a session for a given Docbase.
125
The client can control the session pool indirectly using either the transaction mechanism (that locks the session from being recycled to the session pool until commit or abort) or the "Client Control" mechanism (using the beginClientControl and endClientControl methods). As long as a transaction is active or the session pool is locked, the session is not recycled. For transaction management this is required because a transaction cannot work across different sessions. Client control is needed when you need to prevent the session manager from recycling and disconnecting a session that is still in use even if the service has already released the session. A typical scenario for client pool locking is when a service that is called returns a typed DFC object (for example, IDfCollection) which needs to be manipulated by its caller. DFC persistent objects internally store a reference to the session with which they were fetched. If the session is still valid, the session can be reacquired directly from the object using the IDfPersistentObject.getSession method. You cannot always depend on this session with managed sessions. However, if you have a session manager, it is best to acquire the session from that For objects that will be used in this manner, there is a need to lock the session until the typed object is discarded. In this case, the sMgr.beginClientControl method is used prior to calling the service and accessing the DFC object. When the client application is finished with this object it must call the endClientControl method to re-enable session manager recycling. The following example shows a service call that returns a collection of objects to be displayed. Client Control is used to ensure that the session associated with the collection is not recycled while the object names are printed out:
IDfClient client = DfClient.getLocalClient(); IDfSessionManager sMgr = client.newSessionManager(); sMgr.setIdentity(docbase, loginInfo); IDfSession session = null; IMyService anyService = (IMyService) client.newService(IMyService.class.getName(), sMgr); sMgr.beginClientControl(); try { session = sMgr.getSession( strDocbase1 ); IDfCollection coll = anyService.getObjects(); while( coll.next() ) System.out.println( coll.getString("object_name") ); coll.close(); } finally { sMgr.release( session ); sMgr.endClientControl(); }
Note: Since you are required to guarantee that endClientControl is always called after calling beginClientControl, call endClientControl within a finally block. Additionally, when an exception is thrown while a call is open, you must make sure the session is released. Use the Java finally block to ensure the client application control is switched off when the client application is done or in the case of an exception.
126
Calls to beginClientControl can also be nested as long as there is a matching endClientControl for each beginClientControl When a program performs a query or accesses an object, it currently requires that you obtain a session and apply that session to any subsequent calls requiring authentication and operations on a content server. This can pose a problem for middle-tier application servers involving the maintenance of that session information between HTTP requests. When a BOF service returns a persistent object, the session manager must maintain the session in case access to the object is needed. DFC 5.1 separates the dependency of persistent objects from a session. This involves a new method to the IDfTypedObject interface called setSessionManager. When the setSessionManager method is called, the entire object is fetched from the server and its attributes are cached on the Java side. This allows the session manager to use that same session for other operations on the application server. When modifications are made to the cached persistent object, they are made to the local cache. When the object is saved or checked back in, the session manager supplies a session for that operation. Use setSessionManager judiciously. Because a "fetch" of the entire object is performed in order to cache the object to the Java side, it could be very costly. This should only be considered when a BOF service object returns a persistent object. A new class, DfCollectionEx has been added for your convenience. The DfCollectionEx class can be used when returning a collection of typed objects from a service. DfCollectionEx locks the session until the collection is closed with the DfCollectionEx.close() method.
Statistics
For testing or performance tuning purposes, the session manager provides an interface for querying the special session manager state parameters such as reference counters, number of sessions, Docbases currently connected, etc. Specifically, use the sMgr.getStatisticsmethod to retrieve an IDfSessionManagerStatistics object that contains the state information. The statistics object takes a snapshot of the session manager internal data when getStatistics is called. This means that the data may not be accurate by the time you look examine the data. The IDfSessionManagerStatistics provides the following information: Session pooling mode (for example, enabled/disabled) Whether there are active sessions Get a list of all Docbase names that have active sessions or identities Get a list of all IDfLoginInfo identities for a given Docbase (passwords are removed) Get a list of all active DFC IDfSession objects for a given Docbase Get reference count for a given Docbase session object
Error Handling
There are different scenarios for error handling in session manager, including:
127
Bad identity defined (user , password): When authenticate is called or a session is retrieved DfAuthenticationException is thrown. The server message text is passed to this exception and can be shown to the user.
No identity or principal defined: When the user is authenticated, DfIdentityException is thrown. The message stored in the exception contains the Docbase name to be authenticated against. Set identity is called twice: If an identity is already defined for a given Docbase, (DfServiceException) is thrown. To be sure always call hasIdentity and clearIdentity first. Cannot generate session for principal: This may happen if the principal support is not configured properly. In this case DfPrincipalException is thrown. All other problems: In this case either a DfServiceException is thrown or for severe programming errors a runtime error is produced. DfServiceException does not contain a detailed error message. Check the log file for debugging.
The remainder of this section shows how to call an SBO from a WDK component. The sample service looks up the address of a customer in a phone book, given the customers name or phone number. The main parts of the example are: The ICustomer SBO. A JSP/HTML form to provide the user interface. A custom WDK form event handler to initiate the action.
The user interface form appears as shown in Figure 81, page 129.
128
Define an ICustomer service interface that extends IDfService and provides the methods as shown:
public interface ICustomer extends IDfService { IDfId getCustomerIdFromPhone(String docbase, String phone) throws DfServiceException; String[] getCustomerData(IDfId id, String[] attributes) throws DfServiceException; }
The getCustomerIdFromPhone method returns the object ID of a customer object. The getCustomerData method accepts a customer ID and returns selected customer data attributes. You can create a JSP page as shown in Figure 81, page 129. The form uses a WDK form class named CustomerForm. The CustomerFormNls class handles button and text field labels. A properties file defines the configuration of these classes. Java constants defined in the CustomerFormNls class help you specify these resources. For example, the ID_PHONE constant maps to the value of a number configured in a properties file. The JSP form layout is CustomerForm.jsp. When a user presses the Lookup button, the onLookupPhone event method of CustomerForm runs.
<%@ page contentType="text/html; charset=UTF-8" %> <%@ page errorPage="/wdk/errorhandler.jsp" %> <%@ taglib uri="/WEB-INF/tlds/dmform_1_0.tld" prefix="dmf"%> <html> <head> <dmf:webform formclass="com.documentum.sample.customer.form.CustomerForm" nlsclass="com.documentum.sample.customer.form.CustomerFormNls"/> </head> <body> <dmf:form> <table> <tr> <td><dmf:label nlsid="ID_PHONE"/></td> <td> <dmf:text name="customer_phone"/> <dmf:button nlsid="ID_LOOKUP" onclick="onLookupPhone"/>
129
</td> </tr> </table> <hr/> <table> <tr> <td><dmf:label nlsid="ID_NAME"/></td> <td><dmf:text name="customer_name"/></td> </tr> <tr> <td><dmf:label nlsid="ID_ADDRESS"/></td> <td><dmf:text name="customer_address"/></td> </tr> <tr> <td><dmf:label nlsid="ID_CITY"/></td> <td><dmf:text name="customer_city"/></td> </tr> </table> </dmf:form> </body> </html>
The onLookupPhone event method uses the ICustomer service to look up the customer information corresponding to the number. The method uses the SessionManagerHttpBinding WDK class to obtain a DFC session manager object prior to instantiating the service. The method casts the interface to the ICustomer type, so it can use that types methods. The implementations of the ICustomer methods use the Docbase name and the session manager objects to obtain and release a pooled session.
public void onLookupPhone( Button button, ArgumentList arg ) { Text textControl = (Text) this.getControl(PHONE); String phone = textControl.getValue(); String[] data = new String[0]; try { SessionManagerHttpBinding httpBinding = new SessionManagerHttpBinding(); IDfClient client = DfClient.getLocalClient(); ICustomer service = (ICustomer)client.newService( ICustomer.class.getName(), httpBinding.getSessionManager()); IDfId custId = service.getCustomerIdFromPhone( httpBinding.getCurrentDocbase(), phone); data = service.getCustomerData(custId, ATTRIBUTE_LIST); } catch( DfException e ) { WebComponentErrorService.getService().setNonFatalError( this, "MSG_CANNOT_GET_CUSTOMER", e ); } for( int i = 0; i < data.length; i++ ) { textControl = (Text) this.getControl(ATTRIBUTE_LIST[i]); textControl.setValue(data[i]); } }
130
The code of the onLookupPhone method does the following: Obtain the phone number from the PHONE text box of the HTML form. Declare the String array data to receive the output of the getCustomerData method of the service. The getCustomerData method returns an array of string references, one for each customer attribute, in the same order as the fields are laid out. Construct a new WDK SessionManagerHttpBinding object. Use the getLocalClient factory method of the DfClient class to construct a local client. Note that you can call the getLocalClient method as many times as needed during an application without worrying about memory leakage, because it is a singleton. Use the SessionManagerHttpBinding objects getSessionManager method to obtain a session manager. Call the local clients newService factory method to obtain the ICustomer service object. The newService method uses DBOR to find and instantiate the Java class associated with the interface. The newService method takes the service name and a session manager reference as arguments. The method uses ICustomer.class.getName to obtain the fully qualified interface name. If you cannot import the service interface at development time, you must instead use a string like, com.documentum.services.customerservice. ICustomer. Call the getCustomerIdFromPhone and getCustomerData methods of the ICustomer interface to obtain the customer data. The method downcasts the DfService object that newService returns to the ICustomer interface, so it can call the two methods. The getCustomerIdFromPhone method returns the customer ID, which the getCustomerData method uses to retrieve the rest of the customers data attributes. Execute a for loop to iterate through the String array returned from the getCustomerData method and populate the HTML form fields with the customer data values.
131
The code will not be type safe and can generate runtime errors that would not be detectable during compilation.
Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim clientx client loginInfo sMgr session service id custData() attrList() ctlText As As As As As As As As As As DfClientX IDfClient IDfLoginInfo IDfSessionManager IDfSession Object IDfId String String Text or use CreateObject( "Documentum.Dfc" )
Set clientx = New DFCLib.DfClientX Set client = clientx.getLocalClient Set sMgr = client.newSessionManager
Set service = client.newService("com.documentum.services.customer.ICustomer",_ sMgr ) attrList(0) attrList(1) attrList(2) attrList(3) = = = = "phone" "name" "address" "city"
Set id = service.getCustomerIdFromPhone( strDocbaseName, strPhone ) Set custData = service.getCustomerData( id, attrList ) ctlPhone = custData(0) ctlName = custData(1) ctlAddress = custData(2) ctlCity = custData(3)
Packaging
Each Business object (TBO or SBO) comes with a minimum of two Java class files. These are the business object interface and the Java implementation of that interface. These two
132
Java class files must be accessible through the Java CLASSPATH from the JVM that will load and execute business object class files. Each business object requires an entry in DBOR on every computer that runs the application. This entry must match the Java classes installed. DBOR is located in a directory referenced by the DFC_DATA environment variable. In other words, when a TBO or SBO is deployed we not only need to copy the Java classes but also make sure DBOR matches the deployed components. DFC Version 5.1 or later is required to be able to run the SBO or TBO because DBOR registry is part of BOF, which is new with DFC Version 5.1. It is very important that the deployed business object Java classes of the TBO and SBO are accessed through the same Java class loader as DFC. This means that when running an application server that loads DFC through the CLASSPATH variable the deployed Java classes also need to be referenced by the CLASSPATH. However, when the application is deployed in a WAR file for an application server, the deployed Java classes for SBOs and TBOs must be located in the WAR file. The correct version of dfc.jar would need to be referenced in the CLASSPATH used by the application server servlet container, or supplied as a command line parameter when it is invoked. The rule is, either everything is referenced through the CLASSPATH, or everything is in the WAR file. Avoid mixing jar files. The dmcl40.dll file is excluded from this rule. It can be in a WAR file or referenced with the PATH variable. The WAR file DFC (dfc.jar) would then be located in WEB-INF/lib. If the deployed business objects are in a JAR file, this JAR file must be located in WEB-INF/lib. If the TBO and SBO class files are not shipped in a JAR file, they could also be located under WEB-INF/classes in the WAR file. In addition, client connection pooling should be enabled.
Packaging example
Assume that we want to deploy the IAutoNumber sample service, which consists of a several Java classes. These classes are shipped in a JAR file named autonumber.jar. The JAR file is built as follows (assuming a Windows server and default installation locations):
jar.exe -cvf autonumber.jar com com/ com/documentum/ com/documentum/services/ com/documentum/services/autonumber/ com/documentum/services/autonumber/AutoNumber.class com/documentum/services/autonumber/AutoNumberScheme.class com/documentum/services/autonumber/IAutoNumber.class com/documentum/services/autonumber/IAutoNumberScheme.class com/documentum/services/autonumber/INameGenerator.class com/documentum/services/autonumber/sample/ com/documentum/services/autonumber/sample/RunAutoNumber.class com/documentum/services/autonumber/UniqueNameException.class com/documentum/services/autonumber/Installer.class
133
In the DFC_DATA\config directory a properties file dbor.properties should have been created. If it does not yet exist then add the following two lines:
Table 82. DBOR Entry Attribute Samples For "service" And "type" com.documentum. services. autonumber. IAutoNumber dm_autonumber service com.documentum. services.autonumber. AutoNumber com.documentum. services.autonumber. AutoNumberScheme 1.0
type
1.0
DFC and BOF require the dfc.jar file. The DFC installer places it in the Documentum Shared files directory, (for example, c:\Program Files\Documentum\Shared). To make the services available to the application, servlet, or application server, copy the business object JAR file (for example, the autonumber.jar file created above) into a directory on your hard drive. There are several options for this and a few things to remember: Documentum tries not to impose restrictions on where these files can be located The files are loaded and executed by a JVM. All the rules governing the location, loading, securing, and executing the bytecode in the JAR files follows the rules and recommendations of Java. Considering the Java class loading algorithms and DFC requirements, we have determined that the following locations are good recommendations: Place your business object .JAR file in the JRE\lib\ext directory. This directory is known as the Java Extension Library. Files placed in this directory are implicitly scanned after rt.jar when the JVM searches for classes. Only after the JVM cant find a class in the bootclasses, then rt.jar, then the extension library, will it start to use the CLASSPATH variable. The downside to this approach is that this .jar file becomes visible to all Java applications on that computer. This is especially bad for DFC which contains libraries from Apache and Xerces. Those libraries contained in the dfc.jar file are not guaranteed to be the latest versions and a non-Documentum related application may break. Another problem is that IDEs, like IntelliJ, load all classes located in the JRE\lib\ext directory by default and can be overly time-consuming.
134
A benefit of using the Java Extension Library is that the CLASSPATH environment variable is not used to locate your class. Another benefit is that the CLASSPATH variable is much shorter. There are a few drawbacks to using the extension library. If you install another JVM (for example, when you upgrade from 1.3.1_03 to 1.4.1), you would need to remember to copy all the JAR files from c:\Program Files\JavaSoft\JRE\1.3.1_03\lib\ext to c:\Program Files\JavaSoft\JRE\1.4.0_01\lib\ext. You need to choose a name for the .JAR file the does not conflict with a file already there. (Remember, the namespace is determined by the actual package names, like com.accelera.autonumber, not the name of the JAR file). Place your business object .JAR file in the any directory of your choosing - possibly a repository directory of business object .JAR files. Each Jar file would need to be added to the CLASSPATH variable. The CLASSPATH will begin to get very long. Place your business object .JAR file in the a WAR file in the WEB-INF\lib directory. The drawback here is that dfc.jar would also need to be located there. You must ensure that the CLASSPATH environment variable includes the JAR file of the new business objects, including dfc.jar. To be able to run DFC also the PATH environment variable has to be configured to the Documentum Shared directory where Documentum stores the shared libraries, DLLs and other necessary files. This is typically done by the DFC installer. If this is not the case the PATH variable has to be setup to reference dmcl40.dll for example located in c:\Program Files\Documentum\shared:
set PATH=c:\Program files\Documentum\Shared\;%PATH%
Documentation
When you develop a business object, you should also develop a set of Javadocs for it so that other developers (including yourself) may use it as a reference when calling the business object methods. Since Javadocs can be automatically generated from Java source code it tends to be very good for describing the details of an individual classes. Very often, however it is hard to get the overall picture. Try to give extended descriptions and overviews on what a business objects does and how it relates to other business objects for each class. The recommendation is to always ship Javadocs with a set of business objects.
135
Custom Installer/Uninstaller
To write an installer that installs a Java application that uses TBOs and SBOs, there are several files to be copied to the target computer and DBOR must be configured.
AutoNumber Components
If you want to install the AutoNumber sample business object, follow these steps: Copy the autonumber.jar to %JAVA_HOME%\lib\ext Define the DFC_DATA environment variable. Create %DFC_DATA%\config\dbor.properties file and configure it as shown above.
136
This chapter moves through the DFC interfaces that derive from the Documentum object type hierarchy, starting from the top. It contains the following major sections: Documentum Object Hierarchy, page 137 Typed Objects, page 142 Persistent Objects, page 146 Persistent Objects Without Associated Content, page 149 SysObjectsPersistent Objects With Content, page 152 IDfSession, page 154 IDfClient, page 159 Common Package, page 160
137
interfaces corresponding to most system-defined object types. The interface has separate set and get methods for each of the types attributes, and it has methods that pertain to objects of that type. You read or change the attribute values via the get and set methods, and you operate on the object through the interfaces methods. By the conventions of object-oriented programming, a method without arguments performs the corresponding operation on its associated object. For example, the statement
document.save();
appears in the example on Example 11, page 15. It tells the document object to apply its save method to itself, that is, to save the document in the Docbase. Methods that operate on other objects take references to those objects as arguments.
Persistence
Most objects the server manipulates are persistent, that is, they reside in the Docbase and persist across sessions. A document you create and save in one session is still there in another session on another day. Some objects are not persistent, that is, they do not reside in the Docbase. The server creates them as needed at runtime. For example, collection objects and query result objects, which return the results of DQL statements, are not persistent. When the server executes a DQL query it creates a collection object to contain the results of the query. It creates a query result object for each row that the underlying database returns for the underlying SELECT statement, and it associates the query result objects with the collection object. When you close a collection, the server destroys the collection object and the query result objects.
138
139
In Figure 92, page 141, you can see how the interfaces that derive from the Documentum hierarchy fit into the total DFC interface hierarchy.
140
141
DFC interfaces that are not in the above diagrams are not part of the interface hierarchy. They do not derive from other DFC interfaces, and vice versa.
Typed Objects
The IDfTypedObject interface provides the basis for both persistent and non-persistent types. Here are the main facts about typed objects: They have attributes (properties) that you can retrieve and set. In almost all cases, you obtain them directly or indirectly through a DFC session; therefore they have a reference to the session that created them. A unique object ID identifies them.
The ID of a persistent object uniquely identifies the object in the Docbase. The ID of a non-persistent object, such as a collection or a Docbase map, identifies the object only for the session that creates it. The DFC online reference contains signatures of the methods of DFC interfaces (see Using the DFC Online Reference Documentation, page 20). This section describes the general categories of methods of the IdfTypedObject interface. IDfTypedObject is the base object for most DFC objects.
142
The argument attrName refers to the attribute, such as object_name. Regardless of the type of the attribute, you can call getString to retrieve the value in the form of a string. If you call a get method that is inappropriate for the type of the attribute, for example, getInt("object_name"), DFC attempts to convert the value to that type. To set the value of a single-valued attribute, call one of the following methods, where attrName is the name of the attribute and value is the value you want to assign to that attribute:
void setBoolean(String attrName, boolean value) void setDouble(String attrName, double value) void setId(String attrName, IDfId value) void setInt(String attrName, int value) void setString(String attrName, String value) void setTime(String attrName, IDfTime value) void setValue(String attrName, IDfValue value)
There are several sets of methods that relate to repeating attributes. The server maintains an indexed array of values for a repeating attribute. For example, the authors attribute may contain the following values with the specified indexes:
[0] Sleepy [1] Dopey [2] Happy
143
Methods that operate on repeating attributes often take an index, which specifies which value the operation should affect. The descriptions that follow refer to the authors listed above. The set and get methods for repeating attributes are similar to the set and get methods for single-valued attributes:
boolean getRepeatingBoolean(String attrName, int index) double getRepeatingDouble(String attrName, int index) IDfId getRepeatingId(String attrName, int index) int getRepeatingInt(String attrName, int index) String getRepeatingString(String attrName, int index) IDfTime getRepeatingTime(String attrName, int index) IDfValue getRepeatingValue(String attrName, int index) void setRepeatingBoolean( String attrName, int index, boolean value) void setRepeatingDouble( String attrName, int index, double value) void setRepeatingId( String attrName, int index, IDfId value) void setRepeatingInt( String attrName, int index, int value) void setRepeatingString( String attrName, int index, String value) void setRepeatingTime( String attrName, int index, IDfTime value) void setRepeatingValue( String attrName, int index, IDfValue value)
You can use single-value attribute methods to set/get repeating attributes and repeating-attribute methods to get/set single valued attributes. Single-valued methods always operate on the repeating attribute value at index 0. To use a repeating-attribute method for a single-valued attribute, the index argument must be 0. The call
getAllRepeatingStrings(String attrName, String separator)
returns all values of a repeating attribute as a single string with values delimited by separator, or by a comma if separator is null. For example, given the authors mentioned above,
getAllRepeatingStrings("authors", null)
144
The appendType methods add values to the end of a repeating attributes list of values. For example, to add an eighth dwarf, call
myobj.appendString ("authors", "Burpy")
The insertType methods are similar, but they add the value at the specified index rather than at the end. To make Burpy the fourth dwarf, call
myobj.insertString ("authors", 3, "Burpy")
Generally, appending is more efficient, because insertions can force the server to copy existing values to new index locations. The find methods retrieve the first index at which a specified value appears. For example, findString ("authors", "Happy") returns 2. The remove method deletes the value at the specified index. The truncate method deletes all values from the specified index onward. The removeAll method deletes all values from the specified repeating attribute. The getValueCount method returns the number of values the specified repeating attribute has.
Attribute Information
IDfTypedObject has a number of methods that allow you to get information about the objects attributes:
String dump() int getAttrCount() boolean hasAttr(String attrName) boolean isAttrRepeating(String attrName) int getAttrDataType(String attrName) int findAttrIndex(String attrName) IDfAttr getAttr(int index) Enumeration enumAttrs()
The dump method is for debugging. It returns the objects attributes and values in a formatted string.
145
The getAttrCount method returns the number of attributes that the object has. The hasAttr method returns a boolean value indicating whether the objects type has the specified attribute. The isAttrRepeating method returns a boolean value indicating whether the specified attribute is repeating (True) or single (False). The getAttrDataType method returns an integer representing the attributes type (see the DFC online reference for IDfAttr for the possible return values). The attributes of a Documentum object have a column order. The findAttrIndex method returns the column index of the specified attribute. The getAttr and enumAttrs methods provide more detailed information about the specified attribute. The getAttr method returns an IDfAttr object for the attribute at the specified index. An IDfAttr object allows you to get the attributes name and type. IDfAttr also allows you to determine whether an attribute is repeating. If an attribute is of type String, the maximum character length of any value stored in that attribute may be obtained by calling IDfAttrs getLength method. The enumAttrs method returns an enumeration of IDfAttr objects. This enables you to iterate over all of the objects attributes.
Persistent Objects
Persistent objects are at the second level of the DFC interface hierarchy. They are typed objects that reside in the Docbase. The IDfPersistentObject interface inherits from the IDfTypedObject interface, and hence, IDfPersistentObject has all the methods of IDfTypedObject. In addition IDfPeristentObject has the following sets of methods.
146
The save method directs the server to store the local copy of the object into the Docbase. When you create a new Docbase object, others cannot see it until you explicitly call its save method. Saving an existing object fails if your version of the object is older than the object in the Docbase, that is, if the i_vstamp of your version contains a lower number than the i_vstamp of the object in the Docbase. This happens if another user saves changes to the object between the time you obtain a copy and the time you try to save it. You can prevent this from happening by checking out the object before changing it. The destroy method directs the server to remove the object from the Docbase. The isDeleted method tells you whether the object has been destroyed in the current session. This method does not detect deletion by another user or even in another session subsequent to the time that you obtained the local copy. The isNew method returns False if the object has ever been successfully saved in the Docbase. The isDirty method returns True if you have made unsaved changes to the local copy of the object. The fetch method obtains the latest version of the object from the Docbase if and only if the Docbase version has a newer i_vstamp. If the values are the same, the local copy retains any changes you have made. The revert method obtains the latest version of the object from the Docbase unconditionally. The local copy loses any changes you have made to it.
Audit Trail
Auditing enables you to record information about system events and preserve information in an audit trail, which you can then use to track events and generate reports. You choose which events to monitor, and the audit system logs pertinent data, including the time of the event. To support this process, IDfPersistentObject has the signoff method, which creates an audit trail entry of signoff information for an object.
147
IDfRelation addChildRelative( String relationTypeName, IDfId childId, String childLabel, boolean isPermanent, String d IDfRelation addParentRelative( String relationTypeName, IDfId parentId, String childLabel, boolean isPermanent, String void removeChildRelative( String relationTypeName, IDfId childId, String childLabel) public void removeParentRelative( String relationTypeName, IDfId parentId, String childLabel) public IDfCollection getChildRelatives( String relationTypeName) public IDfCollection getParentRelatives( String relationTypeName)
Validation Methods
DFC provides the IDfValidator interface, which makes it easy to validate proposed new or changed attribute values against information in the data dictionary. Normally, you need to do this when you interact with a user to obtain the attribute values. A related interface, IDfValueAssistance, supports providing contitional value assistance in the user interface. The following method returns an IDfValidator object for the persistent object:
IDfValidator getValidator()
148
String getTimePattern() IDfPersistentObject getAssociatedObject() String getObjectType() IDfId getPolicyID() String getStateName()
IDfACL
IDfACL provides the functionality associated with the server type dm_acl. An access control list (ACL), also called a permission set, is the usual server mechanism for controlling who has access to an object. If the Docbase security mode is set to acl, then every sysobject (that is, every object of type dm_sysobject or of a type that derives from dm_sysobject) has an associated ACL that specifies which users can operate on an object and what they can do. The Documentum Content Server Fundamentals manual discusses the two kinds of permissions: basic and extended. Chapter 5, Using Validation and ACLs contains an extended example of how to use DFC to work with these permissions.
149
IDfFormat
IDfFormat provides the interface methods for obtaining the attribute information from a dm_format object. A format object contains information about a file format recognized by the server. All content stored in the Docbase has an associated format such as msw8 (Microsoft Word 97 document), pdf (Acrobat PDF document), or html (an HTML file). All sysobjects that have associated content keep the content type in the a_content_type attribute. This value corresponds to a dm_format object. Administrators can create new format objects for formats that the server does not support automatically. Format objects provide the information necessary to open a viewer or editor appropriate to the content type.
IDfType
IDfType provides methods for getting information about a type. IDfType provides the following categories of information.
Basic Attributes
The getName method returns the types namea string like dm_format or dm_document. The getDescription method returns the types user-friendly name from the data dictionary. The user interface uses the user-friendly name. For example, a search dialog box may display the name Format rather than dm_format.
150
The getSuperName method returns the name of the types parent type, or null if the type has no parent type. For example, if you hold an IDfType reference to the dm_document type, getSuperName returns dm_sysobject. The method getSuperType returns an IDfType reference to the supertype. You can call isSubTypeOf to test whether a type is a subtype of another type. For example, if you hold an IDfType reference to the dm_document type, isSubTypeOf("dm_sysobject") returns True. By convention, a type is not a subtype of itself, so isSubTypeOf("dm_document") returns False.
Type Information
Programs typically make use of IDfType objects to get information about the attributes of that type. The type dm_type contains several repeating attributes that describe the attributes of the type. The DFC methods for most of these attributes come in two varieties. One takes an index into the array of repeating attributes; the other takes a string specifying the attribute name. The indexed methods are slightly more efficient. The following IDfType methods return type information:
int getTypeAttrCount() String getTypeAttrNameAt(int index) int getTypeAttrDataTypeAt(int index) int getTypeAttrDataType(String attrName) boolean isTypeAttrRepeatingAt(int index) boolean isTypeAttrRepeating(String attrName) int getTypeAttrLengthAt(int index) int getTypeAttrLength(String attrName) int findTypeAttrIndex(String attrName) String getTypeAttrDescriptionAt(int index) String getTypeAttrDescription(String attrName)
The getTypeAttrCount method returns the number of attributes the type has. The method getTypeAttrNameAt returns the attribute name at the specified index. To find an attributes index, call findTypeAttrIndex. The indexes start at zero. The above get type attribute methods return the type of the attribute. This is one of the following values:
IDfType.DF_BOOLEAN IDfType.DF_INTEGER IDfType.DF_STRING IDfType.DF_ID IDfType.DF_TIME IDfType.DF_DOUBLE IDfType.DF_UNDEFINED
They return IDfType.DF_UNDEFINED only in unusual circumstances. The isRepeating methods indicate whether the attribute is repeating.
151
For attributes whose type is DF_STRING, the getTypeAttrLengthAt and getTypeAttrLengthAt methods return the maximum character length of any string that can be stored in that attribute. For attributes of other types, these methods return 0. The get type attribute description methods return attribute descriptions from the data dictionary. This information does not reside in the dm_type object. Recall that IDfType derives from IDfPersistentObject, which, in turn, derives from IDfTypedObject. IDfTypedObject has the following methods:
Enumeration enumAttrs() int findAttrIndex(String attrName) IDfAttr getAttr(int index) int getAttrCount() int getAttrDataType(String attrName) boolean hasAttr(String attrName) isAttrRepeating(String attrName)
Developers often find this confusing. Calling these methods on an IDfType object returns information about the attributes of the type dm_type, not the type that the IDfType object describes. For example, suppose that the IDfType object named doctype describes the type dm_document. The method doctype.getAttrCount returns 15, even though dm_document has almost 70 attributes. The reason is that getAttrCount returns the number of attributes that dm_type has, not the number of attributes that dm_document has. To get the number attributes for dm_document, call
doctype.getTypeAttrCount
Similarly, if you call doctype.getAttrDataType("object_name"), DFC throws an exception, because dm_type does not have an attribute called "object_name". To discover the type of the dm_document attribute object_name, call getTypeAttrDataType("object_name"). All IDfType methods that return attribute information about the type that the IDfType object describes have method names that begin with getTypeAttr. The methods inherited from IDfTypedObject return information about dm_type.
152
Types that need any of these capabilities derive from dm_sysobject. Since the primary focus of Docbases is content, most objects in the Docbase are either SysObjects or objects whose type derives from dm_sysobject.
153
Folders and cabinets do not usually have associated content. They derive from IDfSysObject because folders use the ACL security mechanism. The preceding sections discuss all of the interfaces in , except for IDfDocbaseMap and IDfCollection. Discussion of those interfaces follows the discussion of the IDfSession and IDfClient interfaces.
IDfSession
All interaction with a Docbase occurs in a session, that is, using an IDfSession object. In broad terms, a session: Uses the underlying DMCL library to maintain a connection to a Docbase. Maintains the state of the interaction between an application and the Docbase. Caches information to increase performance. A session keeps track of the objects you fetch and change. It provides explicit and implicit transaction support. The underlying DMCL does most of this, but DFC also caches some information and maintains some state. Provides service methods for creating and fetching objects, performing administrative tasks, and obtaining session information.
Provide Information
The following methods ask for information that the session has access to:
IDfClient getClient(); IDfLoginInfo getLoginInfo() String getDBMSName()
154
String getDMCLSessionId() String getDocbaseId() String getDocbaseName() String getDocbaseOwnerName() String getLoginUserName() String getSecurityMode() String getServerVersion() String getSessionId() boolean isACLDocbase() boolean isAdopted() boolean isConnected() boolean isRemote() boolean isShared()
Note: Be careful not to write getRDBMSName for getDBMSName. The version without the Ris correct.
The short answer is that all persistent objects reside in the Docbase, so you can create or fetch them only through a session. Programming with DFC, page 13 discusses this point in more detail. The getObject methods return IDfPersistentObject interfaces, because IDfPersistentObject is the most derived interface that is general to all of the possible return types. For example, getObject could return an IDfType, an IDfUser, an IDfDocument, or an IDfFolder (among other possibilities). The only interfaces common to those types are IDfTypedObject and IDfPersistentObject. IDfPersistentObject is the more derived. The effect of this is that Java code must provide an explicit cast. For example
IDfFormat format = (IDfFormat) mysession.getObjectByQualification ("dm_format where name = tex);
The following methods support creating objects and obtaining object references:
int getDefaultACL() IDfACL getACL(String aclDomain, String aclName) IDfFolder getFolderByPath(String folderPath) IDfFormat getFormat(String formatName) IDfGroup getGroup(String groupName) IDfId getIdByQualification(String qualification) IDfPersistentObject getObject(IDfId objectId) IDfPersistentObject getObjectByPath(String objectPath)
155
IDfPersistentObject getObjectByQualification( String qualification) IDfPersistentObject getObjectWithType( IDfId objectId, String objType, String className) DfPersistentObject newObject(String typeName) DfPersistentObject newObjectWithType( String typeName, String className) DfType getType(String typeName) DfTypedObject getTypeDescription( String typeName, String attribute, IDfId businessPolicyId, String state) DfUser getUser(String userName) DfUser getUserByOSName( String userOSName, String userOSDomain)
Configuration Information
The Content Server documentation discusses configuration objects (see the sections dealing with apiconfig, sessionconfig, and serverconfig). The IDfClient interface provides the following methods. They return typed objects, because they return configuration information, not Docbase objects.
IDfTypedObject getClientConfig() throws DfException; IDfTypedObject getConnectionConfig() IDfTypedObject getDocbaseConfig() IDfTypedObject getDocbrokerMap() IDfTypedObject getServerConfig() IDfTypedObject getServerMap(String DocbaseName) IDfTypedObject getSessionConfig()
Transaction Support
The following are the basic methods for managing transactions:
void abortTrans() void beginTrans() void commitTrans()
Docbase Scope
Docbase scope tells the server which Docbase a method applies to. In many cases this does not change; in other cases, the server can determine it by examining a method argument that conveys the scope implicitly. For example, if one of the methods arguments is an object ID, the server can determine the Docbase scope from the ID.
156
The following are the basic methods for managing Docbase scope when necessary:
String getDocbaseScope() String setDocbaseScope(String DocbaseName) String setDocbaseScopeById(IDfId objectId)
Multithreading Support
If more than one thread can access a session, you must take care to lock and unlock the session before using it. The following IDfSession methods provide this capability:
boolean lock(int timeoutInMsec); boolean unlock();
You can lock the session explicitly (calling a method of IDfSession) or implicitly (calling a method of IDfPersistentObject, because persistent objects hold a reference to a session). Generally, you should lock and unlock blocks of code. If you lock and unlock a session at too fine a granularity, performance suffers and you increase the chance of making a mistake. If you lock too big a chunk of code, you cause other threads to wait needlessly, also hurting performance. DFC does not enforce the locking mechanism on sessions, so a multithreaded application must be careful to lock and unlock the session. Failure to do so can cause crashes. The need to protect a session against concurrent access applies to both shared sessions and private sessions (sessions obtained through the newSession call), but you must be especially careful if you share sessions across components in a multithreaded environment. You dont need to lock and unlock a session if only one thread at a time can use it. Tip In Java you can use the finally statement to ensure that a thread releases its lock when it dies. Lock sessions during transactions to prevent synchronization problems.
API Calls
Occasionally, an application needs to interact directly with the sessions underlying DMCL programs in ways for which DFC does not provide interfaces. The following routines allow such interactions:
ByteArrayInputStream apiGetBytes( String cmd, String args, String buf, String buflen, int length) IDfCollection apply( String objId, String functionName, IDfList args, IDfList dataType, IDfList values) IDfCollection getLastCollection()
157
IDfList apiDesc(String api) String apiGet(String cmd, String args) String describe(String type, String objType) String getMessage(int severityLevel) boolean apiExec(String cmd, String args) boolean apiSet(String cmd, String args, String value) boolean apiSetBytes( String cmd, String args, ByteArrayOutputStream content) void traceDMCL(int level, String traceFile)
Administration
The following methods support system administration:
IDfId archive( String predicate, String operatorName, int priority, boolean sendMail, IDfTime dueDate) IDfId restore( String predicate, String dumpFile, String operatorName, int priority, boolean sendMail, IDfTime dueDate) void changePassword(String oldPasswd, String newPasswd) void reInit(String serverConfigName) void reStart(String serverConfigName, boolean restartClient) void shutdown(boolean immediate, boolean deleteEntry)
158
Session State
The following methods enable you to control certain aspects of the session:
void disconnect() void flush(String flushType, String cacheKey) void flushCache(boolean discardChanged) void purgeLocalFiles() void setBatchHint(int batchSize)
Miscellaneous
IDfRelationType getRelationType(String relationName) IDfVersionTreeLabels getVersionTreeLabels(IDfId chronicleId) String getLoginTicket()
IDfClient
Most DFC programs start by obtaining an object that implements the IDfClient interface, through a call like the following:
IDfClient client = DfClient.getLocalClient();
The IDfClient object loads the DMCL shared library. Its main function is to create and share sessions, but programs also use IDfClient to get information about the available Docbases and to obtain certain DMCL configuration information. IDfClient also enables client programs to cache information.
159
specified index. IDfClient also provides methods for obtaining a docbroker map (the list of docbrokers that you can access) and a server map (the servers that you can access). It returns these maps as IDfTypedObjects. Typical client applications do not need these maps. The server documentation provides more information about them under the headings Docbroker Locator and Server Locator. IDfClient allows you to obtain information about your general client configuration through the getClientConfig method. This client configuration object maps to the API Config object discussed in the server documentation. Through this object you can dynamically configure such things as your Docbroker, the maximum number of simultaneous sessions allowed, and the maximum number of open collections allowed. You should alter the default values only after reading the server administration documentation.
Service Methods
The IDfClient object provides an IDfProperties object for caching and sharing information within your application. An IDfProperties object is an object that allows you to store name-value pairs. The method
getContext(String contextId)
returns the properties object for the specified ID or creates a new one if one does not already exist. The method
removeContext(String contextId)
removes the specified properties object. Some applications share data within a session by using this object. In this case, they typically use the session ID returned by the IDfSession method getSessionId as the context ID. You should not use the DMCL session ID (for example, s0) for this purpose. Applications should be careful to remove the properties object associated with a session when they no longer use that session.
Common Package
The com.documentum.fc.common package contains interfaces that client programs sometimes find useful. DFC wraps IDs and Time values in IDfId and IDfTime objects. To get an ID as a string you can call either getId or toString (they return the same thing). IDfTime objects allow you to perform time format conversions. Both the IDfId and IDfTime interfaces provide convenience methods. The getValue method returns an IDfValue object, which contains not only the attributes value, but also its type. IDfValue objects are convenient when you need to store an attribute value as an object (such as inserting it into a Java hashtable), but later need to determine its type as well as its value.
160
Avoid calling getValue if you can, because creating an additional object and obtaining and storing the type information are needless overhead if you dont use those features.
161
162
This chapter assumes that you are familiar with the methods that previous Documentum client products use to access server capabilities. It explains DFC by relating it to those methods. It contains the following main sections: Relationship to DMCL, page 163 This section explains the relationship between DFC and the Documentum client library (DMCL). Calling DMCL Directly, page 165 This section describes a way to bypass DFC and to communicate with the server via DMCL. DMCL to DFC Correspondence, page 165 This section contains a table of DMCL methods and the corresponding DFC methods.
Relationship to DMCL
The Documentum client library, DMCL, is a library of procedures and functions that implement the server API. DFC implements the API and an additional layer of related business logic, as shown in the following figure. It does so through a set of interfaces that client programs can use to access DFC from Java or COM.
Figure 101. DFC Builds Business Logic Above DMCL
Using DFC differs from using DMCL in the following ways: DMCL communicates via strings of arguments and results. DFC creates objects that implement specified interfaces. DMCL reports errors via error messages. DFC uses the Java exception mechanism.
The following calls show the ways to use DMCL to access the server.
163
Pass the method (create), the session ID (s0), and the argument.
char *object = dmAPIGet("create,s0,dm_document")
Pass the method (get), the session ID (s0), the object ID (09017...), and the argument.
char *name = dmAPIGet("get,s0,09017...,object_name")
DFCs IDfSession interface hides the session ID and object ID, leading to the following code corresponding to the first DMCL call:
IDfClient client = DfClient.getLocalClient(); IDfLoginInfo loginInfo = new DfLoginInfo(); loginInfo.setUser("user"); loginInfo.setPassword("password"); IDfSession session = client.newSession("docbase",loginInfo );
The third DMCL call can take either of the following forms with DFC:
String name = object.getString("object_name"); String name = object.getObjectName();
In the first form, you know that the attribute is a string. In the second form, you know that the object is of type dm_sysobject. If any of the DFC calls fails, DFC throws DfException, and the getMessage method of the exception object returns the same string that the DMCL getmessage method returns. DFC also performs the reset automatically. The following code fragments show how to handle the error: first in Java, then in Visual Basic:
try //Java { object.checkout(); } catch (DfException e) { // checkout failed System.out.println(e.getMessage()); } On Error GoTo errHandler #Visual Basic object.checkout GoTo finish errHandler: Dim e As IDfException Set e = cx.parseException(Err.Description) MsgBox e.getMessage finish:
The Visual Basic fragment assumes you have set cx via code like the following:
Dim cx as IDfClientX
164
cx = CreateObject(Documentum.Dfc)
Refer to the Content Server reference documentation for more information about how to use these methods. DFC returns a DfException object when a DMCL error occurs. In Java, use a try . . . catch code block to handle the error.
165
DMCL Append
DFC IDfTypedObject :: appendBoolean d IDfTypedObject :: appendDouble IDfTypedObject :: appendI IDfTypedObject :: appendInt IDfTypedObject :: appendString IDfTypedObject :: appendTime IDfTypedObject :: appendValue
Appendcontent Appendfile Appendpart Appendtask Apply Archive Assemble Attach Begintran Bindfile Branch Changepassword Checkin
IDfSysObject :: appendContent IDfSysObject :: appendFile IDfSysObject :: appendPart IDfRouter :: appendTask IDfSession :: apply IDfSession :: archive IDfSysObject :: assemble IDfSysObject :: attachPolicy IDfSession :: beginTrans IDfSysObject :: bindFile IDfSysObject :: branch IDfSession :: changePassword IDfSysObject :: Checkin IDfSysObject :: CheckinEx
Checkinapp Checkout
Count Create
166
DMCL Datatype Demote Dequeue Describe Destroy Disassemble Disconnect Dump End Fetch
DFC IDfTypedObject :: getAttrDataType IDfSysObject :: demote IDfSession :: dequeue IDfSession :: describe IDfPersistentObject :: destroy IDfSysObject :: disassemble IDfSession :: disconnect IDfTypedObject :: dump IDfRouter :: end IDfPersistentObject :: fetch IDfSession :: getObject IDfSession :: getObjectWithType
IDfSession :: flush IDfSession :: flushCache IDfRouter :: force IDfRouter :: forward IDfSysObject :: freeze
167
DMCL Get
DFC IDfTypedObject :: getBoolean IDfTypedObject :: getDouble IDfTypedObject :: getId IDfTypedObject :: getInt IDfTypedObject :: getTime IDfTypedObject :: getString IDfTypedObject :: getValue IDfTypedObject :: getAllRepeatingStrings IDfTypedObject :: getRepeatingBoolean IDfTypedObject :: getRepeatingDouble IDfTypedObject :: getRepeatingId IDfTypedObject :: getRepeatingInt IDfTypedObject :: getRepeatingString IDfTypedObject :: getRepeatingTime IDfTypedObject :: getRepeatingValue
Getcontent
Getdocbasemap
Getdocbrokermap
Getevents Getfile
IDfSession :: getLastCollection IDfSession :: getLoginTicket This happens automatically when the error occurs IDfSession :: getMessage
168
Grant
Halt Id Insert
IDfRouter :: halt IDfSession :: getIdByQualification IDfTypedObject :: insertBoolean IDfTypedObject :: insertDouble IDfTypedObject :: insertId IDfTypedObject :: insertInt IDfTypedObject :: insertString IDfTypedObject :: insertTime IDfTypedObject :: insertValue
IDfSysObject :: insertContent IDfSysObject :: insertFile IDfSysObject :: insertPart IDfRouter :: insertTask IDfSysObject :: link IDfTypedObject :: findBoolean IDfTypedObject :: findDouble IDfTypedObject :: findId IDfTypedObject :: findInt IDfTypedObject :: findString IDfTypedObject :: findTime IDfTypedObject :: findValue
169
DMCL Print Promote Prune Purgelocal Query Queue Readquery Reassign Register Reinit Remove
DFC IDfSysObject :: print IDfSysObject :: promote IDfSysObject :: prune IDfSession :: purgeLocalFiles IDfQuery.execute IDfSysObject :: queue IDfQuery.execute IDfRouter :: reAssign IDfSysObject :: register IDfSession :: reInit IDfTypedObject :: remove IDfTypedObject :: removeAll
IDfSysObject :: removeContent IDfSysObject :: removeNote IDfSysObject :: removePart IDfSysObject :: removeRendition IDfSysObject :: removeRenditionEx
IDfRouter :: removeTask IDfTypedObject :: isAttrRepeating Happens automatically when the error occurs IDfSession :: reStart IDfSession :: restore IDfRouter :: resumeRouter IDfSysObject :: resume
Revoke
Save
170
DFC IDfSysObject :: saveAsNew IDfSession :: setDocbaseScope IDfTypedObject :: setBoolean IDfTypedObject :: setDouble IDfTypedObject :: setId IDfTypedObject :: setInt IDfTypedObject :: setString IDfTypedObject :: setTime IDfTypedObject :: setValue IDfTypedObject :: setRepeatingBoolean IDfTypedObject :: setRepeatingDouble IDfTypedObject :: setRepeatingId IDfTypedObject :: setRepeatingInt IDfTypedObject :: setRepeatingString IDfTypedObject :: setRepeatingTime IDfTypedObject :: setRepeatingValue
Setbatchhint Setcontent
IDfSession :: setBatchHint IDfSysObject :: setContent IDfSysObject :: setContentEx IDfSysObject :: setIsVirtualDocument IDfSysObject :: setFile IDfSysObject :: setFileEx
Setdoc Setfile
IDfSysObject :: setPath IDfSession :: shutdown IDfRouter :: signOff IDfRouter :: start IDfSysObject :: suspend IDfSession :: traceDMCL IDfTypedObject :: truncate IDfSession :: getTypeDescription IDfSysObject :: unfreeze
171
IDfSysObject :: unmark IDfSysObject :: unRegister IDfSysObject :: updatePart IDfSysObject :: useACL IDfRouter :: validateRouter IDfTypedObject :: getValueCount
172
Index
A
abortTrans method, 156 ACLs, 62 private, 64 API calls, 157 to 158 API Config object, 160 apiDesc method, 158 apiExec method, 64, 158 apiGet method, 158 apiGetBytes method, 157 apiSet method, 64, 158 apiSetBytes method, 158 apply method, 157 archive method, 158
B
beginTrans method, 156
C
changePassword method, 158 close method, 56 collections stepping through, 57 com.documentum.com package, 19 com.documentum.fc.client package, 19 com.documentum.fc.common package, 19, 160 com.documentum.operations package, 19 com.documentum.registry package, 19 commitTrans method, 156 common.documentum.fc.client.qb package, 19 containment objects copy_child attribute, 22 copy_child attribute, 22
describe method, 158 DFC (Documentum foundation classes) comparison with DMCL, 165 datatypes, 17 DMCL process, 17 migrating to, 165 naming convention, 18 objects and pointers, 16 online reference, 20 server API callsx09, 165 DFC (Documentum Foundation Classes) COM interface, 13 elements, 13 DFC interface hierarchy, 140 DfClient class, 159 DfPersistentObject class, 156 DfQuery class, 55 DfType class, 156 DfTypedObject class, 156 DfUser class, 156 DfValidationException class, 61 disconnect method, 159 dm_cabinet type, 154 dm_folder type, 154 DMCL commands, 165 DMCL shared library, 159 Docbase scope, 156 docbrokers, 159 Documentum foundation classes. See DFC, 20 DQL queries, 55
E
enumAttrs method, 152 execute method, 57 External applications XML support, 22
D
dequeue method, 158
173
Index
F
findAttrIndex method, 152 flush method, 159 flushCache method, 159
G
getACL method, 155 getAllRepeatingStrings method, 144 getAttr method, 56, 152 getAttrCount method, 152 getAttrDataType method, 152 getBoolean method, 143, 154 getClient method, 154 getClientConfig method, 156, 160 getConnectionConfig method, 156 getContext method, 160 getDataType method, 56 getDBMSName method, 154 getDefaultACL method, 155 getDMCLSessionId method, 155 getDocbaseConfig method, 156 getDocbaseId method, 155 getDocbaseMap method, 159 getDocbaseName method, 155 getDocbaseOwnerName method, 155 getDocbaseScope method, 157 getDocbrokerMap method, 156 getDouble method, 143 getEvents method, 158 getFolderByPath method, 155 getFormat method, 155 getGroup method, 155 getId method, 143 getIdByQualification method, 155 getInt method, 143 getLastCollection method, 157 getLoginInfo method, 154 getLoginTicket method, 159 getLoginUserName method, 155 getMessage method, 158 getObject method, 155 getObjectByPath method, 155 getObjectByQualification method, 156 getObjectWithType method, 156 getQuery method, 55 getRDBMSName is incorrect, 155 getRelationType method IDfRelationType interface, 159 getRepeatingBoolean method, 144
getRepeatingDouble method, 144 getRepeatingId method, 144 getRepeatingInt method, 144 getRepeatingString method, 144 getRepeatingTime method, 144 getRepeatingValue method, 144 getRunnableProcesses method, 158 getSecurityMode method, 155 getServerConfig method, 156 getServerMap method, 156 getServerVersion method, 155 getSessionConfig method, 156 getSessionId method, 155 getString method, 56, 143 getTasks method, 158 getTime method, 143 getType method, 156 getTypeDescription method, 156 getTypedObject method, 56 getUser method, 156 getUserByOSName method, 156 getValue method, 143, 160 when to avoid, 160 getVersionTreeLabels method, 159 grant method, 62 to 63
H
hasAttr method, 152 hierarchy, of DFC interfaces, 140
I
IdfACL interface, 155 IDfAttr interface, 152 IDfClient interface, 14, 154, 156, 159 IDfClientX interface, 55 IDfCollection interface, 55 to 57, 157 to 158 IDfDocbaseMap interface, 159 IDfDocument interface, 154 IDfFolder interface, 155 IDfFormat interface, 155 IDfGroup interface, 155 IDfId interface, 143 to 144, 155, 158 IDfList interface, 158 IDfLoginInfo interface, 154 IDfPersistentObject interface, 139, 155 to 156 IDfProperties interface, 160 IDfSession interface, 14, 154, 157 IDfSysObject interface, 19, 152
174
Index
IDfTypedObject interface, 156 IDfValidator interface, 61 IDfValue interface, 160 IDfVersionTreeLabels interface, 159 IDfWorkflowBuilder interface, 158 IDfXMLTransformOperation, 39, 41 isACLDocbase method, 155 isAdopted method, 155 isAttrRepeating method, 152 isConnected method, 155 isRemote method, 155 isShared method, 155
N
newObjectWithType method, 156 newWorkflowBuilder method, 158
P
permissions, 62 to 63 persistent objects, 138, 155 private ACLs, 64 purgeLocalFiles method, 159
setDocbaseScope method, 157 setDocbaseScopeById method, 157 setDouble method, 143 setId method, 143 setInt method, 143 setRepeatingBoolean method, 144 setRepeatingDouble method, 144 setRepeatingId method, 144 setRepeatingInt method, 144 setRepeatingString method, 144 setRepeatingTime method, 144 setRepeatingValue method, 144 setString method, 143 setTime method, 143 setValue method, 143 shutdown method, 158 subtypes, 138 supertypes, 138 to 139 sysobjects, 152
T
traceDMCL method, 158 transactions, 156 transformations, 40 type libraries, 13 typed objects, 156
Q
queries, 56 to 57 displaying results, 57 flow of processing, 55
U
unlock method, 157
R
reInit method, 158 removeContext method, 160 repeating attributes, 145 resolveAlias method, 158 restore method, 158 revoke method, 63 rows, 56
V
validateAttrRules method, 62 virtual documents containment objects copy_child attribute, 22 copy behavior, defining, 22 defined, 21 purpose, 21 versioning, 22
S
save method, 64 sendToDistributionList method, 158 session ID, 41 sessions, 154, 159 multithreading, 157 setACL method, 64 setBatchHint method, 159 setBoolean method, 143
W
workflow templates, 158 workflows, 158
X
Xalan transformation engine, 39
175
Index
XML support, 22
XSLT stylesheets, 39
176