Skip to main content

Integrate with IBM Records Manager Using Web Service API

Jin Liang Shi (shijl@cn.ibm.com), Software Engineer, IBM
Jin Liang Shi
Jin Liang Shi is a software engineer for IBM in China Software Development Lab, and focus on the development of IBM Records Manager and Content Manager Records Enabler.
Dou Ma (madou@cn.ibm.com), Software Engineer, IBM
Dou Ma
Dou Ma is a software engineer for IBM in China Software Development Lab, and focus on the development of IBM Records Manager and Content Manager Records Enabler. He has over 4 years software development experience in web technology, globalization and accessibility.
Lang Xin Pei (langxp@cn.ibm.com), Staff Software Engineer, IBM
Lang Xin Pei
Lang Xin Pei is working as a staff software engineer in IBM China Software Development Lab. He has many years experience in the integration of software system and the development of J2EE based information system. Now he focus on the development of IBM Records Manager product.

Summary:  This article is an introduction to IBM Records Manager Web service API and describes how to use IBM® Records Manager Web Service API in Java™ applications.

Date:  10 Jul 2009
Level:  Intermediate PDF:  A4 and Letter (40KB | 14 pages)Get Adobe® Reader®
Activity:  1797 views
Comments:  

Overview

IBM Records Manager provides an embedded engine for records management, which can be integrated with some external content management repositories. The content management system can leverage this record management capability to make themselves record-enabled. There are two methods to be provided by IBM Records Manager, the first one is EJB API, and the other is Web Service interface. This article will focus on the IBM Records Manager Web service interface.

The accession of IBM Records Manager Web services is based on standard SOAP protocol. Generally, the transportation of SOAP message is though HTTP connection. HTTP connection itself is stateless and cannot maintain the client requestor’s information in the subsequent request. Therefore, in most cases, the Web services function is thought of being as stateless. However, in other cases, the session state should be maintained between client and server side. The specification JSR 109 has standardized the Web service for Java 2 Platform Enterprise Edition (J2EE), such as servlets and stateless session bean, and their life cycle. However, how to expose stateful session beans as a Web service is not specified.

The IBM Records Manager API comprises some stateful session beans for the client’s usage. Therefore, how to provide a way to expose these stateful session beans as a Web service is a big issue for the implementation of IBM Records Manager Web Services. Finally, the issue has been resolved in IBM Records Manager Web Services. The essence of the IBM Records Manager Web Service solution for this issue is encapsulating the service ID or key into SOAP header and sending it to target service endpoint.

If IBM Records Manager Web service client sends a service ID that is obtained from a previous IBM Records Manager get controller call through SOAP header, the SOAP engine handler in IBM Records Manager Web Service server side intercepts the SOAP message from the client and determines whether to create or reuse the original remote object for a specified stateful session bean based on the service ID.

You can see the Implementing Web services as stateful session beans with WebSphere® Studio and WebSphere Application Server article from Resources for more details to learn more about the IBM Records Manager Web services design.


Web services client programming model

The JAX-RPC specification has defined the following three methods for the creation of a Web service client.

Static Stub

A stub class represents a client side proxy for a specified target service endpoint. The static stub means the stub class or Java file is generated through some utilities. A static stub can be generated from a WSDL or other resources, such as a service endpoint interface and additional binding information. Note that a service endpoint interface is the Java representation of a WSDL port type.

Dynamic Proxy

A dynamic proxy is similar with static stub to act as a proxy for target service endpoint interface. The difference between them is that dynamic proxy support a service endpoint interface dynamically at runtime without requiring any code generation.

Dynamic Invocation Interface (DII)

This method is completely different that the other two methods. A stub or proxy class is not required. The javax.xml.rpc.Call interface provides the support for the dynamic invocation interface. Another interface java.xml.rpc.Service acts as a factory for the creation of Call instances. After a Call instance is created, information regarding target service endpoint interface, operation name, parameters, and so forth can be set by Call setter methods to prepare for the invocation of target Web service operation.


IBM Records Manager Web service access

To access IBM Records Manager Web Service, users can adopt either the Static Stub or DII methods introduced in above section. In this article, these two methods will be demonstrated in detail.

Prerequisite

