JNDI定义了一个Serializable接口类来为应用信息的表达提供一种统一的方式。Serializable接口类包含了诸如地址、类型信息等用于访问具体对象的信息。为了能将对象的引用绑定到目录树中,该对象的类必须实现Referenceable接口,其中包含了方法 getReference()。开发者可以在该对象上调用getReference()方法来获得Reference以用于绑定。Serializable接口与Referenceable接口有颇多相似之处,不同在于Referenceable可引用的对象只包含一些用于创建实际对象的信息,而Serializable会包含更多的甚至不适合存储在目录结构中的信息。
(2)绑定保存对象程序
package jndi;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.*;
public class ldapDataBind {
public static void main(String[]args){
//创建Hashtable以存储JNDI将用于连接目录服务的环境变量
Hashtable hs = new Hashtable();
//设置连接LDAP的实现工厂
hs.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
// 指定LDAP服务器的主机名和端口号
hs.put(Context.PROVIDER_URL, "ldap://localhost:389 ");
//给环境提供认证方法,有SIMPLE、SSL/TLS和SASL
hs.put(Context.SECURITY_AUTHENTICATION, "simple");
//指定进入的目录识别名DN
hs.put(Context.SECURITY_PRINCIPAL, "cn=Directory Manager");
//进入的目录密码
hs.put(Context.SECURITY_CREDENTIALS, "password");
try {
// 得到初始目录环境的一个引用
DirContext ctx = new InitialDirContext(hs);
// 新建一个对象
persons perObj = new persons("jordan","40");
//绑定对象
ctx.rebind ("uid = Jordan,ou = Bull,o = NBA ",perObj);
System.out.println("bind object object success " );
/*实例化一个属性集合*/
Attributes attrs = new BasicAttributes(true);
/*建立一个属性,其属性名为"mail"*/
Attribute personMail = new BasicAttribute("mail");
//设置属性"mail"的值为"xie@163.com"、"liu@sina.com.cn"、
"xyh@powerise.com.cn"
personMail.add("xie@163.com");
personMail.add("liu@sina.com.cn");
personMail.add("xyh@powerise.com.cn");
attrs.put(personMail);
/*建立一个属性,其属性名为"uid",值为001*/
attrs.put("uid","001");
/*建立一个属性,其属性名为"cn",值为jordan1*/
attrs.put("cn","jordan1");
/*建立一个属性,其属性名为"sn",值为NBA */
attrs.put("sn","NBA");
/*建立一个属性,其属性名为"ou",值为bull */
attrs.put("ou","bull");
System.out.println("bind object object success " );
/* 在识别名为DN的目录中增加一个条目*/
ctx.createSubcontext("uid = Jordan, ou = Wizzard,o=NBA",attrs);
//关闭初始目录环境
ctx.close();
} catch (NamingException ex) {
System.err.println("bind object fail: " + ex.toString());
}
}
}
2.使用JNDI查找数据
前面已经介绍了怎么样将对象数据绑定到服务器,现在开始介绍如何取得调用绑定在服务器上的对象数据。
5 例6-2 使用JNDI查找数据。
要调用对象数据,首先就必须用JNDI查找绑定的对象和数据,查找出来后,再调用该对象。程序如下所示。
package jndi;
import java.nutil.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;
public class findUseBindObj {
public static void main(String[]args){
//创建Hashtable以存储JNDI将用于连接目录服务的环境变量
Hashtable hs = new Hashtable();
//设置连接Ldap的实现工厂
hs.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
// 指定LDAP服务器IP地址为本机及端口号为389
hs.put(Context.PROVIDER_URL, "ldap://localhost:389");
try {
// 得到初始目录环境的一个引用
DirContext ctx = new InitialDirContext(hs);
//利用lookup查找返回指定DN的条目对象
persons pers =(persons)ctx.lookup("uid=Jordan,ou=Bull,o=NBA");
// 利用远程对象调用远程方法,返回Age变量的值
String age = pers.getAge();
// 利用远程对象调用远程方法,返回Name变量的值
String name = pers.getName();
//输出Name的值
System.out.println("name is :" + name );
/*根据结点的DN来查找它的所有属性, 然后再从属性中得到所有的值,注意一个属性可
以有多个值*/
Attributes attrs=ctx.getAttributes("uid=Jordan,ou=Wizzard,o=NBA");
//循环获取并输出这个属性的所有属性值
for(NamingEnumeration ae = attrs.getAll();ae.hasMore();){
//获取一个属性
Attribute attr = (Attribute)ae.next();
System.out.println("Attribute : " + attr.getID());
//循环取得输出这个属性的所有属性值
for(NamingEnumeration ve = attr.getAll();ve.hasMore();){
System.out.println(" Value : " + ve.next());
}
}
//成功打印提示信息
System.out.println("find object success " );
//调用该对象的函数
pers.toString();
//关闭初始目录环境
ctx.close();
} catch (NamingException ex) {
System.err.println(ex.toString());
}
}
}
对于作为引用绑定在目录树中的对象,JNDI SPI 指定针对引用创建实际的对象。因此,在程序中只需要认为用lookup()方法返回的对象就是实际对象,而不用在调用什么方法来将引用转换为实际对象了,因为所有的工作都由JNDI内部完成了。
6.2.7 JNDI查询修改LDAP目录条目
前面已经介绍了如何在LDAP服务器里存储一个对象:主要是利用一个DN将对象绑定到LDAP服务器中,然后用lookup(DN)查找定位到绑定的对象,再对该对象进行操作。但是往往使用DN查找非常难,用户很难记住DN,因此我们可以使用其他属性(比如CN=Cherry)来检索包含那个属性的条目。下面来介绍JNDI中相关属性检索的具体使用。
1.修改条目
很多时候可能要对LDAP服务器上的条目进行修改,如修改用户密码,更新应用的配置等。但修改必须由一个已认证过的用户来执行,而且通常只能修改自己的密码而不能修改其他信息,管理助手能够修改电话号码和邮件地址,而修改用户标识这种工作由数据库管理员完成。
6 例6-3 用JNDI修改LDAP条目。
package jndi;
import java.nutil.Hashtable;
import javax.naming.Context;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;
public class jndiPropertyModify {
public static void main(String[] args){
Hashtable hs = new Hashtable();
//设置连接LDAP的实现工厂为com.sun.jndi.ldap.LdapCtxFactory
hs.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.
LdapCtxFactory");
//指定提供服务的服务器IP地址和端口号
hs.put(Context.PROVIDER_URL,"ldap://localhost:389");
//使用简单认证来认证用户
hs.put(Context.SECURITY_AUTHENTICATION,"simple");
hs.put(Context.SECURITY_PRINCIPAL,"uid=Jordan,ou=Bull,o=NBA");
hs.put(Context.SECURITY_CREDENTIALS,"good");
try {
/*指定了JNDI服务提供者中工厂类(factory class)的名称。Factory负
责为其服务创建适当的InitialContext对象。在上面的代码片断中,为文件
系统服务提供者指定了工厂类*/
DirContext ctx = new InitialDirContext(hs);
System.out.println("成功创建初始化context对象!");
//新建生成一个修改条目类对象,用于存放条目属性
ModificationItem[] mdi = new ModificationItem[2];
// 把属性mail的值置为jordan@163.com
Attribute att0 = new BasicAttribute("mail",
"jordan@163.com");
// 把属性call的值置为12745827
Attribute att1 = new BasicAttribute("call","12745827");
//修改指定属性mail
mdi[0]=new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
att0);
//增加新属性call到条目
mdi[1]=new ModificationItem(DirContext.ADD_ATTRIBUTE,att1);
// 修改指定DN条目的属性
ctx.modifyAttributes("uid=Jordan,ou=Bull,o=NBA",mdi);
}catch(Exception ex ){
ex.printStackTrace();
System.exit(1);
}
}
}
上面程序的作用是修改前面例子中增加的DN为uid = Jordan,ou = Bull,o = NBA条目的属性。
在程序中用DirContext.REPLACE_ATTRIBUTE来修改条目的mail属性,在这里如果原来的mail属性有多个值时,都会被删掉,取而代之的是新赋的值。用DirContext. REPLACE_ATTRIBUTE时,如果原来的属性(mail)不存在时,就增加一个属性,有则修改。
用DirContext.ADD_ATTRIBUTE来将一个新属性增加到条目。真正起到修改作用的是ctx.modifyAttributes("uid = Jordan,ou = Bull,o = NBA",mdi)这条语句。
2.删除条目
有时,当开发者不需要某个条目时,就可以把它从LDAP服务器上删除。这只要通过调用参数为指定DN条目的DirContext接口的destorySubContext()方法来完成。
7 例6-4 用JNDI删除LDAP条目。
package jndi;
import java.nutil.Hashtable;
import javax.naming.Context;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;
public class jndiPropertyModify {
public static void main(String[] args){
Hashtable hs = new Hashtable();
//设置连接LDAP的实现工厂为com.sun.jndi.ldap.LdapCtxFactory
hs.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.
LdapCtxFactory");
//指定提供服务的服务器IP地址和端口号
hs.put(Context.PROVIDER_URL,"ldap://localhost:389");
//使用简单认证来认证用户
hs.put(Context.SECURITY_AUTHENTICATION,"simple");
// 指定DN
hs.put(Context.SECURITY_PRINCIPAL,"uid=Jordan,ou=Bull,o=NBA");
// 指定认证密码
hs.put(Context.SECURITY_CREDENTIALS,"good");
try {
/*指定了JNDI服务提供者中工厂类(factory class)的名称。Factory负
责为其服务创建适当的InitialContext对象。在上面的代码片断中,为文件
系统服务提供者指定了工厂类*/
DirContext ctx = new InitialDirContext(hs);
//删除指定DN条目
ctx.destroySubcontext("uid=Jordan,ou=Bull,o=NBA");
}catch(Exception ex ){
ex.printStackTrace();
System.exit(1);
}
}
}
(2)绑定保存对象程序
package jndi;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.*;
public class ldapDataBind {
public static void main(String[]args){
//创建Hashtable以存储JNDI将用于连接目录服务的环境变量
Hashtable hs = new Hashtable();
//设置连接LDAP的实现工厂
hs.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
// 指定LDAP服务器的主机名和端口号
hs.put(Context.PROVIDER_URL, "ldap://localhost:389 ");
//给环境提供认证方法,有SIMPLE、SSL/TLS和SASL
hs.put(Context.SECURITY_AUTHENTICATION, "simple");
//指定进入的目录识别名DN
hs.put(Context.SECURITY_PRINCIPAL, "cn=Directory Manager");
//进入的目录密码
hs.put(Context.SECURITY_CREDENTIALS, "password");
try {
// 得到初始目录环境的一个引用
DirContext ctx = new InitialDirContext(hs);
// 新建一个对象
persons perObj = new persons("jordan","40");
//绑定对象
ctx.rebind ("uid = Jordan,ou = Bull,o = NBA ",perObj);
System.out.println("bind object object success " );
/*实例化一个属性集合*/
Attributes attrs = new BasicAttributes(true);
/*建立一个属性,其属性名为"mail"*/
Attribute personMail = new BasicAttribute("mail");
//设置属性"mail"的值为"xie@163.com"、"liu@sina.com.cn"、
"xyh@powerise.com.cn"
personMail.add("xie@163.com");
personMail.add("liu@sina.com.cn");
personMail.add("xyh@powerise.com.cn");
attrs.put(personMail);
/*建立一个属性,其属性名为"uid",值为001*/
attrs.put("uid","001");
/*建立一个属性,其属性名为"cn",值为jordan1*/
attrs.put("cn","jordan1");
/*建立一个属性,其属性名为"sn",值为NBA */
attrs.put("sn","NBA");
/*建立一个属性,其属性名为"ou",值为bull */
attrs.put("ou","bull");
System.out.println("bind object object success " );
/* 在识别名为DN的目录中增加一个条目*/
ctx.createSubcontext("uid = Jordan, ou = Wizzard,o=NBA",attrs);
//关闭初始目录环境
ctx.close();
} catch (NamingException ex) {
System.err.println("bind object fail: " + ex.toString());
}
}
}
2.使用JNDI查找数据
前面已经介绍了怎么样将对象数据绑定到服务器,现在开始介绍如何取得调用绑定在服务器上的对象数据。
5 例6-2 使用JNDI查找数据。
要调用对象数据,首先就必须用JNDI查找绑定的对象和数据,查找出来后,再调用该对象。程序如下所示。
package jndi;
import java.nutil.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;
public class findUseBindObj {
public static void main(String[]args){
//创建Hashtable以存储JNDI将用于连接目录服务的环境变量
Hashtable hs = new Hashtable();
//设置连接Ldap的实现工厂
hs.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
// 指定LDAP服务器IP地址为本机及端口号为389
hs.put(Context.PROVIDER_URL, "ldap://localhost:389");
try {
// 得到初始目录环境的一个引用
DirContext ctx = new InitialDirContext(hs);
//利用lookup查找返回指定DN的条目对象
persons pers =(persons)ctx.lookup("uid=Jordan,ou=Bull,o=NBA");
// 利用远程对象调用远程方法,返回Age变量的值
String age = pers.getAge();
// 利用远程对象调用远程方法,返回Name变量的值
String name = pers.getName();
//输出Name的值
System.out.println("name is :" + name );
/*根据结点的DN来查找它的所有属性, 然后再从属性中得到所有的值,注意一个属性可
以有多个值*/
Attributes attrs=ctx.getAttributes("uid=Jordan,ou=Wizzard,o=NBA");
//循环获取并输出这个属性的所有属性值
for(NamingEnumeration ae = attrs.getAll();ae.hasMore();){
//获取一个属性
Attribute attr = (Attribute)ae.next();
System.out.println("Attribute : " + attr.getID());
//循环取得输出这个属性的所有属性值
for(NamingEnumeration ve = attr.getAll();ve.hasMore();){
System.out.println(" Value : " + ve.next());
}
}
//成功打印提示信息
System.out.println("find object success " );
//调用该对象的函数
pers.toString();
//关闭初始目录环境
ctx.close();
} catch (NamingException ex) {
System.err.println(ex.toString());
}
}
}
对于作为引用绑定在目录树中的对象,JNDI SPI 指定针对引用创建实际的对象。因此,在程序中只需要认为用lookup()方法返回的对象就是实际对象,而不用在调用什么方法来将引用转换为实际对象了,因为所有的工作都由JNDI内部完成了。
6.2.7 JNDI查询修改LDAP目录条目
前面已经介绍了如何在LDAP服务器里存储一个对象:主要是利用一个DN将对象绑定到LDAP服务器中,然后用lookup(DN)查找定位到绑定的对象,再对该对象进行操作。但是往往使用DN查找非常难,用户很难记住DN,因此我们可以使用其他属性(比如CN=Cherry)来检索包含那个属性的条目。下面来介绍JNDI中相关属性检索的具体使用。
1.修改条目
很多时候可能要对LDAP服务器上的条目进行修改,如修改用户密码,更新应用的配置等。但修改必须由一个已认证过的用户来执行,而且通常只能修改自己的密码而不能修改其他信息,管理助手能够修改电话号码和邮件地址,而修改用户标识这种工作由数据库管理员完成。
6 例6-3 用JNDI修改LDAP条目。
package jndi;
import java.nutil.Hashtable;
import javax.naming.Context;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;
public class jndiPropertyModify {
public static void main(String[] args){
Hashtable hs = new Hashtable();
//设置连接LDAP的实现工厂为com.sun.jndi.ldap.LdapCtxFactory
hs.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.
LdapCtxFactory");
//指定提供服务的服务器IP地址和端口号
hs.put(Context.PROVIDER_URL,"ldap://localhost:389");
//使用简单认证来认证用户
hs.put(Context.SECURITY_AUTHENTICATION,"simple");
hs.put(Context.SECURITY_PRINCIPAL,"uid=Jordan,ou=Bull,o=NBA");
hs.put(Context.SECURITY_CREDENTIALS,"good");
try {
/*指定了JNDI服务提供者中工厂类(factory class)的名称。Factory负
责为其服务创建适当的InitialContext对象。在上面的代码片断中,为文件
系统服务提供者指定了工厂类*/
DirContext ctx = new InitialDirContext(hs);
System.out.println("成功创建初始化context对象!");
//新建生成一个修改条目类对象,用于存放条目属性
ModificationItem[] mdi = new ModificationItem[2];
// 把属性mail的值置为jordan@163.com
Attribute att0 = new BasicAttribute("mail",
"jordan@163.com");
// 把属性call的值置为12745827
Attribute att1 = new BasicAttribute("call","12745827");
//修改指定属性mail
mdi[0]=new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
att0);
//增加新属性call到条目
mdi[1]=new ModificationItem(DirContext.ADD_ATTRIBUTE,att1);
// 修改指定DN条目的属性
ctx.modifyAttributes("uid=Jordan,ou=Bull,o=NBA",mdi);
}catch(Exception ex ){
ex.printStackTrace();
System.exit(1);
}
}
}
上面程序的作用是修改前面例子中增加的DN为uid = Jordan,ou = Bull,o = NBA条目的属性。
在程序中用DirContext.REPLACE_ATTRIBUTE来修改条目的mail属性,在这里如果原来的mail属性有多个值时,都会被删掉,取而代之的是新赋的值。用DirContext. REPLACE_ATTRIBUTE时,如果原来的属性(mail)不存在时,就增加一个属性,有则修改。
用DirContext.ADD_ATTRIBUTE来将一个新属性增加到条目。真正起到修改作用的是ctx.modifyAttributes("uid = Jordan,ou = Bull,o = NBA",mdi)这条语句。
2.删除条目
有时,当开发者不需要某个条目时,就可以把它从LDAP服务器上删除。这只要通过调用参数为指定DN条目的DirContext接口的destorySubContext()方法来完成。
7 例6-4 用JNDI删除LDAP条目。
package jndi;
import java.nutil.Hashtable;
import javax.naming.Context;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;
public class jndiPropertyModify {
public static void main(String[] args){
Hashtable hs = new Hashtable();
//设置连接LDAP的实现工厂为com.sun.jndi.ldap.LdapCtxFactory
hs.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.
LdapCtxFactory");
//指定提供服务的服务器IP地址和端口号
hs.put(Context.PROVIDER_URL,"ldap://localhost:389");
//使用简单认证来认证用户
hs.put(Context.SECURITY_AUTHENTICATION,"simple");
// 指定DN
hs.put(Context.SECURITY_PRINCIPAL,"uid=Jordan,ou=Bull,o=NBA");
// 指定认证密码
hs.put(Context.SECURITY_CREDENTIALS,"good");
try {
/*指定了JNDI服务提供者中工厂类(factory class)的名称。Factory负
责为其服务创建适当的InitialContext对象。在上面的代码片断中,为文件
系统服务提供者指定了工厂类*/
DirContext ctx = new InitialDirContext(hs);
//删除指定DN条目
ctx.destroySubcontext("uid=Jordan,ou=Bull,o=NBA");
}catch(Exception ex ){
ex.printStackTrace();
System.exit(1);
}
}
}