2 Understanding the UCPM API

The Universal Content and Process Management (UCPM) API offers access to Oracle Content Server instances by exposing their services and data in a unified object model. The UCPM API is modeled into a set of services APIs that communicate with the target server.

This chapter contains the following sections:

2.1 Accessing the UCPM API

The UCPM API offers access to Oracle Content Server instances by exposing their services and data in a unified object model. The UCPM API is modeled into a set of services APIs, which are API calls that communicate with the target server, and into ICISObject objects, which are the value objects returned from the server.

The UCPM API is available on the ICISApplication class via the getUCPMAPI() method. The getUCPMAPI() method returns a reference to the IUCPMAPI object, allowing access to all UCPM API objects. The public interface IUCPMAPI is the locator for the getActiveAPI object; getActiveAPI() returns a reference to the SCSActiveAPI object. The SCS API classes communicate with, and handle content stored on, the content server.

2.2 UCPM API Methodology

The UCPM API is stateless; all method calls pass in the necessary state to the method. This means that you can share the reference to the CISApplication class across threads.

  • ISCSContext for the SCS API. The ISCSContext interface is the context object used when communicating with the content server.

  • ICISCommonContext for calling some of the CIS APIs. The ICISCommonContext interface identifies which adapters to query and what user information to use.

The first parameter for all methods is an IContext bean. The IContext bean holds context information, such as username and session ID, which is used in the underlying service APIs to identify the user invoking the given command.

The UCPM API is a service-oriented API that returns value objects, implemented as ICISObject objects (name changed from the 7.6 API). However, calling methods on the value objects themselves do not modify content on the server; one must call the UCPM API and pass in the value object as a parameter before the changes can be applied.

Example:

SCSActiveAPI activeAPI = m_cisApplication.getUCPMAPI ().getActiveAPI ();
ISCSDocumentID documentID = (ISCSDocumentID) m_cisApplication.getUCPMAPI ().
  createObject(ISCSDocumentID.class);
documentID.setDocumentID("10");
ISCSDocumentInformationResponse docResponse =
  activeAPI.getDocumentInformationAPI ().
  getDocumentInformationByID(m_context, documentID);
ISCSContent content = docResponse.getDocNode();

// call does not change object on server
  content.setTitle ("New Title");

// now item is updated on server after this call
  activeAPI.getDocumentUpdateAPI ().updateInfo (m_context, content);

2.3 CIS Initialization

Content Integration Suite (CIS) is initialized by accessing the CISApplicationFactory class, which resides in the com.stellent.cis.impl package.

This section contains the following topics:

2.3.1 Initialization

CIS initialization should happen once per application. The CIS APIs are stateless and the initialized CISApplication instance can therefore be safely shared between threads.

To initialize CIS, a number of properties must be defined. The cis.config.type should be server and the cis.config.server.type should be standalone. The adapter configuration file contains XML-formatted configuration information for communicating with the content servers.

Initialization Examples

Initializes the system and reads the adapterconfig.xml file from the classpath:

cis.config.type=server
cis.config.server.type=standalone
cis.config.server.adapterconfig=classpath:/adapterconfig.xml

Code example:

ICISApplication application;
  URL xmlRes = new File ("adapterconfig.xml").toURL()
  Properties properties = new Properties();
  properties.setProperty(ICISApplication.PROPERTY_CONFIG_TYPE, "server");
  properties.setProperty(ICISApplication.PROPERTY_CONFIG_SERVER_ADAPTER_CONFIG,
    xmlRes.toExternalForm());

properties.setProperty(ICISApplication.PROPERTY_CONFIG_SERVER_TYPE, "standalone");
application = CISApplicationFactory.initialize(properties);

Property Definitions

The properties are defined in the following table.

Property Description
cis.config.type Should be set to server.
cis.config.server.type Should be set to standalone.
cis.config.server.adapterconfig The URL pointing to the adapter configuration file. In addition to standard URLs, this can be in classpath form (classpath:/) or file form (file:/)
cis.config.server.temporarydirectory The location of the temporary directory used for file transfers, streaming, and file caching.

2.3.2 SCSInitializeServlet

The SCSInitializeServlet is a convenient way to initialize a CISApplication instance from within a web application. Any of the properties described can be used by the SCSInitializeServlet. The SCSInitializeServlet can be configured externally via a properties file. The cis.initialization.file property can be set with a path (either a web-relative path or a classpath reference), to a property file containing the initialization properties. This allows you to easily externalize the initialization to a properties file.