Before you create Web Service client to integrate with IBM Records Manager, make sure the IBM Records Manager Web Service application has been deployed on the target WebSphere Application Server. To create a IBM Records Manager Web Service client, the following jar packages should be added into your lib or classpath. You can obtain these jar packages from the IBM Records Manager Web Service ear package or official Web site.

  1. axis.jar
    Apache Axis version 1.4 core package. You can get it from the IBM Records Manager Web Service ear package.
  2. IRMAPI.jar
    IBM Records Manager API package. You can also get it from the IBM Records Manager Web Service ear package.
  3. soap.jar
    Apache SOAP package. You can download it from Apache web site or find it in WebSphere lib directory.
  4. axis-ant.jar
    Ant support for Axis. You can get it from IBM Records Manager Web Service ear package.
  5. commons-logging.jar
    Apache logging utility. You can get it from IBM Records Manager Web Service ear package.
  6. commons-discovery.jar
    Apache common discovery utility. You can get it from IBM Records Manager Web Service ear package.

Static Stub

To use IBM Records Manager Web Services in a Java application, you can follow these steps:

  1. Create or generate IBM Records Manager Web Service stub or proxy classes.
  2. Add a setter method setServiceId(String serviceId) and corresponding field for all generated stub classes except the stub for LoginManagerEJB in step 1.
  3. Encapsulate service id into element of SOAP header before the client sends request.
  4. Invoke web service client in the user's application.

In step 1, extract *.wsdl from IRMWebService.ear package and create static stub class for client application. You can use Axis utility class wsdl2java to generate stub class for a WSDL file as shown in Listing 1.


Listing 1. WSDL2Java Command Line

Set CLASSPATH=%CLASSPATH%;axis.jar;commons-logging.jar;commons-discovery.jar;jaxrpc.jar;
wsdl4j.jar;saaj.jar;axisprovider.jar
java –cp %CLASSPATH% org.apache.axis.wsdl.WSDL2Java -o {outputdir} LoginManagerEJB.wsdl

Alternatively, you can write an Ant build.xml as shown in Listing 2.


Listing 2. Ant build script sample for WSDL2Java

<project default="Generate_Client_Side_Stubs" basedir=".">
	<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" />
	<property name="WSDL_DIR" value="${basedir}/wsdl"/>
	<property name="WSDL2JAVA_DEST" value="${basedir}/src"/>
	<taskdef name="wsdl2java" classname=
"org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask" 
    	classpath="${basedir}/lib/axis-ant.jar;${basedir}/lib/axis.jar"/>
<target name="Generate_Client_Side_Stubs_LoginManagerEJB">>
		<wsdl2java debug="false" helperGen="false" noimports="false"
	            output="${WSDL2JAVA_DEST}"
	            serverside="false" skeletonDeploy="false" testcase="false"
	            typeMappingVersion="1.1"
	            url="${WSDL_DIR}/LoginManagerEJB.wsdl" 
	            verbose="false">
		</wsdl2java>
	</target>
	<target name="Generate_Client_Side_Stubs_UserControllerEJB">
		<wsdl2java debug="false" helperGen="false" noimports="false"
	            output="${WSDL2JAVA_DEST}"
	            serverside="false" skeletonDeploy="false" testcase="false"
	            typeMappingVersion="1.1"
	            url="${WSDL_DIR}/UserControllerEJB.wsdl" 
	            verbose="false">
		</wsdl2java>
	</target>
	…
</project>


Note that you might change the default location attribute value in Listing 3 of wsdlsoap:address in *.wsdl into your actual host and port in the runtime environment as shown in Listing 4 before you generate the stub classes using command or ant script above.


Listing 3. Web service default port address
		    
<wsdl:service name="LoginManagerEJBService">
      <wsdl:port binding="impl:LoginManagerEJBSoapBinding" name="LoginManagerEJB">
        <wsdlsoap:address location=
"http://localhost:9080/IRMWebServices/services/LoginManagerEJB"/>
      </wsdl:port>
   </wsdl:service>


Listing 4. Web service port address after change
		    
<wsdl:service name="LoginManagerEJBService">
      <wsdl:port binding="impl:LoginManagerEJBSoapBinding" name="LoginManagerEJB">
         <wsdlsoap:address location=
            "http://irmut03:9080/IRMWebServices/services/LoginManagerEJB"/>
      </wsdl:port>
   </wsdl:service>


After you change the location of target service port address and then generate the stub classes, you will see the stub differences between them, as shown in Listing 5 and Listing 6.


Listing 5. The default address in the LoginManagerEJB stub
		    
// Use to get a proxy class for LoginManagerEJB
private final java.lang.String LoginManagerEJB_address = 
"http://localhost:9080/IRMWebServices/services/LoginManagerEJB";



