应用场景
我们需要远程访问 IBM Lotus Domino R6 服务器,从中获取用户邮箱的邮件信息等关键数据。我们不需要提供每一个用户密码以及 ID 文件。
技术关键词
Java :
Java 和 Lotus Notes/Domino 是理想的开发组合。
DIIOP :
IIOP , 是 Internet Inter-ORB Protocol , 一种传输层协议。它用于 CORBA 2.0 及兼容平台上。 IIOP 协议是要建立以下几个部分:一个 IIOP 到 HTTP 的网关,使用这个网关可以让 CORBA 客户访问 WWW 资源;一个 HTTP 到 IIOP 的网关,通过这个网关可以访问 CORBA 资源;一个为 IIOP 和 HTTP 提供资源的服务器,一个能够将 IIOP 作为可识别协议的浏览器。
其中 ORB 呢 , Object Request Broker( 请求对象代理 ) , 一个中间件 。它可以建立对象之间的 client/server 关系。通过 ORB ,一个 client 可以透明的引用同一台机器上或网络上的一个 server 对象的方法。 ORB 解释该调用并负责查找一个实现该请求的对象,找到后,把参数传给该对象,调用它的方法,最后返回结果。
那么, DIIOP 就 是 Domino IIOP 了 , 什么意思呢 ? 就是一个服务器端的任务 , 通过 Domino ORB , 来使得 Domino Server 与 Java applets 交互 , 双方使用 IIOP 来交互和交换对象数据。
IOR :
IOR , Interoperable Object Reference 。
实际上,就是 Domino 服务器上的一个文件 diiop_ior.txt 的内容,类似于:
IOR:01012d032900000049444c3a6c6f……………………… |
,它在 c:\lotus\domino\data\domino\html 文件夹下。
客户端 java 程序向 domino 服务器发出 CORBA 请求 , 服务器通过 HTTP 协议返回给客户端 IOR 字符串, 之后客户端通过 IIOP 协议与服务器进行通讯。
从这一点来看, IOR 实际上是一个对象的字符串编码,包含对 Domino 服务器的 CORBA 访问的识别信息。客户 端 java 程序 将字符串 IOR 解码,就可以用它来寻找到对应的主机并建立远程会话了。
Domino对象
Domino Database :
Domino 中的 Database ,指的是在一个名字下存储的,一个集合,包含了 Document 以及相应的 form 、 view 和 folder 。 Java 中有 lotus.domino.Database 。
我们通常可以通过 session 对象的 getDatabase 方法,或者 DbDirectory 对象的 getFirstDatabase/ getNextDatabase 方法,来获取 Database 对象的实例。
Domino View :
Database 集合中有着各种 View 。 Java 中有 lotus.domino.View 。可以通过 Database 对象的 getView 方法,来获取 View 对象的实例。
Domino Document :
Domino 中的 Document ,指的是在一个 Database 的一个条目,包含了 fileds , text , numbers , graphics 等等。 Java 中有 lotus.domino.Document 。
可以通过 Database 对象的 getView 方法,来获取 View 对象的实例。
环境准备
客户端 java 开发:
安装 Lotus Notes Client 。
安装 Eclipse 3.1 with Eclipse-JDT-SDK 。
安装 JRE 1.3.1 。 Lotus Notes/Domino 的 R5/6 版本使用的是 Java 1.3.1 ,所以必须安装该软件以使用正确的版本来编译项目。( Lotus Notes/Domino 7 使用 JDK 1.4 。)虽然许多 Java 代理和程序都可以编译,而且没什么问题,但可能会陷入另一些问题,比如使用一个 JDK 版本构建程序,却在另一个版本上运行。
从服务器端 Lotus 目录下复制 NCSO.jar 以及 NCSO.cab 文件。远端访问 Domino Server ,需要这个 jar 包。
Domino 提供了两个 JAR 文件,用于编程访问 Domino 对象。这两个文件是 Notes.jar 和 NCSO.jar 。Notes.jar 用来访问 本地的 Domino 服务器(此时 Lotus Domino 和 Java 程序运行在相同的服务器上)。NCSO.jar 包含了用来访问远程服务器的其他 CORBA/IIOP 代码。 在决定使用哪个 JAR 文件时,请考虑以下因素:
|
如果你不用超级管理员用户名密码创建连接 session ,而是采用 Domino Server ID ,那么请从 Domino 服务器上 Lotus 目录下复制一个 server.id 文件以备用。
如果你想直接使用 diiop_ior.txt , 把这个 diiop_ior.txt 复制到本地。
Domino 服务器端配置:
必须配置的项目:
必须设置 Domino 服务器监听 IIOP 请求 :
首先确保安装了 DIIOP ,你可以在安装过程中选择 DIIOP ,这样当安装结束,启动 Domino Server Console 时,就会看到提示“
DIIOP Server Listen for connect requests on TCP Port:63148
DIIOP Server Ultility task ”。
可以在 Domino Console 中执行 show task 或 load diiop 命令,可以帮助判断现在是否已经安装了 DIIOP 。如果还没有安装,请从 Domino 安装光盘上安装 DIIOP 。
否则,就要修改 lotus 目录下的 Notes.ini 文件了。找到以 ServerTask 开头的一行,找找看等号后面的字符串中是否有 DIIOP ,如果没有,就加上一个,然后重新启动 Domino Server 。这样, Domino 启动时就会自动加载 DIIOP 。
ServerTask 一行类似于:
ServerTasks=Update,Replica,Router,AMgr, AdminP,CalConn,Sched,DIIOP,HTTP,LDAP
如何获取 IOR :
在 DIIOP 进程启动时,它在 Domino HTTP 根目录( Windows 中 Domino 默认的安装目录为 C:\lotus\domino\data\domino\html )中创建一个名为 diiop_ior.txt 的 IOR ( Internet Object Reference )对象。
如何得到这个 diiop_ior.txt 内容 ( 也就是 IOR 了 ) ,有两个办法:
第一个就是,您通过 HTTP 方式向服务器请求这个文件。那么这个时候,如果您使用 Lotus Domino 作为 HTTP 服务器,就必须告诉 DIIOP 将这些文件放到您的 HTTP 服务器的根 HTML 目录中。配置方法如下所示:
1. 运行 Domino Admin 6 ,点击 “XXX Domain” 图标,打开 Domino Server 文档。
2. 选择 Internet Protocols 属性页 - DIIOP 子属性页。
3. 在 External HTML directory 字段中,输入非 Domino HTTP 服务器的根 HTML 目录的完整路径名。
4. 保存这个 Server 文档,并重新启动 DIIOP 。
第二个办法,是把这个 diiop_ior.txt 复制到客户端机器上,直接使用 。
TCP/IP 连接检查:
远程访问还需要设置 Domino Server 和客户端进行 TCP/IP 连接。 Domino Server 必须能够通过 TCP/IP 进行访问。必须能够用 Internet 名称从客户端 ping 到服务器。
DIIOP 设置:
检查 Domino Directory 中 Server 文档。转至 Ports 选项卡,然后转向 Internet Ports 选项卡。查看 Web 选项卡(用于 HTTP )并找到 DIIOP 选项卡。这些部分有用于指定端口号以及启用 / 禁用端口的字段。通常, HTTP 的端口号是 80 , DIIOP 的端口号是 63148 。下图显示了 Internet Ports--DIIOP 选项卡:
No. |
Items |
Descriptions |
1 |
Name and Password |
DIIOP 验证需要名称和密码 |
2 |
Anonymous |
DIIOP 验证不需要名称和密码 |
3 |
Enforce server access settings |
DIIOP 使用 Security 选项卡下的 Server Access 设置 |
如果访问数据库时不知道文件名称(例如,要使用 DbDirectory.getFirstDatabase ),那么必须允许通过网络浏览文件名。转至 Internet Protocols 选项卡、 HTTP 选项卡和 R5 Basics 选项卡。然后将 “Allow HTTP clients to browse databases” 设为 Yes 。
配置权限:
必须给你当前建立 session 的用户配置权限,否则你将会遇到下面的错误:
NotesException: You must have permission to sign documents for server based agents at lotus.domino.NotesExceptionHelper.read(Unknown Source) at lotus.domino.NotesExceptionHolder._read(Unknown Source) at lotus.priv.CORBA.iiop.RepImpl.invoke(Unknown Source) at lotus.priv.CORBA.portable.ObjectImpl._invoke(Unknown Source) at lotus.domino.corba._IDocumentStub.send(Unknown Source) at lotus.domino.cso.Document.send(Unknown Source) at SendMail.send(SendMail.java:203) at SendMail.main(SendMail.java:28) |
转至 Security 选项卡,找到“ Programmability Restrictions ”,在“ Run unrestricted methods and operations: ”和“ Sign agents to run on behalf of someone else: ”后面输入你的用户名:
总之,如果你遇到了权限错误,就到这里来配置。
开始编写
Add External JARs :
在 Eclipse 3.1 ,选中你的项目,右键菜单中“ Build Path ” à “ Add External Archives ”,在文件选择对话框中找到并选中你前面复制到本地的 NCSO.jar ,如下图所示。
添加了 JAR 文件之后,可以使用项目中 Notes Java API 定义的类和接口。 Domino Designer on-line help 中有关于 Notes Java API 的文档。
然后 选择 JRE System Library 采用 1.3.1 版本的。
获取 IOR :
首先,我们去获取 IOR 。
还是前面说过的两种办法。
第一种,与 Domino Server 联系获取:
Code |
String dominoHost = "192.168.1.223"; // 这里填写主机名或 IP 地址 String strIOR = null; URL url = new URL("http://" + dominoHost + "/diiop_ior.txt"); InputStream in = url.openStream(); BufferedReader br = new BufferedReader(new InputStreamReader(in)); for (boolean bExit = false; !bExit; ) { String line = br.readLine(); if (line == null) { bExit = true; } else { if (strIOR == null) strIOR = line; else strIOR = strIOR + line; if (strIOR.startsWith("IOR:")) bExit = true; } } br.close(); |
第二种,取得本地文件:
Code |
FileInputStream fin = new FileInputStream("c:\\diiop_ior.txt"); InputStreamReader fisr = new InputStreamReader(fin); BufferedReader br = new BufferedReader(fisr); String ior = br.readLine(); fin.close(); |
创建 session :
我们调用 NotesFactory 的 createSessionWithIOR 方法,通过前面获取的 IOR ,创建一个 session 对象。
Code |
Session s = NotesFactory.createSessionWithIOR(ior, "super admin" ,"admin password"); |
打开 names.nsf :
我们调用 session 的 getDatabase 方法,打开指定服务器上的 “ names.nsf ”数据库 。
Code |
final static String DB_NAMES = "names.nsf"; Database dbCache = s.getDatabase(s.getServerName(), DB_NAMES, false); |
得到 Users View :
我们调用 Database 的 getView 方法,打开指定数据库上的 “ ($Users) ”视图 。
Code |
View view = dbCache.getView("($Users)"); |
遍历 Users View :
我们可以遍历指定数据库上的 “ ($Users) ”视图,得到每一个用户的 Document 。
也可以指定一个用户,专门取得他的 Mail File ,
Code |
Document docKey = view.getDocumentByKey("zheng yun"); if (docKey == null) System.out.println("docKey not found!"); else { strMailFile = docKey.getItemValueString("MailFile"); if (strMailFile == null) System.out.println("strMailFile is null!"); else System.out.println("strMailFile = " + strMailFile); } |
输出结果就是: mail\zyun.nsf 或者 mail\zyun 。
这样,我们就知道了该用户的邮箱所在的数据库文件的路径了。
打开邮箱数据库文件 :
知道了一名用户的邮箱文件名称,我们可以再用 session 的 getDatabase 方法打开该数据库:
Code |
Database dbMail = s.getDatabase(s.getServerName(), "mail\\zyun.nsf", false); if(dbMail == null) System.out.println("cannot open database"); |