By default, if SCSInitializeServlet finds no properties in the web.xml file, it will attempt to load a properties file from the WAR and then from the classpath using the default value /cis-initialization.properties. Thus, if you place a file called cis-initialization.properties in your classpath (that is, in the same directory as the adapterconfig.xml file), that file will be read during startup.

This properties file can hold all the standard initialization properties as defined in the CISApplication class. This allows you to move the configuration of how CIS initializes outside the scope of the EAR/WAR file.

Server Property Definitions

The server properties are defined below. The defaults can be overridden by creating a file named cis-initialization.properties and saving the file to the server-ear directory of the unbundled CIS distribution file (this is the directory containing the adapterconfig.xml file).

Property Description
cis.config.type Must be set to server (default).
cis.config.server.adapterconfig The URL pointing to the adapterconfig.xml file. In addition to standard URLs, this can also be in classpath form (that is, classpath:/)
cis.config.server.type.options.ejb=true Default is true (EJBs enabled).
cis.config.server.type.options.rmi=true Default is true (MI enabled).

Initialization Process

At startup, the SCSInitializeServlet servlet begins the CIS server initialization process. It attempts to load various properties from the web.xml file and classpath (that is, cis-initialization.properties). It then passes those properties to the static method CISApplicationFactory.initialize(…). This section describes the order of operation.

SCSIntitialize init(ServletConfig)

Called by the web application container during initialization of the web application.

  1. Load properties from web.xml.

  2. Load properties from classpath: /cis-initialization.properties.

  3. Call CISApplicationFactory.initialize(properties).

  4. Via the CISWebHelper class, it sets the CISApplication and the command application instance as an attribute on the servlet context.

CISApplicationFactory initialize(properties)

Called by the init(…) method of an object instance of SCSInitialize. Calls CISApplicationFactory.initializeCisApplication(properties).

CISApplicationFactory initializeCisApplication(properties)

Determines if CIS should be started in client or server mode. Calls CISApplicationFactory.initializeServer(properties).

CISApplicationFactory initializeServer(properties)

Called by CISApplicationFactory.initialize(properties).

  1. Creates the adapter config URL (used to eventually load the adapterconfig).

  2. Loads IsolatedJarClassloader.

  3. Calls CISApplication.initialize(properties).

2.4 Integration in a Web Environment

This is what you would put in the web.xml if you wanted the SCSInitializeServlet to start up and register the CIS application:

<servlet id="scsInitialize">
  <servlet-name>scsInitialize</servlet-name>
  <display-name>SCS Initialize Servlet</display-name>
  <servlet-class>com.stellent.cis.web.servlets.SCSInitializeServlet
    </servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>

If you add a new JavaServer Page called search.jsp, it would look like the following:

<%-- JSTL tag library --%>
<%@ taglib uri="/WEB-INF/tlds/c.tld" prefix="c" %>

<%--  CIS Application object placed in servlet context by the SCSInitialize servlet. Get the CIS Application and make a query --%>

<%
ICISApplication cisApplication =
  (ICISApplication) request.getSession().getServletContext().
    getAttribute ("CISApplication");
ISCSSearchAPI searchAPI =
  cisApplication.getUCPMAPI ().getActiveAPI ().getSearchAPI ();

// create a context
ISCSContext context =
  cisApplication.getUCPMAPI ().getActiveAPI ()._createSCSContext ();
  context.setUser ("sysadmin");

// execute the search
ISCSSearchResponse response =
  searchAPI.search (context, "dDocAuthor <substring> 'sysadmin'", 20);
%>
<!-- model the search results as desired -->

The SCSInitializeServlet places the initialized CISApplication class as an attribute in the javax.servlet.ServletContext with the name CISApplication. The CISApplication instance is available to the entire web application and is thread-safe; the one instance can be shared across the application.

2.5 Classloading

The UCPM 8.0.0 API uses a custom class loader to isolate dependencies on specific libraries from any application that uses the CIS API. Refer to the Java 2 Platform API specification for more information:

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html

This section contains the following topics:

2.5.1 Custom Class Loader

Our implementation of this paradigm is found in the com.stellent.cis.impl.IsolatedJarClassLoader object. This custom class loader allows for a jar to have a nested set of jar files that serve as the library. This is the structure of the nested jar files:

+ cis-application-8.0.0.jar
    +-- com/stellent/cis/...
    +-- META-INF
    +-- lib/
        +-- spring-1.1.5.jar
        +-- log4j-1.0.3.jar
        +-- ...

All libraries that live in the /lib directory will be the classpath for the CIS objects. The classloader will query this local directory first before loading files from the parent classloader.

