IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Information Management  >

基于 IBM Records Manager 的 Host 应用开发

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码


级别: 初级

马斗, 软件工程师, IBM
郎昕培, 软件工程师, IBM
李晓霞, 软件工程师, IBM

2009 年 10 月 26 日

IBM Records Manager 是一款为业务应用提供记录管理功能的软件产品,本文将结合代码实例介绍如何为一个业务应用实现 IBM Records Manager 的 Host 接口以让 IBM Records Manager 能够访问业务应用。

IBM Records Manager 简介

IBM Records Manager(以下简称 IRM)是符合 DOD 5015.2 V3 规范、用于管理企业电子和物理记录的整个生命周期(从创建到废弃)的应用程序。它为各种业务应用(例如,电子邮件,文档管理,工作流程,图像和群件)提供生命周期记录保留管理,能够有效地帮助企业的降低存储成本同时避免潜在的法律风险。





回页首


IBM Records Manager 的体系结构

IBM Records Manager 由引擎、API、基于 Web 的管理员用户界面和基于 Swing 的客户端工具组成。一般情况下,IBM Records Manager 不作为单独的应用程序来运行,而是把 IRM 作为提供记录管理服务的记录管理引擎提供给其他生成记录的应用程序(在此我们称其为 Host 应用程序),为后者(host 应用)提供记录管理服务。使用 IRM 来管理生成记录的应用程序可以是各种类型的应用程序,典型的如企业内容管理系统、电子邮件系统、账单系统等等,这些应用系统在 IBM Records Manager 的体系架构中被统一称为 IRM 的 Host 应用,在 IRM 的架构中,这类 Host 应用都将通过 Host 连接器连接到 IRM 的核心引擎,完成记录生成和管理等各项功能,如图 1 所示为 IRM Records Manager 的体系结构的各个组成部分。


图 1. IRM 与 Host 应用的体系结构
图 1. IRM 与 Host 应用的体系结构

引擎

引擎提供了启用生命周期管理所必需的所有业务逻辑。企业可以将记录引擎嵌入到他们的电子邮件、文档管理、工作流程、图像、群件或其他应用程序中,以获得电子记录保管功能。这些产品的用户将其对记录的保留看作是当前使用的业务应用程序的一个功能。

Java API

Java API 是 IBM Records Manager 的引擎对外提供的主要操作接口。IRM 的 API 接口功能相当完备,借助于 API 可以完成记录管理的所有功能,也使其他应用能够比较方便的集成 IRM。Host 接口也是 API 的一个组成部分。API 提供接口包 irmapi.jar,通过导入 API 包,外部应用可以访问 IBM Records Manager 的所有功能。

Host 连接器

Host 连接器是依照 Host 接口开发的应用程序,用于连接 IRM 和一个具体的 Host 应用。Host 连接器能够通过 IRM 的 API 接口调用 IRM 记录管理引擎,进行生成记录、管理记录的生命周期,同步记录更新、销毁处置记录等操作。下面本文进一步介绍 Host 接口,并借助于实例介绍如何在 Host 连接器中实现 Host 接口,如何部署和注册 Host 连接器。





回页首


IBM Records Manager 与 Host 应用程序的集成

Host 应用和 IBM Records Manager 的引擎通过中间的 Host 连接器应用实现了交互访问,如图 2 反应了 IRM 与 Host 应用的交互关系。IBM Records Manager 仅为 Host 应用提供了 API 和 Host 接口规范,而并没有强制限定 Host 连接器的实现方式。基于这种开放的架构,用户可以灵活地为业务应用定制集成方案。

Host 应用在使用 IRM 进行记录管理时的一个典型应用是生命周期管理,Host 应用程序通过 IRM 的 API 能够访问到 IRM 引擎,实现记录声明。一旦 Host 应用程序的内部文档被声明为 IRM 的记录,就意味着 IRM 接管了对文档的生命周期管理过程。同时 Host 应用需要实现 Host 接口,使 IRM 能够在记录生命周期的管理过程中,将记录更新信息同步通知给 Host 应用程序。本文以下内容将参考这一典型应用来说明 Host 连接器的实现。


图 2. Host 连接器的作用
图 2. Host 连接器的作用

Host 连接器的主要结构

Host 连接器就是 IBM Records Manager 访问 Host 应用的入口。IBM Records Manager 通过 Host 连接器从 Host 应用获取信息,并向 Host 应用发送所发生的记录管理事件的通知。例如,在生命周期过程中,IBM Records Manager 需要访问 Host 应用以通知所发生的生命周期事件,如生命周期阶段的变更、销毁记录等。