Listing 6. The port address after changed in the LoginManagerEJB stub
		    
private final java.lang.String LoginManagerEJB_address = 
"http://<host>:<port>/IRMWebServices/services/LoginManagerEJB";

Alternatively, you can construct URL and invoke corresponding getter method like in Listing 7 to get the stub instance.


Listing 7. Obtain correct stub at the runtime
		    
try {
java.net.URL endPoint = new java.net.URL(LoginManagerEJB_address);
com.ibm.LoginManagerEJB loginManager = getLoginManagerEJB(endPoint);

} catch (java.net.MalformedURLException e) {
    throw new javax.xml.rpc.ServiceException(e);
}

In step 2, add a setter method setServiceId(String serviceId) and corresponding field for all generated stub classes except the stub class for LoginManagerEJB in Step 1.

In step 3, to access a stateful session bean service provider, according to previous discussion, for each stub class to delegate a stateful session bean service provider, a service key must be provided to access the corresponding stateful session bean. The service key can guarantee that a specified stateful session bean will be accessed by subsequent requests from same client.

The Listing 8 is a demo for the ClientControllerEJBSoapBindingStub which is generated by wsdl2java command. The code snippet below highlighted with bold is appended for the purpose of stateful session bean accession.


Listing 8. Generated stub class
	
public class ClientControllerEJBSoapBindingStub extends 
    org.apache.axis.client.Stub implements com.ibm.ClientControllerEJB {

…

// To identify stateful session bean
    private String serviceId;
    
    public void setServiceId(String serviceId) {
    	this.serviceId = serviceId;
}


private org.apache.axis.client.Call createCall() throws java.rmi.RemoteException {

try {
org.apache.axis.client.Call _call =
                    (org.apache.axis.client.Call) super.service.createCall();
	…

     java.util.Enumeration keys = super.cachedProperties.keys();
     while (keys.hasMoreElements()) {
         java.lang.String key = (java.lang.String) keys.nextElement();
         _call.setProperty(key, super.cachedProperties.get(key));
     }
     
/* set serviceId header entry */
     		if(this.serviceId != null) {
SOAPHeaderElement header = 
new SOAPHeaderElement("", "IRMHeader");
         		try {
                                MessageElement msgElement = 
new MessageElement("", "serviceId");
            			msgElement.setObjectValue(this.serviceId);
            	header.addChild(msgElement);
            		
            			_call.addHeader(header);
            		
         	} catch(SOAPException e) {
       	    			e.printStackTrace();
         		}
     		}
		…
		…
     		return _call;
     	} catch (java.lang.Throwable t) {
           throw new org.apache.axis.AxisFault
                ("Failure trying to get the Call object", t);
     	}
}
}    


In addition, for each stateful IBM Records Manager Web Service you will access, the serviceId header entry should be set as shown above. Because LoginManagerEJB is a stateless session bean, it does not need to set service ID for the stub class. In step 4, invoke web service client stub class in the application. In the downloadable IRMWSJavaClientSample1 project, you can see the sample code to create the IBM Records Manager Web service Client call in the SampleClient1.java as shown in Listing 9.


Listing 9. Sample Code to invoke Web Service Client API
		    
public class SampleClient1 {
	
	private static String IRMUSERNAME = "administrator";
	private static String IRMUSERPWD = "cronos";
	private static String IRMDSJNDI = "recordmanager/jdbc/db2/DB2DOD"; 
	private static String HOSTNAME = "";
	private static String LANGCODE = "en_US";

