转载于http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0812liuwei/index.html
本文样例是基于企业内部的文档管理流程的一个片断。在该流程中,秘书可以上传和更新某些文档资料;公司的管理者可以检查上传的文件;上述三个 活动,代表了对文档的创建、查询和更新操作,文档被存储到 FileNet Ce 中,并通过 PE 的“引用”,可以被流程中每个任务活动所共享。
在操作 CE 之前,需要获取与 CE 的连接。 FileNet 提供了两种连接方式:EJB transport 和 Web services transport 。如果,使用 EJB transport 连接 CE,所必需的 JAAS context 常常已经建立 (例如:如果使用的应用服务器是 Websphere Application Server, 可以配置相关的 JAAS), 因此不需要使用代码建立 JAAS context:
// Need setup parameters of JVM to login; parameters include url and jaas config // … … // Get the connection String uri = "http://CEServer:9080/wsi/FNCEWS40DIME/"; Connection conn = Factory.Connection.getConnection(uri); // Get the default domain Domain domain = Factory.Domain.getInstance(conn, null); // Get an object store ObjectStore os = Factory.ObjectStore.fetchInstance(domain, "ObjectStoreName", null); |
如果使用一般的 JAVA 应用程序或者 Web services transport 连接 CE,需要额外增加下列方法建立一个 JAAS context:
// conn: CE connection; Subject subject = UserContext.createSubject(conn, user, password, null); UserContext uc = UserContext.get(); uc.pushSubject(subject); |
当释放 CE 的联接,需要使用“ UserContext.get().popSubject() ”,将当前登录用户的主题对象从用户上下文中清除掉;否则,如果另外用户登陆到 PE 和 CE 中,进行相应的操作,可能会出现下列异常:
[Err=d56d0044] Security attributes disallow access at filenet.pe.peorb.client.ORBUtility.mapServerException(ORBUtility.java:370) at filenet.pe.peorb.client.ORBSession.executeRPC(ORBSession.java:1203) at filenet.pe.peorb.client.ORBSession.getQueueNames(ORBSession.java:1788) at filenet.vw.api.VWSession.getQueue(VWSession.java:1120) |
下面将介绍使用 CE API 对文档进行存储和管理。
Object Store 是一个独立的、存在于 Domain 的对象。它提供了对资源的访问和存取,这里的资源包括 documents,folders, custom objects 等,以及有关这些资源的元数据(Class)。 Object Store 代表了这些资源在 CE 上的存储位置。借助 Object Store 对象提供的方法,开发者可以对 Content Engine Server 中的资源进行操作。
Domain domain = Factory.Domain.getInstance(conn, null); ObjectStore os = Factory.ObjectStore.fetchInstance(domain, objStoreName, null); return os; |
Folder folder = Factory.Folder.fetchInstance(objStore, folderPath, null); return folder; |
// os: objectStore; path: the parent folder in the objectStore Folder folder = Factory.Folder.createInstance(os, path); return folder; |
清单 7. 通过 Class 的名字创建一个 Document 对象
Document myDoc = null; myDoc = (Document) os.createObject(className); // add some values for the properties of document // ... ... // add some external files for document // ... ... myDoc.checkin(AutoClassify.AUTO_CLASSIFY, CheckinType.MAJOR_VERSION ); myDoc.save(RefreshMode.REFRESH); ReferentialContainmentRelationship rel = folder.file(myDoc, AutoUniqueName.AUTO_UNIQUE, null, DefineSecurityParentage.DEFINE_SECURITY_PARENTAGE); rel.save(RefreshMode.NO_REFRESH); //return myDoc; |
1 .当创建一个 document 对象时,可以为它的属性对象赋值。
// … … //'docProps' is 'java.util.Properties' object for input com.filenet.api.property.Properties properties = myDoc.getProperties(); for (Iterator iterator = docProps.keySet().iterator(); iterator.hasNext();) { String key = (String) iterator.next(); String value = docProps.getProperty(key); properties.putValue(key, value); } // … … |
当 document 对象中的一个属性的类型不是简单类型,而是指向另外一个对象时,需要建立相互之间的引用关系。首先,使用 Enterprise Manager 在 CE 中创建 document class 过程中,为两个 class 之间的相互关系创建一种特殊的属性:association property 。使用它可以在 design time 为两个 class 建立引用关系,当 class 在 runtime 被实例化为对象,相关的引用使用下列代码实现:
(1)当对象之间是 1:1 的关系时,需要在对象双方建立关系。
//create the association between 'doc' and 'itemDoc' documents com.filenet.api.core.Document doc = ...; com.filenet.api.core.Document itemDoc = ...; com.filenet.api.property.Properties a_properties = doc.getProperties(); a_properties.putObjectValue("association name", itemDoc); com.filenet.api.property.Properties b_properties = itemDoc.getProperties(); b_properties.putObjectValue("association name", doc); |
(2)当对象之间是 1:* 的关系时,只需在“ * ”的一方对象中分别建立关系,而 CE 会自动在“ 1 ”的一方创建引用。
//create the association between 'doc' and 'itemDoc' documents com.filenet.api.core.Document doc = ...; com.filenet.api.core.Document itemDoc1 = ...; com.filenet.api.core.Document itemDoc2 = ...; // … … com.filenet.api.property.Properties properties1 = itemDoc1.getProperties(); com.filenet.api.property.Properties properties2 = itemDoc2.getProperties(); // … … properties1.putObjectValue("association name", doc); properties2.putObjectValue("association name", doc); // … … |
2 .可以为创建的 document 对象增加相关的外部文件,使用“ ContentElementList ”存储文件流对象。
清单 11. 创建 ContentElementList 对象
myDoc = (Document) os.createObject(className); ContentElementList contentList = Factory.ContentElement.createList(); for (int i = 0; i < files.length; i++) { ContentTransfer content = Factory.ContentTransfer.createInstance(); content.setCaptureSource(new FileInputStream(filePath); contentList.add(content); } myDoc.set_ContentElements(contentList); |
搜索CE 中的一个对象
可以按照 Document Class 的名字在 Object Store 中搜索相关的对象:
//queryStr: SELECT * FROM ClassName SearchSQL sqlObject = new SearchSQL(queryStr); SearchScope searchScope = new SearchScope(os); RepositoryRowSet rowSet = searchScope.fetchRows(sqlObject, null, null, new Boolean(true)); for (Iterator iterator = rowSet.iterator(); iterator.hasNext();) { RepositoryRow row = (RepositoryRow) iterator.next(); Properties props = row.getProperties(); for (Iterator iterator2 = props.iterator(); iterator2.hasNext();) { Object o = (Object) iterator2.next(); System.out.println(o); } |
下面将介绍使用上述 CE API,并结合 FileNet PE,在一个文档管理流程中实现内容的共享。
使用 FileNet Process Designer 设计一个 DocumentManager 流程,并为流程创建一个名为“ DocAttachmentID ”的“ Attachment ”变量,在后面的开发实践中,它将指向一个在 CE 中创建好的 document 实例,用于存放上传的文件。下图描述了这个流程的片断:
这一步对应流程中的“ Upload Documents ”节点,需要做的工作:上传一些文件,并把它们存放到 FileNet CE 中。
首先为当前的文档管理流程分配一个业务 ID,唯一标识一个流程实例。同时,使用 CE API 在指定的目录下创建一个 Folder,名字为业务 ID,表示对于当前的流程,相关的文档都存放在这个 Folder 中。然后,在这个 Folder 下创建一个 document 对象,所有上传的文件都存放到该对象的“ ContentElementList ”中。最后将当前创建好的 document 对象与流程的 attachment 对象“ DocAttachmentID ”建立关联,代码如下:
VWAttachment vwattach = new VWAttachment(); vwattach.setId(document.get_Id().toString()); vwattach.setVersion(document.get_VersionSeries().get_Id().toString()); vwattach.setLibraryName(objStoreName); vwattach.setLibraryType(VWLibraryType.LIBRARY_TYPE_CONTENT_ENGINE); vwattach.setType(VWAttachmentType.ATTACHMENT_TYPE_DOCUMENT); vwStepElement.setParameterValue("ClaimDocID", vwattach, false); |
其中,“ vwStepElement ”对象表示活动“ Upload Document ”的实例,可以通过 FileNet PE API 获取。当建立好与流程中 Attachment 对象的关联后,流程的其他活动实例,可以通过 Attachment 对象从 CE 中获取对应的 document 。需要说明的是,因为 FileNet PE API 和 CE API 是彼此独立的,它们之间是不能通过“对象引用”的方式直接交互,即不能在 PE 中保留一个对 CE 的对象引用,只能保留简单类型的值(String, int 等)。因此,建立两者之间的联系只是把当前 CE 中 document 实例的 ID(String),关联到 PE 中 Attachment 对象的 ID(String)。
这一步对应流程中“ Review Documents ”节点,需要做的工作:
// get attachment object from process VWAttachment vwattach = (VWAttachment) stepElement.getParameterValue ("DocAttachmentID"); // retrieve document object from CE; Document doc = Factory.Document.fetchInstance(os, vwattach.getId(), null); ContentElementList list = claimDoc.get_ContentElements(); ContentTransfer content = (ContentTransfer) list.get(i); InputStream is = content.accessContentStream(); String mimeType = content.get_ContentType(); |
这一步对应流程中“ Add Additional Documents ”节点。根据业务场景,当用户上传的文件不充分时,流程转向该任务节点,允许用户(secretary)提交额外的文件到 FileNet CE 中。程序中所需要做的工作:
claimDoc.checkout(ReservationType.EXCLUSIVE, null, null,null); claimDoc.save(RefreshMode.NO_REFRESH); Document reservation = (Document) claimDoc.get_Reservation(); ContentElementList contentList = reservation.get_ContentElements(); ContentTransfer content = Factory.ContentTransfer.createInstance(); content.setCaptureSource(...); contentList.add(content); reservation.checkin(AutoClassify.DO_NOT_AUTO_CLASSIFY,CheckinType.MAJOR_VERSION); reservation.save(RefreshMode.REFRESH); claimDoc.checkin(AutoClassify.DO_NOT_AUTO_CLASSIFY,CheckinType.MAJOR_VERSION);