However, all of the jar files cannot be isolated as the consuming client needs to have access to some API classes so they can be imported into their application space. Therefore, only our interfaces are exposed into the application space; keeping our implementation and associated dependencies isolated. Since the class loader for the dependencies and implementation has access to the parent loader, it can access the same version of the interfaces as the application using the APIs. This also implies that a client will only be able to access the interfaces of the UCPM APIs. Any attempt to create an implementation class using the new keyword will result in a ClassNotFoundException.

2.5.2 Classloader Usage

To use this classloader, use the new com.stellent.cis.impl.CISApplicationFactory object to initialize the system. This object will automatically detect and use the IsolatedJarClassLoader if required. This means that you can still deploy CIS in the original format, with all the class files and libraries at the application level, if you so desire.

In the current version, CIS only needs the cis-client-8.0.0.jar file in the classpath; no other libraries are needed. Once cis-client-8.0.0.jar is in the application classpath, you initialize CIS using the following code:

// the initialization properties (as defined in ICISApplication)
  Properties properties = new Properties ();
  ICISApplication cisApplication = CISApplicationFactory.initialize(properties);

Once you have a reference to com.stellent.cis.ICISApplication, you can interact with the APIs. The difference is that now you only have access to interface objects (everything in com.stellent.cis.client) and not the implementation objects.

If you implement custom commands, your public interfaces will also need to be in the classpath, and the implementation classes packaged in the cis-client-8.0.0.jar.

2.6 Object Creation

The UCPM 8.0.0 API uses a customized classloader to hide library dependencies and implementation classes. Only the client interface classes are exposed to the user. However, this implies that you cannot use the new keyword to instantiate UCPM API objects. Therefore, in the UCPM API framework, use the generic _create methods available on the IUCPMAPI object to tell the system to instantiate an instance of the given object.

Since objects are mutable and only the interfaces are exposed, use the createObject method and set the properties that you need:

ISCSDocumentID docID =
  (ISCSDocumentID)ucpmAPI.createObject(ISCSDocumentID.class);
docID.setDocumentID("20");

2.7 Interacting With the UCPM API

With an initialized CISApplication instance, the getUCPMAPI () method (of the CISApplication object) returns a reference to the IUCPMAPI object, allowing access to all UCPM API objects. The IUCPMAPI interface is the locator for the various API objects in the UCPM API. The IUCPMAPI object has methods to get references to the Active API; getActiveAPI () returns a reference to the SCSActiveAPI object for communicating with the content server. This allows you to access the necessary APIs and begin making calls through the UCPM API to the target server.

Calling API Objects Using Newly Instantiated ICISObject Objects

Many UCPM API calls take in an ICISObject or an interface that inherits from ICISObject. For example, in the ISCSDocumentInformationAPI (SCS API) the getDocumentInformationByID () method takes as a parameter a ISCSDocumentID object.

The fully qualified method name is:

ICISApplication.getUCPMAPI ().getActiveAPI ().getDocumentInformationAPI ()

In such cases, to obtain a reference to a valid object to pass in as a parameter, you can either retrieve the object reference from another ICISObject or create a new instance of the ICISObject using the generic createObject method available in the UCPM API. In CIS 11gR1, a customized classloader is used to hide our library dependencies and implementation classes. Only our client interface classes are exposed to the user. However, this implies that you cannot use the new keyword to instantiate UCPM API objects. Therefore, in the CIS API framework, you use the generic create method available on the IUCPMAPI object to tell the system to instantiate an instance of the given object. The createObject method will let you create a new instance of any ICISObject.

For example, if you wanted to query for document information, but only had the document ID, you would do the following:

ISCSDocumentInformationAPI documentInfoAPI =
  m_cisApplication.getUCPMAPI ().getActiveAPI ().getDocumentInformationAPI ();

// create the document ID
ISCSDocumentID documentID =
  (ISCSDocumentID) m_cisApplication.getUCPMAPI ().
    createObject (ISCSDocumentID.class);
  documentID.setDocumentID("12345");

ISCSDocumentInformationResponse docResponse =
  documentInfoAPI.getDocumentInformationByID(m_context, documentID);

For any API that requires an ICISObject, you can use the createObject method that allows you to create a new instance of the API object. The createObject methods is a client-side method; it does not make a call to the target server. It is to be treated as a constructor for the ICISObject implementations.

If you needed to build up a more complex object such as a new content item to be checked into the content server, you would need to create several objects and populate the data:

// Create an empty content object
ISCSContent content =
  (ISCSContent) m_cisApplication.getUCPMAPI ().createObject(ISCSContent.class);

// Create an empty content ID object, and then give it a content ID
ISCSContentID contentID = (ISCSContentID) m_cisApplication.getUCPMAPI ().
  createObject(ISCSContentID.class);
  contentID.setContentID("my_document");

// Set all of the properties of the content item required for check in
  content.setContentID(contentID);
  content.setAuthor (context.getUser ());
  content.setTitle ("Document Title");
  content.setSecurityGroup ("Public");
  content.setType ("ADACCT");
  content.setProperty ("xCustomProperty", "Value for custom property");

2.8 Interface IContext

The interface IContext is the generic context used for communication with the Command APIs. This interface handles contextual information to determine the current caller identity, the target adapter, and so on.

The context should be populated with the username and adapter name. The adapter name is determine by the adapterconfig.xml file and the username can be any valid user ID for the target server.

IContext has the sub-interfaces SCSContext (ISISContext extends the IContext interface); ISCSContext is the context object used for the SCS APIs and represents a users operating context when communicating with the content server.

The context object can be created by using the _create method. Thus, ISCSContext can be created from SCSActiveAPI.

// create an ISCSContext
  ISCSContext context =
  m_cisApplication.getUCPMAPI ().getActiveAPI ()._createSCSContext ();

Once the context is created, it should be populated with a username and the adapter name. This can be done by using the accessor methods on the IContext bean.

  context.setUser ("sysadmin");
  context.setAdapterName ("myadapter");

The CIS API will take either an ICISCommonContext or an IContext object. ICISCommonContext is a special kind of context that is used as a container for ISCSContext and ISISContext. It is required in APIs that federate information between a number of different adapters; it identifies which adapters to query and what user information to use. In instances where the call only operates against one adapter at a time, a single IContext is required.

// create an ICommonContext
  ICISCommonContext m_commonContext =
  m_cisApplication.getUCPMAPI ().getCommonAPI ()._createCommonContext ();

Once the ICISCommonContext adapter is created, multiple adapters can be added to it. This is done using the ICISCommonContext.addContext() method. Any number of adapters can be added; all the adapters added to the ICISCommonContext are then used individually during a Common API call.

The same ISCSContext object can be used for multiple queries and across threads. In a web application context, the easiest method is to add the IContext object to the session and retrieve it from the session for each query.

An sample web application has been provided (located in /SDK/Samples/WebSample) which has a login method that first validates the username against the content server and, if successful, adds the IContext object to the HttpSession object. Refer to the LoginActionHandler class in the src/com/stellent/sdk/web/sampleapp/handlers/login directory for more details.

2.9 Interface ICISObject

The interface ICISObject is the base interface for all objects with metadata in the UCPM API. Thus, all UCPM API objects are inherited from ICISObject. The interface ICISObject allows for the retrieval and setting of the object properties. The objects returned from calls to the UCPM API are value objects in the form of beans (reusable software components) that encapsulate data from the server call, not live objects. Updating or modifying the objects in any fashion will not affect server data; only by directly calling a method on a given UCPM API can the server data be modified.

This section contains the following topics:

2.9.1 Property Accessors

Most implementations of ICISObject have their own specific property accessor methods. However, all properties can be retrieved by calling the getProperty () method on the ICISObject. The ICISObject.getProperty () method will return an ICISProperty object. From this object you can get the property value or property information using these methods:

  • getValue() returns the property value. If the property has a null value, calling getValue () will result in a null reference.

  • getDescriptor() returns the property descriptor that describes the contents of the property value.

// use the response object from the previous example - retrieve the content object
  ISCSContent content = docResponse.getDocNode ();

// get the title property
  String title = content.getTitle ();

// get the title by using the ICISObject getProperty method
  title = content.getProperty ("title").getValue ().getStringValue ();

The ICISObject property methods may throw a PropertyRetrievalException if an error occurs during the lookup of a given property. Since the PropertyRetrievalException is a RuntimeException, it does not have to be caught directly in your code. Common cases for the exception to be thrown is when a property is asked for but does not exist or when the property value contains invalid data. You can catch this exception and query the exception class for more details on the specific reason for the error.

ISCSProperty also allows for setting property values back into the property object. To do this, you can use an appropriate set method or call setProperty () and pass in the bean property name (both are valid and both will set the property value on the target object).

// set the title - using the content object from the previous example
  content.setTitle ("My New Title");

// set using the setProperty method
  content.setProperty ("title", "My New Title");

2.9.2 Property Object Types

A property object type is determined by the return value of the property method on the ICISObject. When using the generic getProperty() method, the ISCSPropertyValue has methods to get both the value of the property and the value as a specific object type (for example, boolean, float, long, and so on).

The ISCSPropertyValue is retrieved via the getValue() method on the returned ISCSProperty object.

When setting a property via the generic setProperty() method, it is important that the property value passed into the method is of the correct type or can be converted to the appropriate type via simple BeanUtils property conversion.

Apache BeanUtil is a utility for populating bean properties from the org.apache.commons project.

If we take a look at the ISCSContent object, the property readOnly is type boolean. Therefore, in the following example, the first three methods will successfully set the property value and the last method will not:

// correct
  content.setReadOnly (true);
  content.setProperty ("readOnly", Boolean.TRUE);
  content.setProperty ("readOnly", "true");

// incorrect
  content.setProperty ("readOnly", "not a boolean");

Since the setProperty () method takes an object as the second parameter, the boolean encapsulation must be used. Also, as mentioned, the method uses the BeanUtils property conversion and therefore the string true converts to the boolean value TRUE. As shown in the example above, passing a property value that cannot be converted (for example, not a boolean) will result in an exception.

2.9.3 Property Collections

The available list of properties can be retrieved using the getProperties() method on the ICISObject interface. This will return all of the available properties for a given object.

// using the content item from the previous example
  Collection properties = content.getProperties ();

// iterate through the collection
for (Iterator it = properties.iterator (); it.hasNext (); ) {
  ISCSProperty property = (ISCSProperty)it.next ();
  String name = property.getDescriptor ().getName ();
  ICISPropertyValue value = property.getValue ();
  if (value != null) {
     System.out.println (name + " = " + value.getStringValue ());
  }
}

2.10 Adapter Configuration File

The adapter configuration file (adapterconfig.xml) contains XML-formatted configuration information for communicating with your Oracle Content Server instance. It specifies for the CIS layer which servers to open communications with.

A single connection to a server is called an adapter; any number of adapters can be configured in the adapterconfig.xml file. The adapterconfig.xml file is required to initialize the CISApplication instance.

This section contains the following topics:

2.10.1 Adapter Element

Each adapter configuration is a separate element in the XML markup. The adapter element has four attributes as shown in the following table:

Adapter Attributes Description
type Should be scs for a connection to Oracle Content Server.
default If true, then this is the default adapter for this type. Only one default adapter for a given type is allowed.
name The adapter name.

A sample adapter element is shown below:

<adapter type="scs" default="true" name="myadapter">

2.10.2 Config Element

The config element includes a set of property elements that define the adapter-specific properties. These configuration elements are explained below.

SCS Adapter Configuration Elements

An SCS adapter communicates with the content server. The configuration element for the SCS adapter has four general attributes as shown in the following table:

Property Name Description
post The port of the content server.
host The hostname or IP address of the content server.
type These values may be used:

socket: Uses the content server socket communication layer.

mapped: Uses shared directories to transfer the files for file upload and download.

web: Uses HTTP requests to transfer files; requires a content server username and password for Basic HTTP Authentication (file download only).


A sample SCS configuration element is shown below:

<adapter name="myadapter" type="scs" default="true">
  <config>
    <property name="host">localhost</property>
    <property name="port">4444</property>
    <property name="type">socket</property>
    <property name="version">75</property>
  </config>
  <beans template=
  "classpath:/META-INF/resources/adapter/adapter-services-scs.jxml"/>
</adapter>

By default, the content server socket communication layer is used to stream files to and from the content server. However, for high-volume check in or file retrieval, you can set the mapped or web optimized file transfer options.

A mapped transfer loads the files from a shared directory on the content server; this results in much faster file transfers and does not tie up a socket that could be used for other requests. To use mapped transfer, you must define these properties:

Property Name Description
contentServerMappedVault The content server vault directory as seen from the application server.
appServerMappedVault The application server vault directory as seen from the content server.

A web transfer uses HTTP requests to the content server web server to download files. To use web transfer, you must define these properties:

Property Name Description
contentServerAdminID The content server administrator ID to use to authenticate against the content server.
contentServerAdminPassword The content server administrator password to use to authenticate against the content server. This password is encrypted.

A sample SCS configuration element using web transfer is shown below:

<adapter type="scs" default="true" name="myadapter">
  <config>
    <property name="port">4444</property>
    <property name="host">localhost</property>
    <property name="type">web</property>
    <property name="contentServerAdminID">sysadmin</property>
    <property name="contentServerAdminPassword">idc</property>
  </config>
</adapter>