	public static void main(String[] args) {
		
		// get LoginManagerEJB proxy class
LoginManagerEJBServiceLocator loginLocator = 
new LoginManagerEJBServiceLocator();

		try {
			LoginManagerEJB loginBean = 
                            loginLocator.getLoginManagerEJB();
			System.out.println("Data source list : " + 
                    loginBean.getDataSourceList());			
			String clientControllerKey = loginBean.integrationLogin
                    (IRMUSERNAME, IRMUSERPWD, IRMDSJNDI, 
                            HOSTNAME, LANGCODE);			
			ClientControllerEJBServiceLocator clientControllerLocator = 
                    new ClientControllerEJBServiceLocator();
			ClientControllerEJBSoapBindingStub clientControllerBean =
                    (ClientControllerEJBSoapBindingStub)
                            clientControllerLocator.getClientControllerEJB();
			clientControllerBean.setServiceId(clientControllerKey);
			
			String queryControllerKey = 
                    clientControllerBean.getQueryControllerAsString();
			QueryControllerEJBServiceLocator queryControllerLocator = 
                    new QueryControllerEJBServiceLocator();
			QueryControllerEJBSoapBindingStub queryControllerBean = 
                    (QueryControllerEJBSoapBindingStub)
                            queryControllerLocator.getQueryControllerEJB();
			queryControllerBean.setServiceId(queryControllerKey);

			String susQuery = 
                    queryControllerBean.runQuery(getSuspensionQuery(), 
                    QueryTypes.ADVANCED);
			String queryListing = queryControllerBean.runQuery(getQuery(), 
                    QueryTypes.LISTING);

			System.out.println("suspension query : " + susQuery);
			System.out.println("query : " + queryListing);
			…
			…
			
		} catch(ServiceException e) {
			e.printStackTrace();
		} catch(RecordManagerException e) {
			e.printStackTrace();
		} catch(RemoteException e) {
			e.printStackTrace();
		} 
	}
}



Dynamic Invocation Interface (DII)

The normal steps for this method are:

  1. Get a JAX-RPC Service.
  2. Instantiate a JAX-RPC Call using the JAX-RPC Service createCall() method.
  3. Configure your Call instance with its setter methods.
  4. Invoke the Web service operation using the JAX-RPC Call's invoke method.

When you use this method to create IRM Web Service client, comparing with the first method static stub, the major difference is that you should add a SOAP header element into original SOAP header in step 2. The added SOAP header element includes the service ID of your target session bean.

You can find the sample code snippet from IRMWSJavaClientSample2 project.


Listing 10. A proxy class for SOAP DII style
		    
public class SOAPDII {

	private static String TARGET_NAMESPACE = "http://ibm.com"; 
	private static String TARGET_OBJECTURI = "http://ibm.com";
	private static String SOAPActionURI = "";
	
	private String serverName = "localhost";
	private String serverPort = "9080"; 
	
	private ServiceFactory serviceFactory = null;
	
	…
	public Object invoke(String portType, String target, String method, 
        Class[] parameterTypes, String[] parameterNames, 
        Object[] parameterValues) throws SOAPException {
		
		if(portType == null || portType.length() < 1) {
			throw new SOAPException(Constants.FAULT_CODE_CLIENT, 
                    "The portType must be specified.");
		}

		Call call = null;
		
		try { 
			call = createCall(portType);
		} catch (ServiceException e) {			
			throw new SOAPException(Constants.FAULT_CODE_CLIENT, 
                    e.getMessage());
		}
		
		…
		…
		
		call.setOperationName(new QName(TARGET_NAMESPACE, method));
		call.setOperation(oper);
		call.setTargetEndpointAddress(location);
		
		SOAPHeaderElement header = createIRMHeader(target);
		if(header != null)
			call.addHeader(header);
		
		
		try {
			Object result = call.invoke(parameterValues);
			System.out.println("result : " + result);
			return result;
		} catch (RemoteException e) {
			throw new SOAPException(Constants.FAULT_CODE_CLIENT, 
                    e.getMessage());
		}

	}
	
	
	private SOAPHeaderElement createIRMHeader(String target) {
		
		if(target != null && target.length() > 0) {
		SOAPHeaderElement header = new SOAPHeaderElement("", "IRMHeader");
        	
try {
        		MessageElement msgElement = new MessageElement("", "serviceId");
        		msgElement.setObjectValue(target);
        		header.addChild(msgElement);
        		return header;
        	} catch(Exception e) {
        		e.printStackTrace();
        	}
		}
		
		return null;
		
	}
	…
	…
		
}


The listing 11 below shows a sample for another style of DII.


Listing 11. Another proxy class for SOAP invocation
		    
public class SOAPProxy {
	
	…
	
	public SOAPProxy(String serverName, String serverPort) {
		this(serverName, serverPort, false);
	}
	
	public SOAPProxy(String serverName, String serverPort, boolean noTCPDelay) {
		this.serverName = serverName;
		this.serverPort = serverPort;
		this.noTCPDelay = noTCPDelay;
	}
	
	
	
	public Object invoke(String portType, String target, String method) throws 
        SOAPException {
		return invoke(portType, target, method, null, null, null);
	}
	
