Accessing Service-based Business Objects (SBOs) from .NET
|
September 2004
|
Customization Types
SBO Access From .NET
Overview
This convenience class allows developers to access Documentum Service-based Business Objects (SBOs) from .NET languages. The class allows .NET developers to make use of the existing Java-based business objects that ship with Documentum products or are downloaded from the Component Exchange.
Software Environment
|
Feature |
Tested
on |
| Operating System |
Windows 2000 Server SP4 |
| Compiler |
MS Visual C# .NET Compiler version 7.10.3052.4 |
| Runtime Environment |
MS .NET Runtime 1.1.4322.573 |
| E-Content Server |
5.2.5 SP1 |
| DFC |
5.2.5 SP2 |
| DFC Primary Interop Assembly |
5.2.5.12 |
Programming Languages
Dependencies
None
Architecture
Background
When programming in Java, a new SBO instance is
instantiated by calling the IDfClient#newService() method.
This method takes two parameters - the name of the service required and the session manager. Depending
on the name of the service, the method constructs an instance of the specified SBO
implementation class and returns it to the caller. When calling this method from Java, the caller can simply cast this
returned instance to the appropriate SBO Java interface that the caller is expecting.
However, casting does not work when IDfClient#newService() is
called from a .NET language such as C# or VB.NET because the SBO interface is not known in the .NET world. The
workaround to this is to invoke IDfClient#newService() from .NET using reflection.
To access an SBO from .NET the DFC Primary Interop Assembly (PIA) classes should be used
everywhere except when calling the method IDfClient#newService(). Instead, this method
should be invoked using reflection. This will return a COM object that represents the
SBO instance. The SBO methods can then be invoked on this instance using reflection. The following code shows
how this can be done,
IDfClientX clientX = new DfClientXClass();
IDfClient localClient = clientX.getLocalClient();
Type lcType = localClient.GetType();
object[] metParams = {serviceName,sessMgr};
object servObj = lcType.InvokeMember("newService",BindingFlags.InvokeMethod,null,localClient,metParams);
|
The servObj instance created above can then be used to make the SBO calls.
For example,
Type serviceObjectType = servObj.getType();
IDfId folderid = clientX.getId("12345678");
string localFolderToImport = "c:\\devprog\\test";
object[] servMethodParams = {folderId,localFolderToImport};
IDfId newFolderId = (IDfId) serviceObjectType.InvokeMember("deepImportFolder",
BindingFlags.InvokeMethod,null,servObj,servMethodParams);
|
In the above code sample, note the cast of the return type. It is only possible to cast the
return type to PIA types and base .NET types such as string, int, and float. Also,
only SBO methods that have these standard types can be accessed. It is not possible to access SBO methods that have custom
Java classes as their arguments. For example, it is not possible to access the WebContentDownloader
SBO, (available from the Component Exchange), because one of the arguments it accepts is the Java class
java.net.URL.
Note: Only using the base .NET types or PIA types as arguments is an essential best practice for SBOs that may be used across Java and .NET.
Convenience Class
A convenience base class called SBOBridge has been created that
wraps the above piece of code into utility methods. The public static method
SBOBridge#NewService(...) creates a new service object and returns
an instance of SBOBridge. This instance of
SBOBridge contains the late-bound service COM object on which
SBO methods can be invoked using reflection.
The SBOBridge contains another method called InvokeSBOMethod(...). It can be used to invoke methods
on the contained SBO 'object'. Thus,
//Creating the deepExportService present on the component exchange
string serviceName = "com.documentum.devprog.deepexport.IDpDeepExportService";
IDfSessionManager sessMgr = ...
SBOBridge sbo = SBOBridge.NewService(serviceName,sessMgr);
//now invoke method on SBO
IDfId fldrId = clientX.getId("12345");
string localPath = "c:\\devprog\\exportTest";
string exportedLocalPath = (string)sbo.InvokeSBOMethod("deepExportFolder",fldrId,localPath);
|
The above code assumes that the deepExport SBO has been installed and registered in the DBOR .The SBO jar needs to
be in the user CLASSPATH variable.
The SBOBridge implements the DFC's IDfService interface and provides implementation for the various methods
of the IDfService interface. The implementation of these methods invokes the corresponding
method on the contained service 'object'. Thus,
string version = sbo.getVersion();
string name = sbo.getName();
|
where getVersion() is a standard method of the
IDfService interface
Creating custom accessors around existing SBOs
It is possible to subclass the SBOBridge class and provide custom
wrapper methods instead of directly using the InvokeSBOMethod(..)
method. This will ensure type-safety in C# and callers will be able to invoke a method whose
name semantically corresponds to the operation the method is going to perform. This method
could simply invoke the InvokeSBOMethod(...) or do some custom
operations before invoking the SBO method. For example, the method below checks whether
the filesystem path actually exists before invoking the SBO method.
class DeepExportService : SBOBridge
{
public String deepExportFolder(IDfId folderId,String localFilesystemPath)
{
if(File.Exists(localFilesystemPath)
{
string localPath = (string) invokeSBOMethod("deepExportFolder",folderId,localFilesystemPath);
return localPath;
}
return "";
}
}
|
To support custom subclasses of SBOBridge, a public static method on SBOBridge called
NewServiceWithClass(string serviceName,IDfSessionManager sessMgr,string assemblyFile,string className)
is provided. This method instantiates a service with a .NET wrapper class specified by
className contained in the assembly specified by
assemblyFile. The class specified by className
must be a subtype of SBOBridge. For example, the following code creates
a new deep export SBO that has the previously defined .NET wrapper
class DeepExportService.
string name = "com.documentum.devprog.deepexport.IDpDeepExportService";
IDfSessionManager sessMgr = ...
string className = "Documentum.Devprog.DeepExport.DeepExportService";
DeepExportService expServ = (DeepExportService)SBOBase.newService(name,sessMgr,className);
expServ.deepExportFolder(fldrId,"c:\\devprog\\test");
|
Disposing the SBO
The SBOBridge class or any of its subclasses will hold the late-bound SBO COM object. This COM object
must be released after the service usage is over. The SBOBridge implements the IDisposable pattern and the release
of the COM object happens in the Dispose() method. You can either call the Dispose() method explicitly
or leave it to .NET to call Dispose() by coding with the using(...) {} paradigm.
try{..} finally{}
SBOBridge bridge = null;
try
{
bridge = SBOBridge.NewService(...);
//use service here
}
finally
{
bridge.Dispose();
}
|
using(...){}
SBOBridge bridge = SBOBridge.NewService(...);
using(bridge)
{
....
}
|
Installation
Extract the SBOBridge.zip file into a location of your choice. The following files will be extracted:
- Documentum.Devprog.Bof.SBOBridge.dll - This is the assembly that contains the SBOBridge class
used to access SBOs from .NET. This assembly is not signed and hence cannot be added to the
Global Assembly Cache (GAC). Thus, to use or reference this assembly it will need to be in
one of the folders specified in the system PATH variable.
- SBOBridgeTester.exe - This is an application used to test the SBOBridge class.
- Documentation.zip - This file contains the HTML Help generated documentation.
- Projects.zip - This file contains the VS.NET solution. You can open this using VS.NET
and browse the source code
- Unzip the Solution.zip into any location of your choice.
- This should extract two folders 'SBOBridge' and 'SBOTester'
- Open the file SBOBridge\Documentum.Devprog.Bof.sln
- This should open up the VS.NET solution that contains two projects - SBOBridge and SBOTester
-
Configuration
To use the tester application, download and install the following SBOs from the Documentum
Component Exchange. Make sure that their Java Archive (JARs) locations are
referenced in the user CLASSPATH environment variable.
Testing
- Make sure that the Documentum.Devprog.Bof.SBOBridge.dll assembly is in one of the directories
specified in the PATH system variable or it is in the same folder as SBOBridgeTester.exe program
- Run the SBOBridgeTester.exe program
- Clicking on button labeled 'TestDeepExport' shows a window that accepts parameters to test the deep export service
- Clicking on button labeled 'TestDeepImport' shows a window that accepts parameters to test the deep import service
Known Issues
None known at the time of release
Bug Submissions
If you find bugs or issues with the component, please contact
developer_program@documentum.com
with a short description of the issue, steps to reproduce it and the relevant software environment.
|