在经典的Lotus Notes应用程序开发中,表单与Notes文档密不可分,在位于表单的代码里获取当前文档几乎是后续所有操作和运算的起点。在XPages里,页面和数据虽然在架构上是分开的,但是一个用作表单的XPage的数据源通常还是一个Notes文档,只不过在SSJS里可以直接使用的document1等变量对应的是一个Java的com.ibm.xsp.model.domino.wrapped.DominoDocument对象。如果只用SSJS编程,这些变量具有和LotusScript里NotesDocument类似的方法可以读写字段。但如果要用Java开发,很多人已经习惯了使用lotus.domino包【注1】里的类,它们与LotusScript里的Notes类有几乎一一对应的属性和方法。那么怎样从一个设定了数据源为一个Domino文档的XPage获取代表该文档的lotus.domino.Document类型的Java对象呢?笔者写了如下的工具方法,可以在managedbean里调用:
public static Document getCurrentDocument() throws Exception{
UIViewRootEx2 view=(UIViewRootEx2) FacesContext.getCurrentInstance().getViewRoot();
for (DataSource ds : view.getData()){
if (ds instanceof DominoDocumentData){
DominoDocumentData ddd=(DominoDocumentData) ds;
DominoDocument dd=(DominoDocument) ddd.getDataObject();
return dd.getDocument();
}
}
throw new AppException("No document data source is found.");
}
UIViewRootEx2 view是代表整个XPage的视图对象,它的getData()方法返回该页面添加的所有数据源,这些对象都实现了com.ibm.xsp.model.DataSource接口。如果添加了一个Domino文档,就会产生一个类型为com.ibm.xsp.model.domino.DominoDocumentData的对象,从这个数据源对象的getDataObject()方法可以返回一个com.ibm.xsp.model.domino.wrapped.DominoDocument对象,从它的getDocument()方法才能最终得到我们想要的lotus.domino.Document对象。如果当前XPage没有添加任何Domino文档数据源,则抛出一个自定义的异常AppException(简单扩展Exception,统一标志自定义的异常)。
com.ibm.xsp.model.domino.wrapped.DominoDocument类(以后简称DominoDocument)从名称就显示了它是一个包装器(wrapper),实际上它也确实是XPages对lotus.domino.Document类(以后简称Document)的包装,因为Document类不能满足在一个XPage上作数据源的要求,XPages构建了一个复杂的类和接口的层次【注2】,Document只是在最底层作为和Lotus Domino平台的接口读写文档的数据,最上层的com.ibm.xsp.model.domino.DominoDocumentData类作为数据源,和它绑定的各个表单控件从中读写数据,还要在同一页面每次被提交后和视图一道恢复状态。因此,在XPages环境下用Java编程时,不少情况用DominoDocument比Document更合适。比如用户填写了一个XPage表单后,点击一个按钮触发managed bean里的事件代码,在业务逻辑里读取用户输入的字段值,修改和保存表单背后的Domino文档时,就都应该调用DominoDocument的相应方法,而不能用Document,因为与在Lotus Notes客户端NotesDocument的各字段动态获得用户的输入值不同,在XPages里更新的是DominoDocument对象,而不是底层的Document。所以只有从DominoDocument对象才能获得用户输入的值;保存时如果直接调用Document的save方法,则会丢失用户的修改;若要修改文档,也要使用DominoDocument对象,否则在调用DominoDocument的save方法时,Document上做的修改会被DominoDocument对应的字段值覆盖掉。既然我们要经常获得和使用这个DocuminoDocument对象,也就应该像Document一样写一个工具方法:
public static DominoDocument getCurrentDominoDocument() throws Exception{
UIViewRootEx2 view=(UIViewRootEx2) FacesContext.getCurrentInstance().getViewRoot();
for (DataSource ds : view.getData()){
if (ds instanceof DominoDocumentData){
DominoDocumentData ddd=(DominoDocumentData) ds;
return (DominoDocument) ddd.getDataObject();
}
}
throw new AppException("No document data source is found.");
}
有了这个对象我们就可以像下面这样读取修改和保存文档数据源。
DominoDocumentData domDoc=XSPUtil.getCurrentDominoDocument();
String status = domDoc.getItemValueString("Status");
domDoc.replaceItemValue("Action", "");
domDoc.save();
注1:lotus.domino包随R5发布,自那以后Java访问Lotus Domino对象都是藉由其中的类, XPages API里有关Domino对象的类也是依靠调用lotus.domino包。
注2:下面只是列举了XPages API里与Domino文档数据源相关的部分类和接口的层次:
Classcom.ibm.xsp.model.domino.DominoDocumentData
java.lang.Object
extended by com.ibm.xsp.complex.ValueBindingObjectImpl
extended by com.ibm.xsp.model.AbstractDataSource
extended by com.ibm.xsp.model.AbstractDocumentDataSource
extended by com.ibm.xsp.model.domino.DominoDocumentData
All Implemented Interfaces:
ComponentBindingObject,ValueBindingObject, DataPublishingObject, DataSource, DocumentDataSource,javax.faces.component.StateHolder
Classcom.ibm.xsp.model.domino.wrapped.DominoDocument
java.lang.Object
extended by com.ibm.xsp.model.domino.wrapped.DominoDocument
All Implemented Interfaces:
com.ibm.xsp.model.DataObject, java.io.Serializable