	public Object invoke(String portType, String target, String method, 
        Class[] parameterTypes, String[] parameterNames, Object[] parameterValues) 
            throws SOAPException {
		
		if(portType == null || portType.length() < 1) {
			throw new SOAPException(Constants.FAULT_CODE_CLIENT, 
            "The portType must be specified.");
		}
		
		// create SOAPHTTPConnection for each web service call
		Call call = createCall(noTCPDelay);
		
		String location = "http://" + serverName + ":" + serverPort + 
            "/IRMWebServices/services/" + portType;
		
		URL url = null;
		try {
			url = new URL(location);
		} catch (MalformedURLException e) {
			throw new SOAPException(Constants.FAULT_CODE_CLIENT, 
                e.getMessage());
		}
		
		Response response = null;
	
		call.setTargetObjectURI(TARGET_OBJECTURI);		
		call.setEncodingStyleURI(Constants.NS_PRE_SOAP_ENV);
		call.setMethodName(method);
		
		Header header = createIRMHeader(target);
		if(header != null) 
			call.setHeader(header);
		
		Vector parameters = new Vector();
		if(parameterTypes != null && parameterTypes.length > 0) {
			for(int i = 0; i < parameterTypes.length; i++) {
				Parameter parameter = new Parameter(parameterNames[i], 
                    parameterTypes[i], parameterValues[i], Constants.NS_URI_SOAP_ENC);
				parameters.add(parameter);
			}			
		}
		
		call.setParams(parameters);
		
		response = call.invoke(url, SOAPActionURI);
		
		if(response.generatedFault()) {
			Fault fault = response.getFault();
			call.setFullTargetObjectURI(TARGET_OBJECTURI);
			throw new SOAPException(fault.getFaultCode(), 
                fault.getFaultString());
		} else {
			if(response.getReturnValue() != null) {
				return response.getReturnValue().getValue();
			}
		}

		return null;
	}
	
	private Call createCall(boolean noTCPDelay) {
		
		SOAPHTTPConnection soapConn = new SOAPHTTPConnection();
		
		if(noTCPDelay) {
			soapConn.setTcpNoDelay(Boolean.TRUE);			
		}
		
		SOAPMappingRegistry smr = new SOAPMappingRegistry ();
		StringDeserializer sd = new StringDeserializer();
		smr.mapTypes(Constants.NS_URI_SOAP_ENC, new 
            QName("http://schemas.xmlsoap.org/soap/encoding/",""), null, null, sd);
		
		Call call = new Call();
		call.setSOAPTransport(soapConn);
		call.setSOAPMappingRegistry(smr);
		
		return call;
	
	}
			    
		    
	private Header createIRMHeader(String target) {
		
		if(target != null && target.length() > 0) {
			Header header = new Header();
			Vector vector = new Vector();
			
			Document doc = XMLUtil.createDocument();
			Node irmHeader = doc.createElement("IRMHeader");
			Node serviceID = doc.createElement("serviceId");
			XMLUtil.setValue(serviceID, target);
			XMLUtil.insertNode(doc, irmHeader, serviceID);

			vector.add(irmHeader);
			header.setHeaderEntries(vector);
			return header;
		}
		return null;		
	}
}



Important: The two sample projects are in the attachments. These projects are built on the RAD (Rational® Application Developer) 7 environments.


Conclusion

Whatever methods you use to build IBM Records Manager Web Service client, the state maintenance cross SOAP request is the key point. Users can find detail instruction in this article.



Downloads

DescriptionNameSizeDownload method
Java Client Sample 1IRMWSJavaClientSample1.zip4,591KB HTTP
Java Client Sample 2IRMWSJavaClientSample2.zip4,591KB HTTP

Information about download methods


Resources

About the authors

Jin Liang Shi

Jin Liang Shi is a software engineer for IBM in China Software Development Lab, and focus on the development of IBM Records Manager and Content Manager Records Enabler.

Dou Ma

Dou Ma is a software engineer for IBM in China Software Development Lab, and focus on the development of IBM Records Manager and Content Manager Records Enabler. He has over 4 years software development experience in web technology, globalization and accessibility.

Lang Xin Pei

Lang Xin Pei is working as a staff software engineer in IBM China Software Development Lab. He has many years experience in the integration of software system and the development of J2EE based information system. Now he focus on the development of IBM Records Manager product.

Comments



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services
ArticleID=412982
ArticleTitle=Integrate with IBM Records Manager Using Web Service API
publish-date=07102009
author1-email=shijl@cn.ibm.com
author1-email-cc=
author2-email=madou@cn.ibm.com
author2-email-cc=
author3-email=langxp@cn.ibm.com
author3-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers