深入 apache 目录服务器
简介:这个两部分的系列介绍了在 Apache 目录服务器(ApacheDS)中保存 Java™ 对
象的步骤 。在第 1 部分中,作者 Bilal Siddiqui 介绍了 ApacheDS,并提供了 ApacheDS
核心架构的概述。因为 主要把 ApacheDS 用作保存 Java 对象的 LDAP 服务器,所以
Bilal 提供了对 LDAP 概念和术语的快速 概述。他还介绍了如何用 JXplorer 查看 LDAP
模式组件,例如属性类型和对象类,还介绍了如何在 ApacheDS 中输入数据对象。文章末
尾概述了 Java 对象的序列化和远程方法调用,并用它们把 Java 对 象保存在 ApacheDS
中,为 第 2 部分中 实践性更强的方法做好准备。
Apache 目录服务器是众多的 Internet 协议中的一个开放源码的、基于 Java 的实现。
ApacheDS 的 核心是目录服务,可以保存数据,并对不同类型的数据进行搜索操作。协议
的实现在目录服务器顶层工作 ,提供与数据存储、搜索和检索有关的 Internet 服务。
ApacheDS 最重要的特性可能是利用不同协议公开目录服务的能力。这意味着可以把
应用程序的数据(包括运行时的 Java 对象)保存在 ApacheDS 中,而不同的客户机可以
使用不同的协议来利用数据。由 ApacheDS 实现的最重要的协议是轻 量级目录访问协议
(LDAP)。ApacheDS 充当 LDAP 服务器,侦听请求,与内部核心目录服务协调,响应
LDAP 请求。
在这个两部分的系列中,我将介绍核心的 ApacheDS 架构,并介绍在 ApacheDS 中保
存运行时 Java 对象的全部步骤。因为我对 ApacheDS 的关注几乎全在它作为 LDAP 服
务器实现上,所以 本系列的第 1 部分主要介绍 LDAP 功能和术语。但在进入这部分之前,
我要介绍 ApacheDS 模块化的可 扩展架构,并解释如何用它把新的协议实现和 Internet
服务插入 ApacheDS。对 ApacheDS 核心目录服 务工作方式的理解,有助于后面理解它提
供 LDAP 功能的方式。
要跟上这篇文章的讨论,需要 下 载并安装 ApacheDS 和 JXplorer。可能还要下载 完
整源代码 供文章使用。
第一部分 ApacheDS 中的目录 服务
目录服务 是保存和组织数据的应用程序。目录服务处理不需要频繁更新的数据,例如
系统用 户的个人数据(例如姓名、地址、电话号码)或者车间的生产能力(例如安装的设
备的数量、型号和生产 能力)。在本系列的第 2 部分中,将介绍一个整合了这两种类型数
据的示例应用程序。现在,我把重点 放在 ApacheDS 提供目录服务的方式上。
ApacheDS 实现 JNDI
在图 1 中可以看到, ApacheDS 为自己的核心目录服务实现了 Java 名称和目录接
口(JNDI)包装器。JNDI 是 Java 接口,定 义了执行目录操作的方法,例如在目录中保
存数据和搜索保存的数据。JNDI 是 Java 2 企业版(J2EE) 和 Java 2 标准版(J2SE)
的组成部分。其中 J2SE 只包含客户端 JNDI 支持,而 J2EE 容器通常包含服 务器端
JNDI 实现。J2EE 容器可以通过 ApacheDS 的 JNDI 包装器利用它的目录服务,如图 1
所示:
图 1
JNDI 中的接口集提供了 目录服务的抽象。JNDI 实现提供了与目录服务对话的实际
逻辑(例如,Java 平台自带了针对 LDAP 的 JNDI 实现)。只要拥有针对这一类型的 JNDI
实现,您就可以用 JNDI 与任何类型的目录服务对话。如 果想在基于 Java 的客户机应用
程序中使用 JNDI,就需要 JNDI 的客户端实现。客户端 JNDI 实现提供 的类,实现的
是进行目录操作请求的 JNDI。
ApacheDS 实现服务器端 JNDI。这意味着它包含的类 ,实现的是对目录操作请求进
行响应的 JNDI 接口。正如前面指出的(如 图 1 所示),J2EE 容器可以 通过 ApacheDS
的 JNDI 包装器利用它的目录服务。
可插入的协议支持
图 1 只显示了 ApacheDS 的一个使用模型。ApacheDS 的用途不仅仅是嵌在 J2EE
容器内作为目录服务。可以用 ApacheDS 实现任何需要后端目录服务的协议。甚至可以用
它同时为各种类型的协议服务;例如,当前的 ApacheDS 实现就同时实现了 LDAP 和
Kerberos。而且,ApacheDS 中支持的协议的列表仍在增长。
ApacheDS 拥有灵活的可扩展的架构,因此可以实现新的协议。在图 2 中可以看到
ApacheDS 架 构的模型,它工作在 图 1 所示的 JNDI 包装器之上:
图 2. ApacheDS 灵活的可扩展的架构
可以看到,ApacheDS 使用一套叫做多用途网络应用程序接口(MINA)的接口。MINA
支持把新的协议实现插入 ApacheDS。在介 绍这些内容之前,我要解释一下 MINA 的工
作方式。
MINA 如何工作
MINA 中的接口包含的 方法可以生成特定协议的工厂对象。这些工厂对象提供了把新
协议实现插入 ApacheDS 的手段。协议实现 负责实现 MINA 接口,ApacheDS 框架依靠
MINA 包含的方法与协议实现对话。
例如,MINA 有一 个叫做 ProtocolProvider 的接口,该接口有一个 getCodecFactory()
方 法 。 ProtocolProvider.getCodecFactory() 方 法 返 回 一 个 对 象 , 公 开 另 一 个 叫 做
ProtocolCodecFactory 的 MINA 接口。
ApacheDS 中的协议实现,实现了 ProtocolProvider 接口。例如,ApacheDS 中的
LDAP 实现拥有一个叫做 LDAPProtocolProvider 的类,这个类实现了 ProtocolProvider
接口。
LDAPProtocolProvider 中 的 getCodecFactory() 方 法 返 回 一 个 公 开
ProtocolCodecFactory 接 口 的 对 象 。 这 个 ProtocolCodecFactory 是 一 个 工 厂 对 象 ,
ApacheDS 框架用它创建特定于 LDAP 的编码 和解码对象。
ProtocolCodecFactory 包含 newEncoder() 和 newDecoder() 方法,这两个方法返 回
的对象公开 MINA 的 ProtocolEncoder 和 ProtocolDecoder 接口。特定于协议的编码对
象公开 ProtocolEncoder 接口,而解码对象则公开 ProtocolDecoder 接口。
MINA 的编码和解码框架
猜也猜得出来,ApacheDS 框架使用特定于协议的 ProtocolDecoder 实例对协议请求
进行解码, 这样就可以在处理请求之前理解请求的意义。在解码之后,ApacheDS 处理请
求。例如,如果请求是一个 LDAP 搜索请求,那么 ApacheDS 就会在后端目录服务中搜
索需要的数据,并提取搜索结果。
在找 到需要的搜索结果后,ApacheDS 框架用特定于协议的 ProtocolEncoder 对象编
码 搜 索 结 果 。 在 LDAP 搜 索 请 求 的 示 例 中 ,ApacheDS 会 使 用 特 定 于 LDAP 的
ProtocolEncoder 对象在向请求客户机发送响应之前 对搜索结构进行编码。
MINA 的服务框架
MINA 还有处理服务的类。任何服务提供者都可以 把自己注册到一个服务注册表,而
协议提供者会与提供服务的提供者类一起注册。然后协议提供者就把协 议请求映射成
JNDI 操作。简单的示例就是映射到 JNDI 搜索请求的 LDAP 搜索请求。一旦 ApacheDS
框 架了解了在处理协议请求时需要包含哪个 JNDI 操作,它就能生成事件。
MINA 中的事件处理框架 把事件传递给适当的处理程序。例如,如果请求需要调用
JNDI 搜索操作,那么就调用搜索处理程序。 MINA 还维护了一个线程池。如果处理程序
正忙着处理前一个操作,那么事件会临时保存在线程池中,直 到得到处理。
在 图 2 中可以看到操作 JNDI 的协议提供者、MINA 接口、类以及操作处理程序。
ApacheDS 框架最大的优势可能是它使用公共的目录服务(JNDI)处理不同的协议提
供者。这意味 着可以使用 ApacheDS 时,可以用不同的协议向客户机公开数据。因为
ApacheDS 支持的最重要的协议是 LDAP (而且因为日后主要会把 ApacheDS 用作保存
Java 对象的 LDAP 服务器),所以我想进一步深入 讨论 LDAP。
LDAP 概述
LDAP 协议定义了目录操作的请求和响应消息。目录操作包括把新 数据保存到目录,
搜索和检索保存的数据,删除不需要的数据,更新过时数据,以及类似的操作。
ApacheDS 中用来保存新数据(例如运行时 Java 对象)的 LDAP 消息叫做绑定
(bind) 消息。 绑定消息把用户数据传输到 LDAP 目录服务 —— 例如 ApacheDS,并
把数据保存到目录。
LDAP 并不考虑数据存储的物理位置。相反,LDAP 保存在 ApacheDS 中的每个数据
条目指定了专 有名称(Distinguished Name,DN)。在整个目录服务中,每个 DN 都必须
是惟一的。不允许有两个条目 拥有相同的 DN。在本文后面将了解到 LDAP 保证每个 DN
惟一的机制。
另外,LDAP 中的搜索机 制也使用 DN。下一节介绍的示例应用程序场景将让您熟悉
LDAP 的术语,并介绍 LDAP 的搜索机制。贯 穿这个两部分的系列,我都将使用这个示
例应用程序。
学习用的应用程序
对于应用程序的 场景,假设要为一个制造公司设计一个数据管理系统。公司有员工、
客户、合作伙伴和供应商,他们都是 数据管理系统的用户。现在要求数据管理系统把关于
用户的数据保存在 ApacheDS 中。
系统允许 所有用户都可以设置自己喜欢的使用系统的方式。例如,用户可以定制在使
用系统时,在个人的默认视图 中显示的数据,并为不同的数据元素应用不同的显示样式。
系统还支持根据用户类型 的特殊设置。例如 ,公司的员工(内部组织用户)可以设置消
息传递选项,客户可以设置发货选项,供应商可以设置发票选 项。
在 ApacheDS 中设置每个用户的设置的简单方式是以 Java 对象的形式保存选项。对
于 这 个 应 用 程 序 场 景 , 可 以 从 设 计 一 个 针 对 所 有 用 户 类 型 的 Preferences 类 开 始 。
Preferences 类包含的方法 允许用户设置所有用户类型(在这个示例中,是内部用户、客
户和供应商)公共的选项。例如, Preferences 类可能包含一个 setStyles() 方法,用于指
定样式表的位置。可以用样式表给不同的数据 元素应用显示样式。
也可以扩展 Preferences 类,形成 MessagingPreferences 类,用它包含针 对内部用户
的 消 息 传 递 选 项 。 类 似 地 , 可 以 为 客 户 设 计 ShippingPreferences 类 , 为 供 应 商 设 计
InvoicingPreferences 类。
清 单 1 是 Preferences 、 MessagingPreferences 、 ShippingPreferences 和
InvoicingPreferences 类的骨架。为简单起见,在清单 1 中我没有包含任何 方法(除了
setStyles() 方法)。现在我只想演示类实例在 ApacheDS 中的存储。
清单 1. 代表 不同类型用户的选项的 Java 类
public
class Preferences
implements
java.io.Serializable
{
String
styleSheetURL = null;
public
void setStyles(String
styleSheetURL){
this.styleSheetURL =
styleSheetURL;
}
//Other methods
of
the Preferences
class
}
public
class MessagingPreferences
extends Preferences
{
//Methods
of
the MessagingPreferences
class
}
public
class ShippingPreferences
extends Preferences
{
//Methods
of
the
ShippingPreferences
class
}
public
class
InvoicingPreferences
extends Preferences
{
//Methods
of
the
InvoicingPreferences
class
}
用 ApacheDS 管理数据
假设 Alice 在制造公司的商务部门工作。她用数据管 理系统把她的所有数据(姓名、
部门、电子邮件地址、电话号码,等等)和她的选项(以 MessagingPreferences 对象的形
式)保存到 ApacheDS 中。她保存在 ApacheDS 中的所有数据都有一个 惟一的 DN。
术语说明
可以把 DN 当成目录服务中的命名上下文。Alice 这类用户的数据条目在她的 DN 定
义下的命名上下文中写入。实际上,通常会发现 DN 和命名上下文 这两个术语被互换地
使用。JNDI 文 档通常采用命名上下文这个术语,而 LDAP 文档则采用 DN 这个术语。
如果既使用 LDAP 又使用 JNDI, 那么可以认为这两个术语的含义相同。
现在假设 Alice 想用数据管理系统修改她的消息传递选项。数据管理系统首先用
LDAP 搜索 Alice 的命名上下文,以了 解它的 DN。在知道了 DN 之后,就从 DN 提取
Alice 的 MessagingPreferences 对象,用 Alice 的最 新数据更新对象,然后把对象保存回
ApacheDS。
现在脑子里有了一个应用程序场景,下面开始研 究如何用 ApacheDS 变化所有这些
服务器端魔术。
ApacheDS 入门
要理解如何在 ApacheDS 中存储各种类型的数据(包括 Java 对象),需要学习 LDAP
模式。而且,用图形方式查看 LDAP 服务器 中保存的数据会有帮助,在图形方式中可以
用树的形式查看数据。为了这个目的,我要介绍如何使用 JXplorer,这是个基于 Java 的
开放源码客户端 LDAP 实现,为保存在 LDAP 服务器中的数据提供了浏览 器视图。因为
我使用 JXplorer 来介绍 LDAP 模式,所以在继续之前需要 下载和安装 JXplorer。
如果还没有下载 ApacheDS,那么现在还需要 下载 ApacheDS。安装相当简单:会得
到一个 zip 文件,解压它得到 ApacheDS 的 JAR 文件。从命令行上,像下面这样运行
apacheds-main-0.9.jar,启 动 LDAP 服务器:
/java
-jar
apacheds-main-0.9.jar
ApacheDS 的 LDAP 服务器现在在 localhost:389 上(默认端口)侦听,准备为客户
机应 用程序的 LDAP 请求服务。
连接 ApacheDS
在启动了 ApacheDS 之后,请运行 JXplorer, 得到图 3 所示的浏览器视图。可以看
到,JXplorer 还没有连接到任何 LDAP 服务器。
图 3. 启 动 JXplorer 时的第一个视图