如前所述,IBM Records Manager 只提供了 Host 连接器的接口定义和操作声明,因此 Host 连接器可以是独立的应用程序,也可以是 Host 应用的组件部分。通常 Host 连接器是由 Host 应用程序的集成开发人员根据 IBM Records Manager 提供的接口定义和操作声明结合业务应用来开发。

Host 接口规范从功能上可以分为两类:向 IRM 提供信息的方法和响应记录管理事件的方法。Host 连接器依照的 Host 接口规范由一个有状态服务和一个无状态服务组成。无状态的服务不需要认证,可以用无状态 EJB 来实现无状态服务。而有状态服务需要认证,由有状态 EJB 来实现。图 3 说明了 Host 连接器需要实现的两个部分:有状态的 HostInterface 和无状态的 HostServiceInterface


图 3. Host 连接器的组成结构
图 3. Host 连接器的组成结构

在下面的样例代码中,我们使用一个简单的文档管理系统作为一个 Host 应用。这个文档管理系统由一组 XML 配置文件和一个文档存储目录组成。我们以一个独立 EJB 应用程序的方式为这个文档管理系统实现 Host 连接器,并介绍如果在 IRM 中部署和注册该 Host 连接器,从而让 IBM Records Manager 能够通过 Host 连接器访问该文档系统。

实现 HostServiceInterface

HostServiceInterface 接口主要用来向 IBM Records Manager 提供一些 Host 应用的基本信息。它是集成 IRM 和 Host 应用所必须实现的接口,由 Host 连接器来实现。HostServiceInterface 可以实现为一个无状态的 EJB,HostServiceInterface 接口中定义的方法如下:

  • String getHostCapabilities(Host host)
  • String getUserGroupMembership(int blockStart, int blockSize, Host host)
  • String validateUser(java.lang.String username, java.lang.String password, Host host)

参考文献中的 IBM Records Manager 的 API 文档中有以上 3 个接口方法的详细说明,包括调用时机、参数说明、返回值的格式和说明等。在本实例中(清单 1),我们只列出 getHostCapabilities 方法在 Host 连接器中的一个实现,该方法用于返回 Host 连接器端实现的 Host 调用接口的描述信息,以便 IRM 这个 Host 实现了哪些 Records Manager 可以访问的功能,例如能否上载文档、查看文档内容、响应生命周期管理事件等。完整的代码清单请参考代码下载部分。


清单 1. 实现 HostServiceInterface 的 getHostCapabilities 方法
				
 public class ServiceEJBBean implements javax.ejb.SessionBean { 
 public String getHostCapabilities(Host host)throws Exception{ 
 log.info(" GET HOST CAPABILITIES "); 
 log.info("Host Name =" + host.getHostName()); 

 Properties h = new Properties(); 
 h.put(Context.INITIAL_CONTEXT_FACTORY, 
	"com.ibm.websphere.naming.WsnInitialContextFactory"); 
 h.put("com.ibm.websphere.naming.jndicache.cacheobject", "none"); 
 Context context = new InitialContext(h); 
 Object o = context.lookup("ejb/com/host/Configuration"); 
 ConfigurationEJBHome home = 
 ConfigurationEJBHome)PortableRemoteObject.narrow(o,ConfigurationEJBHome.class); 
 
 ConfigurationEJB remote = (ConfigurationEJB) home.create(); 
 Properties prop = remote.getProperties(); 

 Document doc = XMLUtil.createDocument(); 
 Element list = doc.createElement("List"); 
 doc.appendChild(list); 

 Element item = doc.createElement("Item"); 
 boolean onUpdate = 
		 onversionUtil.stringToBoolean((String)prop.get("host.on.update")); 
 item.setAttribute("Capability",HostCapabilitiesOptions.ON_UPDATE); 
 item.setAttribute("Supported",onUpdate ? "1":"0"); 
 list.appendChild(item); 

 item = doc.createElement("Item"); 
 boolean allowContentRetr = 
 ConversionUtil.stringToBoolean((String)prop.get("host.allow.content.retrieval")); 
 
 item.setAttribute("Capability",HostCapabilitiesOptions.ALLOW_CONTENT_RETRIEVAL); 
 item.setAttribute("Supported",allowContentRetr ? "1":"0"); 
 list.appendChild(item); 

 item = doc.createElement("Item"); 
 boolean allowViewContent = 
 ConversionUtil.stringToBoolean((String)prop.get("host.allow.view.content")); 
 
 item.setAttribute("Capability",HostCapabilitiesOptions.ALLOW_CONTENT_VIEWING); 
 item.setAttribute("Supported",allowViewContent ? "1":"0"); 
 list.appendChild(item); 

 item = doc.createElement("Item"); 
 boolean allowContentUpload = 
 ConversionUtil.stringToBoolean((String)prop.get("host.allow.content.upload")); 
 
 item.setAttribute("Capability",HostCapabilitiesOptions.ALLOW_CONTENT_UPLOAD); 
 item.setAttribute("Supported",allowContentUpload ? "1":"0"); 
 list.appendChild(item); 

 item = doc.createElement("Item"); 
 boolean supportContentSearch = 
 ConversionUtil.stringToBoolean((String)prop.get("host.supports.content.search")); 
 
 item.setAttribute("Capability",HostCapabilitiesOptions.SUPPORT_CONTENT_SEARCH); 
 item.setAttribute("Supported",supportContentSearch ? "1":"0"); 
 list.appendChild(item); 

 log.debug(XMLUtil.getXML(doc)); 
 return XMLUtil.getXML(doc); 
 } 
 } 


