问题描述
LotusDomino作为一种全球领先的协作、消息传递和Web支持软件,正在迅速地在中国企事业推广。Domino已经成为帮助每个人更灵活和更高效地工作的强大支持。如何从DOMINO数据库中获取数据,使这些数据为其他系统可用,已经成为许多企业迫切需要解决的问题。然而domino不同于普通的关系型数据库,由ibm/lotus自主研发,有自己的标准和特殊性,是一种另类的数据库类型。开发具有访问DOMINO服务器的应用程序的方法有许多种,但是普遍存在的问题是功能有很大的局限性,都要在依赖于lotousnotes这一庞大而昂贵的客户端软件。随着java语言和CORBA中间件技术的日趋成熟,新版本的Domino也提供了corba服务,使这一问题得到彻底的解决。java/corba访问domino的优点在于采用此技术开发的应用程序在不用安装lotusnotes的情况下获取远程domino服务器上的数据,真正做到了瘦客户端,为企业节省了不必要的开支,同时也极大的降低了应用程序部署的难度。由于这一技术刚刚发展两三年,国内基本上没有相应的中文资料,corba技术也属于比较高级的开发技术,绝大多数开发工程师都没有接触过,因此许多做数据集成的开发人员对domino的开发望而生畏。本文旨在为开发人员提供一个全面的java/corba访问domino的技术解决方案,并通过例程指导开发人员掌握这一新技术。其中也有笔者在开发过程中的一些经验与教训,相信对广大开发人员一定会有相当大的帮助。起点R3能够通过以下三种方式来获取Domino数据,第一种方式是Notes本地获取;第二种是DIIOP方式远程获取;第三种是Corba访问Domino,第一第二种方式只能在Windows平台下,第三种方式能够实现跨平台访问Domino。本文分为上下两篇,本文为上篇,先介绍第一第二两种方式获取数据,下篇再介绍第三种方式。在起点R3的Domino采集器中,有如下代码:if(properties.getProperty("local")==null){session=NotesFactory.createSession(((CrawlTask)job.getCrawltask()).getResourceuri(),((CrawlTask)job.getCrawltask()).getAccount(),((CrawlTask)job.getCrawltask()).getPassword());}else{session=NotesFactory.createSession();}即如果传入的插件参数中有local=true,则使用本地Notes访问数据,否则,通过DIIOP访问Domino数据,需要注意的是,起点R3在采集Domion数据的时候需要将Domino或者Notes的安装目录加入到PATH中,获取到session之后,通过以下代码获取数据库信息:db=session.getDatabase(session.getServerName(),properties.getProperty("database"));documentList=db.getAllDocuments();然后可以遍历documentList获得数据库中的所有文档。对Domino数据库的遍历有两种方式,第一种是通过documentList.getFirstDocument()和documentList.getNextDocument()顺序获取文档,第二种方式是documentList.getLastDocument()和documentList.getPrevDocument()逆序获取文档,最终获取到的是Document对象,然后通过以下代码来对Document的域进行遍历:Vectorid=fieldDoc.getItems();for(inti=0;i<id.size();i++){try{Itemitem=(Item)id.get(i);MetaTypemetaType=newMetaType(item.getName(),String.valueOf(item.getType()));if(item!=null&&item.getType()==1280){//表示是文本Vectorvalues=item.getValues();if(values!=null&&values.size()>0){StringBufferstrb=newStringBuffer();for(Objectvalue:values){if(strb.length()>0){strb.append("");}if(value!=null){strb.append(value.toString());}}metaType.setValue(strb.toString());outputText.getMetadata().add(item.getName(),metaType.getValue());}else{metaType.setValue(item.getValueString());outputText.getMetadata().add(item.getName(),metaType.getValue());}//metaType.setValue(item.getValueString());//outputText.getMetadata().add(item.getName(),metaType.getValue());}elseif(item!=null&&item.getType()==1024){//表示是时间DateTimedateTime=item.getDateTimeValue();if(dateTime!=null){metaType.setValue(String.valueOf(item.getDateTimeValue()));outputText.getMetadata().add(item.getName(),metaType.getValue());}}elseif(item!=null&&item.getType()==768){//表示是整型metaType.setValue(String.valueOf(item.getValueInteger()));outputText.getMetadata().add(item.getName(),metaType.getValue());}elseif(item!=null&&item.getType()==1){//表示是rtf域metaType.setValue(item.getValueString());outputText.getMetadata().add(item.getName(),metaType.getValue());}else{Vectorvalues=item.getValues();if(values!=null&&values.size()>0){StringBufferstrb=newStringBuffer();for(Objectvalue:values){if(strb.length()>0){strb.append("");}if(value!=null){strb.append(value.toString());}}metaType.setValue(strb.toString());outputText.getMetadata().add(item.getName(),metaType.getValue());}else{metaType.setValue(item.getValueString());outputText.getMetadata().add(item.getName(),metaType.getValue());}}dataList.add(metaType);}catch(Exceptionex){}}重点是集中特殊域的获取,其中,域类型1280是文本,1024是时间,768是数字,1表示RTF域,还有文本列表域等。RTF域的获取需要使用以下代码:if(item!=null&&item.getType()==1){//表示是rtf域/***处理RTF域中的文本内容*/if(properties!=null&&"false".equals(properties.getProperty("rtftext"))){}else{outputText.getMetadata().add(item.getName(),item.getValueString());}java.util.Vectorvector=document.getItems();for(inti=0;i<vector.size();i++){ItemitmWjbt=(Item)vector.get(i);if(itmWjbt!=null&&itmWjbt.getName().equals("$FILE")&&zipData.getFileMap().get(itmWjbt.getValueString())==null){EmbeddedObjecteo=document.getAttachment(itmWjbt.getValueString());InputStreaminput=eo.getInputStream();//从input中获取数据保存到文件或其他输出流input.close();}}文本列表域的获取需要使用Vectorvalues=item.getValues(),然后for(Objectvalue:values){if(strb.length()>0){strb.append("");}if(value!=null){strb.append(value.toString());}}在上篇中介绍了从JAVA中获取Domino数据库中的文档信息,但有一个缺点,就是必须要有本地Notes,即限制了只能在Windows下使用,在有些情况下,可能需要在其他操作系统中通过JAVA获取Domino数据,本文即为介绍在JAVA中使用CORBA实现跨操作系统访问Domino。本文介绍的Domino版本应该要在R5以上,R5以下版本未经验证,无法确认是否可行。注意,本文中需要使用lotus.domino.corba包,网络上找到这个库源码非常不容易,作者也是花费了不少时间才从国外一个小网站上下载到,如果有需要,请联系作者。Corba访问Domino过程比较复杂,大致如下:Stringior=http://127.0.0.1/diiop_ior.txt;Propertiesprops=newProperties();props.put("org.openorb.orb.core.ORB","org.openorb.orb.core.ORB");ORBorb=ORB.init(newString[]{},props);//通过IOR得到IObjectServer对象org.omg.CORBA.Objectobj=orb.string_to_object(ior);IObjectServerios=IObjectServerHelper.narrow(obj);//通过IObjectServer获得ISessionProtocolVersionmaxVersion=newProtocolVersion(IBase.DOM_MAJOR_MINIMUM_VERSION,IBase.DOM_MINOR_MINIMUM_VERSION);ProtocolVersionminVersion=newProtocolVersion(IBase.DOM_MAJOR_VERSION,IBase.DOM_MINOR_VERSION);SessionDatasd=ios.createSession(maxVersion,minVersion,((CrawlTask)job.getCrawltask()).getAccount(),((CrawlTask)job.getCrawltask()).getPassword());session=sd.sesObject;通过账号和密码访问登录Domino后获得session,然后通过session获得数据库信息,如下://使用ISessiondbCache=session.getDatabase(sd.serverName,properties.getProperty("database"),false);dCdata=dbCache.db.getAllDocuments();//iDatabase.search("1=1",null,10);IDatabaseHolderidatabaseholder=newIDatabaseHolder();IntHolderintholder=newIntHolder();IDocumentdocument=dCdata.dcObject.getFirstDocMDB(idatabaseholder,intholder);一样是或得到document,类型为IDocument,dCdata.dcObject即是文档列表,对此对象遍历即可document=dCdata.dcObject.getNextDocMDB(document,idatabaseholder,intholder);对IDocument对象的遍历也和DIIOP也有一些差别:ItemData[]id=fieldDoc.getData().items;for(inti=0;i<id.length;i++){MetaTypemetaType=newMetaType(id[i].name,String.valueOf(id[i].type));ItemValueitem=id[i].values;if(id[i].type==1280){//表示是文本metaType.setValue(item.StringValue());}elseif(id[i].type==1024){//表示是时间DateTimedateTime=item.TimeObject();if(dateTime!=null){metaType.setValue(String.valueOf(dateTime.toString()));}}elseif(id[i].type==768){//表示是整型metaType.setValue(String.valueOf(String.valueOf(item.DoubleValue())));}elseif(id[i].type==1){//表示是rtf域//获得RTF域的附件信息}else{metaType.setValue(item.StringValue());}}类型代码和上篇中介绍的都是一样的,但RTF域的附件信息获取方式不太一样,需要对items[i].RTObject对象进行进一步处理,处理过程如下:IRichTextItemrtf=items[i].RTObject;if(item.StringValue()!=null){outputText.getMetadata().add(items[i].name,item.StringValue());}elseif(rtf.getValueAsString()!=null){outputText.getMetadata().add(items[i].name,rtf.getValueAsString());}{NameAndObject[]ed=rtf.getEmbeddedObjects();if(ed.length>0){for(NameAndObjectnameObject:ed){EmbeddedDataeo=document.getAttachment(nameObject.name);if(eo!=null&&eo.embedObject!=null&&eo.embedObject.getFileSize()>0){BooleanHolderholder=newBooleanHolder(true);IntHolderinholder=newIntHolder();byte[]data=null;java.io.ByteArrayOutputStreamoutput=newjava.io.ByteArrayOutputStream();try{while((data=eo.embedObject.getFile(inholder,holder))!=null&&data.length>0){output.write(data);}}catch(Exceptionex){ex.printStackTrace();}java.io.ByteArrayInputStreaminput=newByteArrayInputStream(output.toByteArray());//获得输入流,自定义后续处理过程input.close();}}}}最后是关闭session和db,db.recycle();