在代码实例中,Host 的信息以 XML 格式保存在操作文件中,由 ConfigurationEJB 读取。完整的代码清单请参考代码下载部分。

实现 HostInterface

IRM 通过 HostInterface 实际操作 Host 应用,从而获取信息、访问 Host 应用的服务以及通知 Host 应用电子记录的生命周期事件。HostInterace 接口中的操作从功能上可以分为两类:

  • 从 Host 应用获取 Host 所提供的服务的操作。如 getContentList、getContentMetaDataById、readContentStream 等这些操作是 IBM Records Manager 查询和浏览文档信息和内容的操作;
  • 当电子记录的生命周期发生变化时将事件通知给 Host 应用。如 onUpdate、unregister、delete、phaseTransition 等这些操作是电子记录在发生生命周期变化时 IBM Records Mnager 将相应的事件通知给 Host 应用。

IBM Records Manager 的引擎在创建 HostInterface 的远程接口实例时,会将当前登录用户的状态信息(用户信息,登录数据库的 JDNI)作为参数传送给 HostInterface 的实现,而 HostInterface 的实现需要负责维护这些状态信息以便随时能够登录回 IBM Records Manager 访问 API。因此 HostInterface 接口的的实现应该是一个有状态的 EJB。

在清单 2 的代码实例中,实现了一个有状态的、实现了 HostInterface 接口的 EJB: RemoteHostEJBBean,它的 ejbCreate 方法接收三个包含状态信息的参数,并将它们保存在 session bean 的属性中。Host 应用需要回调 IRM 的 API 时,就可以使用这些信息登录进 IRM 以获取 ClientControllerEJB 以及其他的 EJB,进而进行 API 调用。


清单 2. 实现 HostInterface 的 ejbCreate 方法
				
 public class RemoteHostEJBBean implements javax.ejb.SessionBean, SessionSynchronization
 { 
 private User user = null; 
 private String jndiName = null; 
 private String hostName = null; 
 private String repositoryDir = "./repository/"; 

 public void ejbCreate(User user, Host host, String db_jndi_name) { 
 Random random = new Random(); 
 beanID = random.nextInt() + " Bean: " + this.getClass().getName(); 
 log.info(" REMOTE_HOST_CREATE "); 
 log.info( "Bean" + beanID ); 
 log.info("Host User Name = 
 " + host.getHostUserName() + " Host Password " + host.getPassword()); 
 Properties prop = new Properties(); 
 try { 
	 // read the properties file. 
	 Properties h = new Properties(); 
	 h.put(Context.INITIAL_CONTEXT_FACTORY, 
		"com.ibm.websphere.naming.WsnInitialContextFactory"); 
	 h.put("com.ibm.websphere.naming.jndicache.cacheobject", "none"); 
	 Context context = new InitialContext(h); 
	 Object o = context.lookup("ejb/com/host/Configuration"); 
	 ConfigurationEJBHome home = 
 (ConfigurationEJBHome) PortableRemoteObject.narrow(o, ConfigurationEJBHome.class); 
	 ConfigurationEJB remote = (ConfigurationEJB) home.create(); 
	 prop = remote.getProperties(); 
 } catch (Exception e) { 
	 e.printStackTrace(); 
	 throw new RuntimeException("Can not read from property file" + e); 
 } 

 repositoryDir = (String) prop.get("repository.directory"); 

 if(!repositoryDir.endsWith("/")) 
	 repositoryDir += "/"; 

 // get jndi name and user is to create unique repository directory per DB 
 String reponame = ""; 
 if(db_jndi_name != null && db_jndi_name.length() > 0){ 
	 reponame = db_jndi_name; 
	 reponame = reponame.replace('/', '_'); 
	 repositoryDir += reponame + "/"; 
 } 

 dir = new File(repositoryDir); 
 if(!dir.exists() && !dir.isDirectory()) 
	 dir.mkdir();  

 this.user = user; 
 this.jndiName = db_jndi_name; 
 this.hostName = host.getHostName(); 
 } 
 } 


代码清单 3 为该 EJB 对 HostInterface 接口的 delete 方法的实现。当电子记录在 IBM Records Manager 中被删除,并且明确可以删除 Host 中所对应的文档时,IBM Records Manager 调用 HostInterface 远程实例的 delete 方法,通知 Host 应用删除对应的文档。


清单 3. 实现 HostInterface 的 delete 方法
			
--------10--------20--------30--------40--------50--------60--------70--------80--------|
public class RemoteHostEJBBean implements javax.ejb.SessionBean, SessionSynchronization {


 public void delete(String hostRecordID, 
			 long filePlanComponentID, 
			 String cmpntFieldsAsXml) throws Exception { 
 log.info("Deleting host record: " + hostRecordID); 
 log.info("XML: " + cmpntFieldsAsXml); 

 File document = new File(repositoryDir + File.Seperator + hostRecordID); 

 if(document.exists()){ 
	 document.delete(); 
 } 
 } 
 } 

Delete 方法的第一个参数 hostRecordID 为文档在 Host 应用中的标识。在本实例中,文档在 Host 应用中的标识即为文档名,我们在实现中利用 hostRecordID 定位文档将其删除。

HostInterface 的完整实现请参考代码下载部分。

部署 Host 连接器

IBM Records Manager 对实现 HostInterface 和 HostServiceInterface 接口 EJB 的 JNDI 名称做了约定:它们 JNDI 名称由两部分组成——由用户设定的 JNDI 上下文和 IBM Records Manager 给定的 EJB 名称。实现 HostInterface 的 EJB 的名称为 RemoteHost,实现 HostServiceInterface 接口的 EJB 名称为 Service。例如,如果用户设定的 JNDI 上下文为 ejb/com/host,那么这两个 EJB 的 JNDI 分别是 ejb/com/host/RemoteHost 和 ejb/com/host/Service。下一小节的内容讲述了如何设定 Host 连接器的 JNDI 上下文。

在本实例中,我们将 Host 连接器实现为独立的 J2EE 应用程序。我们将 Host 连接器的代码打包为 ear 包或 jar 包部署到 WebSphere 6.1 上。

注册 Host 应用

在使用 Host 连接器连接 IRM 和 Host 应用之前,首先需要让 IBM Records Manager 知道如何找到 Host 连接器,因此在开发完 Host 连接器之后,还需要预先将 Host 应用的注册到 IBM Records Manager 的数据库中。这一步骤称为注册 Host。

注册 Host 应用就是将 Host 的连接信息,包括 Host 机器地址、JNDI 上下文和端口、登录 Host 应用的用户名、密码。注册 Host 应用可以通过 IBM Records Manager 的 Web 管理客户端直接注册,在 I 管理客户端的 Host 配置管理功能中,可以给 IRM 添加 Host,当然,我们也可以通过调用 API 的方式直接注册 Host。如图 4 所示为通过 IRM 的 Web 管理客户端注册 Host 应用的界面。


图 4. 注册 Host 应用
图 4. 注册 Host 应用




回页首


结束语

IBM Records Manager 是一个记录管理引擎,通过 Host 连接器与业务应用集成。本文通过实现一个典型的 Host 连接器,向您介绍了 Host 连接器基本结构、实现和注册的方式。事实上,基于 IBM Records Manager 开放的体积结构和应用集成接口,您完全可以根据具体需求和业务应用的特点灵活地实现与 IBM Records Manager 的集成。






回页首


下载

名字大小下载方法
FileSysHost1000kHTTP
关于下载方法的信息

注意:

  1. 本文所实现的 Host 连接器示例 FileSysHost.zip!


参考资料

学习

获得产品和技术

讨论


作者简介

马斗的照片

马斗,是 IBM 中国软件开发中心的一名软件工程师,目前主要从事 IBM Records Manager 以及 Content Manager Records Enabler 产品的开发工作。他有超过 4 年的 Web 开发经验,在 Web 2.0 技术、可访问性以及 UI 国际化方面有丰富的经验和兴趣。


郎昕培的照片

郎昕培,是 IBM 中国软件开发中心的一名资深软件工程师,在软件系统的集成和基于 J2EE 的信息系统开发方面有着多年的经验。目前主要从事 IBM Records Manager 产品的开发工作。


李晓霞的照片

李晓霞,是 IBM 中国软件开发中心的一名资深测试工程师,在软件系统尤其是基于 Web 应用的测试方面有着多年的经验。目前主要从事 IBM Records Manager 产品的测试工作。




对本文的评价








IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款