java jndi ldap 操作,兼容tivoli,标准的。
By:Roy.LiuLast updated:2011-06-18
最近在弄TIVOLI LDAP,TDS, TDS 本身有自己的 CLIENT API, 但是不好用,其实用JAVA JNDI 就可以了。通用的,JNDI 的教程,在JAVA官方网站上有介绍。。
JNDI Tutorial系列文章的第二部分:The Basics,介绍了JNDI的一些基础知识,诸如Naming操作和Directory操作。介绍了如何通过编程的方式访问命名和目录服务,如何使用JNDI和目录进行交互。从准备环境到查找对象以及在目录中进行搜索等操作。
本部分主要介绍了关于命名的一些操作(Naming Operations)
前提条件:创建命名操作所需的文件系统环境,通过执行Setup类进行初始化,设置根路径为d:/workspace/JNDITutorial/tmp/tutorial/。
可以通过使用JNDI来进行命名操作,例如读操作和更新名称空间操作。本部分内容中将主要介绍以下操作:
* Looking up an object
* Listing the contents of a context
* Adding, overwriting, and removing a binding
* Renaming an object
* Creating and destroying subcontexts
在这些例子中使用下面的环境属性初始化initial context:
// Set up environment for creating the initial context
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:d:/workspace/JNDITutorial/tmp/tutorial");
Context ctx = new InitialContext(env);
查找对象:
使用Context.lookup()方法来从命名服务中查找对象,需要将对象的名字作为参数传递给lookup方法。假设在命名服务中有一个叫做report.txt的对象,那么获取这个对象的代码为:
Object obj=ctx.lookup(“report.txt”);
lookup()方法返回的对象的类型由命名系统和对象自身关联的数据决定。一个命名系统可能包含多种不同类型的对象,并且根据对象在命名系统的位置的不同也会导致对象类型的不同。在本例中,”report.txt”绑定到一个java.io.File对象,可以进行强制类型转换。下面是查找操作的源代码:
import java.io.File;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
/**
* Demonstrates how to look up an object.
*
* usage: java Lookup
*/
class Lookup {
public static void main(String[] args) {
// Set up the environment for creating the initial context
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL,
"file:d:/workspace/JNDITutorial/tmp/tutorial");
try {
// Create the initial context
Context ctx = new InitialContext(env);
// Perform lookup and cast to target type
File f = (File) ctx.lookup("report.txt");
System.out.println(f);
// Close the context when we're done
ctx.close();
} catch (NamingException e) {
System.out.println("Lookup failed: " + e);
}
}
}
输出结果为:
d:\workspace\JNDITutorial\tmp\tutorial\report.txt
(注:需要将service provider的jar包加入到classpath中,文件为fscontext.jar和providerutil.jar)
(注:不能够将file:d:/workspace/JNDITutorial/tmp/tutorial中的file:去掉,因为第一个冒号前面的字符串为协议,冒号和d之间可以加多个”/”)
枚举上下文:
和调用Context.lookup()方法每次获取一个对象不同的是,使用Context.list()方法可以获取一个名称-对象枚举,Context.listBindings()方法可以返回一个所有的绑定。
Context.list()方法
Context.list()方法返回一个NameClassPair的美剧。每个NameClassPair由对象名和其所属的类名组成。下面的代码片断列出了awt目录下的内容(文件和目录):
NamingEnumeration list = ctx.list("awt");
// Go through each item in list
while (list.hasMore()) {
NameClassPair nc = (NameClassPair) list.next();
System.out.println(nc);
}
运行上面例子的结果如下:
accessibility: javax.naming.Context
......
swing: javax.naming.Context
(它只列举出awt目录下面的直接目录或者文件。)
Context.listBindings()方法
Context.listBindings()方法返回一个绑定的枚举。Binding类似NameClassPair的子类。一个绑定不仅仅包好对象名和类名,还包含对象本身。下面的代码列举出awt上下文中的所有绑定并打印:
NamingEnumeration bindings = ctx.listBindings("awt");
// Go through each item in list
while (bindings.hasMore()) {
Binding bd = (Binding) bindings.next();
System.out.println(bd.getName() + ": " + bd.getObject());
}
输出结果如下:
accessibility: com.sun.jndi.fscontext.RefFSContext@1cf8583
......
swing: com.sun.jndi.fscontext.RefFSContext@dbe178
终止NamingEnumeration
一个NamingEnumeration可以有三种终止方式:自然终止、显式终止和异常终止。
¨ 当NamingEnumeration.hasMore()方法返回false的时候,枚举已经完成,所以终止。
¨ 可以在枚举完成之前显式的终止它,通过调用NamingEnumeration.close()方法。
¨ 如果hasMore()方法或者next()方法抛出NamingException时,枚举终止。
无论以哪种方式终止NamingEnumeration,一旦终止后,就不能再被使用。调用已经终止的枚举对象会返回一个未定义的结果。
为什么有两种不同的列举方法
list()方法的目的是提供给浏览器风格的应用程序,这些应用程序只希望显示上下文中的对象的名称。例如一个浏览器可能只希望列出上下文中的名字供用户选择以便执行更进一步的操作,这样的应用程序一般不需要访问上下文中的所有对象。
listBindings()方法的目的是提供给应用程序,这些应用程序对上下文中的对象进行操作。例如,一个备份应用程序可能需要对一个文件目录中的所有对象执行”file stats”操作。又或者一个打印机管理程序可能希望重启整个大厦中的所有打印机。为了执行这些操作,应用程序需要获取上下文中绑定的所有对性。所以这个时候需要将对象本身作为结果返回。但是使用listBindings()方法的开销要比list()的大。
添加、替换和移除绑定
Context接口包含添加、替换和删除绑定的方法。
添加绑定
Context.bind()方法用于向上下文中添加一个绑定,它接受绑定的名字和要绑定的对象作为参数。
下面的例子演示了将一个Fruit对象和favoriate名字进行绑定:
package com.sun.jndi.examples.basics;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.naming.spi.ObjectFactory;
/**
* Demonstrates how to add a binding to a context. (Use Rebind example to
* overwrite binding; use Unbind to remove binding.)
*
* usage: java Bind
*/
public class Bind {
public static void main(String[] args) {
// Set up the environment for creating the initial context
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:/tmp/tutorial");
try {
// Create the initial context
Context ctx = new InitialContext(env);
// Create the object to be bound
Fruit fruit = new Fruit("orange");
// Perform the bind
ctx.bind("favorite", fruit);
// Check that it is bound
Object obj = ctx.lookup("favorite");
System.out.println(obj);
// Close the context when we're done
ctx.close();
} catch (NamingException e) {
System.out.println("Operation failed: " + e);
}
}
}
class Fruit implements Referenceable {
String fruit;
public Fruit(String f) {
fruit = f;
}
public Reference getReference() throws NamingException {
return new Reference(Fruit.class.getName(), new StringRefAddr("fruit",
fruit), FruitFactory.class.getName(), null); // factory
// location
}
public String toString() {
return fruit;
}
}
public class FruitFactory implements ObjectFactory {
public FruitFactory() {
}
public Object getObjectInstance(Object obj, Name name, Context ctx,
Hashtable env) throws Exception {
if (obj instanceof Reference) {
Reference ref = (Reference) obj;
if (ref.getClassName().equals(Fruit.class.getName())) {
RefAddr addr = ref.get("fruit");
if (addr != null) {
return new Fruit((String) addr.getContent());
}
}
}
return null;
}
}
(注:本例中的三个类都是public类型的类,但是为了代码的简洁,笔者将其都写在了一个类中,并将Fruit类和FruitFactory类定义为了friendly类型的类,但是执行的时候抛出了异常,信息如下:
Operation failed: javax.naming.NamingException: unexpected exception [Root exception is java.lang.IllegalAccessException: Class javax.naming.spi.NamingManager can not access a member of class com.sun.jndi.examples.basics.FruitFactory with modifiers "public"]; remaining name 'favorite'
在ObjectFactory的类说明中有如下的说明:An object factory must implement the ObjectFactory interface. In addition, the factory class must be public and must have a public constructor that accepts no parameters.
所以必须将FruitFactory类定义为public类型的类,并且提供一个public的无参构造方法。而Fruit类没有这个限制)
上述例子创建了一个Fruit类的对象,然后将其和名称”favorite”进行绑定。如果接着执行检索favorite名称,那么将返回fruit对象。在编译Fruit类的时候,需要使用FruitFactory类。如果执行例子两次的时候,将会抛出异常,异常为NameAlreadyBoundException。这是由于favorite已经被绑定。为了使再次绑定成功,需要使用rebind()方法。或者先移除再重新绑定。
添加或者替换绑定
rebind()方法用来添加或者替换一个存在的绑定。它接受和bind()方法相同的参数。但是执行的顺序是如果绑定存在的话,就先解除绑定,然后绑定到指定的新的对象。
Fruit fruit = new Fruit("lemon");
// Perform the bind
ctx.rebind("favorite", fruit);
// Check that it is bound
Object obj = ctx.lookup("favorite");
System.out.println(obj);
此时无论程序执行几次,都会打印出lemon作为结果。
执行完上述程序后,在D:\workspace\JNDITutorial\tmp\tutorial中生成.bindings文件,内容如下:
#This file is used by the JNDI FSContext.
#Tue Dec 04 15:47:06 JST 2007
favorite/RefAddr/0/Type=fruit
favorite/RefAddr/0/Content=lemon
favorite/FactoryName=com.sun.jndi.examples.basics.FruitFactory
favorite/RefAddr/0/Encoding=String
favorite/ClassName=com.sun.jndi.examples.basics.Fruit
移除绑定
通过使用unbind()方法移除绑定。
重命名对象
使用Context.rename()方法重命名对象:
// Rename to old_report.txt
ctx.rename("report.txt", "old_report.txt");
上面的代码将绑定到report.txt的对象绑定到old_report.txt。
创建和销毁上下文
Context接口提供了创建或者销毁子上下文的接口,一个上下文可以被绑定到相同类型的其他上下文。对应到文件系统的话,也就是可以创建或者删除一个子目录。
创建上下文
通过传递上下文的名称给createSubcontext()方法来创建子上下文:
// Create the context
Context result=ctx.createSubcontext(“new”);
执行示例程序后,会在tuitorial目录下创建新的目录new。
销毁上下文
通过调用destroySubcontext()方法来销毁参数指定的上下文。
// Destroy the context
ctx.destroySubcontext(“new”);
结合创建和删除上下文,代码如下:
Context ctx = new InitialContext(env);
try {
ctx.lookup("new");
System.out.println("destroying context new...");
ctx.destroySubcontext("new");
} catch (NameNotFoundException e) {
}
// Create the context
System.out.println("creating context new...");
Context result = ctx.createSubcontext("new");
// Check that it was created by listing its parent
Context newCtx = (Context) ctx.lookup("new");
System.out
.println("the new context:" + newCtx.getNameInNamespace());
// Close the context when we're done
ctx.close();
连续执行两次,结果如下:
creating context new...
the new context:d:\workspace\JNDITutorial\tmp\tutorial\new
destroying context new...
creating context new...
the new context:d:\workspace\JNDITutorial\tmp\tutorial\new
JNDI Tutorial系列文章的第二部分:The Basics,介绍了JNDI的一些基础知识,诸如Naming操作和Directory操作。介绍了如何通过编程的方式访问命名和目录服务,如何使用JNDI和目录进行交互。从准备环境到查找对象以及在目录中进行搜索等操作。
本部分主要介绍了关于命名的一些操作(Naming Operations)
前提条件:创建命名操作所需的文件系统环境,通过执行Setup类进行初始化,设置根路径为d:/workspace/JNDITutorial/tmp/tutorial/。
可以通过使用JNDI来进行命名操作,例如读操作和更新名称空间操作。本部分内容中将主要介绍以下操作:
* Looking up an object
* Listing the contents of a context
* Adding, overwriting, and removing a binding
* Renaming an object
* Creating and destroying subcontexts
在这些例子中使用下面的环境属性初始化initial context:
// Set up environment for creating the initial context
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:d:/workspace/JNDITutorial/tmp/tutorial");
Context ctx = new InitialContext(env);
查找对象:
使用Context.lookup()方法来从命名服务中查找对象,需要将对象的名字作为参数传递给lookup方法。假设在命名服务中有一个叫做report.txt的对象,那么获取这个对象的代码为:
Object obj=ctx.lookup(“report.txt”);
lookup()方法返回的对象的类型由命名系统和对象自身关联的数据决定。一个命名系统可能包含多种不同类型的对象,并且根据对象在命名系统的位置的不同也会导致对象类型的不同。在本例中,”report.txt”绑定到一个java.io.File对象,可以进行强制类型转换。下面是查找操作的源代码:
import java.io.File;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
/**
* Demonstrates how to look up an object.
*
* usage: java Lookup
*/
class Lookup {
public static void main(String[] args) {
// Set up the environment for creating the initial context
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL,
"file:d:/workspace/JNDITutorial/tmp/tutorial");
try {
// Create the initial context
Context ctx = new InitialContext(env);
// Perform lookup and cast to target type
File f = (File) ctx.lookup("report.txt");
System.out.println(f);
// Close the context when we're done
ctx.close();
} catch (NamingException e) {
System.out.println("Lookup failed: " + e);
}
}
}
输出结果为:
d:\workspace\JNDITutorial\tmp\tutorial\report.txt
(注:需要将service provider的jar包加入到classpath中,文件为fscontext.jar和providerutil.jar)
(注:不能够将file:d:/workspace/JNDITutorial/tmp/tutorial中的file:去掉,因为第一个冒号前面的字符串为协议,冒号和d之间可以加多个”/”)
枚举上下文:
和调用Context.lookup()方法每次获取一个对象不同的是,使用Context.list()方法可以获取一个名称-对象枚举,Context.listBindings()方法可以返回一个所有的绑定。
Context.list()方法
Context.list()方法返回一个NameClassPair的美剧。每个NameClassPair由对象名和其所属的类名组成。下面的代码片断列出了awt目录下的内容(文件和目录):
NamingEnumeration list = ctx.list("awt");
// Go through each item in list
while (list.hasMore()) {
NameClassPair nc = (NameClassPair) list.next();
System.out.println(nc);
}
运行上面例子的结果如下:
accessibility: javax.naming.Context
......
swing: javax.naming.Context
(它只列举出awt目录下面的直接目录或者文件。)
Context.listBindings()方法
Context.listBindings()方法返回一个绑定的枚举。Binding类似NameClassPair的子类。一个绑定不仅仅包好对象名和类名,还包含对象本身。下面的代码列举出awt上下文中的所有绑定并打印:
NamingEnumeration bindings = ctx.listBindings("awt");
// Go through each item in list
while (bindings.hasMore()) {
Binding bd = (Binding) bindings.next();
System.out.println(bd.getName() + ": " + bd.getObject());
}
输出结果如下:
accessibility: com.sun.jndi.fscontext.RefFSContext@1cf8583
......
swing: com.sun.jndi.fscontext.RefFSContext@dbe178
终止NamingEnumeration
一个NamingEnumeration可以有三种终止方式:自然终止、显式终止和异常终止。
¨ 当NamingEnumeration.hasMore()方法返回false的时候,枚举已经完成,所以终止。
¨ 可以在枚举完成之前显式的终止它,通过调用NamingEnumeration.close()方法。
¨ 如果hasMore()方法或者next()方法抛出NamingException时,枚举终止。
无论以哪种方式终止NamingEnumeration,一旦终止后,就不能再被使用。调用已经终止的枚举对象会返回一个未定义的结果。
为什么有两种不同的列举方法
list()方法的目的是提供给浏览器风格的应用程序,这些应用程序只希望显示上下文中的对象的名称。例如一个浏览器可能只希望列出上下文中的名字供用户选择以便执行更进一步的操作,这样的应用程序一般不需要访问上下文中的所有对象。
listBindings()方法的目的是提供给应用程序,这些应用程序对上下文中的对象进行操作。例如,一个备份应用程序可能需要对一个文件目录中的所有对象执行”file stats”操作。又或者一个打印机管理程序可能希望重启整个大厦中的所有打印机。为了执行这些操作,应用程序需要获取上下文中绑定的所有对性。所以这个时候需要将对象本身作为结果返回。但是使用listBindings()方法的开销要比list()的大。
添加、替换和移除绑定
Context接口包含添加、替换和删除绑定的方法。
添加绑定
Context.bind()方法用于向上下文中添加一个绑定,它接受绑定的名字和要绑定的对象作为参数。
下面的例子演示了将一个Fruit对象和favoriate名字进行绑定:
package com.sun.jndi.examples.basics;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.naming.spi.ObjectFactory;
/**
* Demonstrates how to add a binding to a context. (Use Rebind example to
* overwrite binding; use Unbind to remove binding.)
*
* usage: java Bind
*/
public class Bind {
public static void main(String[] args) {
// Set up the environment for creating the initial context
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:/tmp/tutorial");
try {
// Create the initial context
Context ctx = new InitialContext(env);
// Create the object to be bound
Fruit fruit = new Fruit("orange");
// Perform the bind
ctx.bind("favorite", fruit);
// Check that it is bound
Object obj = ctx.lookup("favorite");
System.out.println(obj);
// Close the context when we're done
ctx.close();
} catch (NamingException e) {
System.out.println("Operation failed: " + e);
}
}
}
class Fruit implements Referenceable {
String fruit;
public Fruit(String f) {
fruit = f;
}
public Reference getReference() throws NamingException {
return new Reference(Fruit.class.getName(), new StringRefAddr("fruit",
fruit), FruitFactory.class.getName(), null); // factory
// location
}
public String toString() {
return fruit;
}
}
public class FruitFactory implements ObjectFactory {
public FruitFactory() {
}
public Object getObjectInstance(Object obj, Name name, Context ctx,
Hashtable env) throws Exception {
if (obj instanceof Reference) {
Reference ref = (Reference) obj;
if (ref.getClassName().equals(Fruit.class.getName())) {
RefAddr addr = ref.get("fruit");
if (addr != null) {
return new Fruit((String) addr.getContent());
}
}
}
return null;
}
}
(注:本例中的三个类都是public类型的类,但是为了代码的简洁,笔者将其都写在了一个类中,并将Fruit类和FruitFactory类定义为了friendly类型的类,但是执行的时候抛出了异常,信息如下:
Operation failed: javax.naming.NamingException: unexpected exception [Root exception is java.lang.IllegalAccessException: Class javax.naming.spi.NamingManager can not access a member of class com.sun.jndi.examples.basics.FruitFactory with modifiers "public"]; remaining name 'favorite'
在ObjectFactory的类说明中有如下的说明:An object factory must implement the ObjectFactory interface. In addition, the factory class must be public and must have a public constructor that accepts no parameters.
所以必须将FruitFactory类定义为public类型的类,并且提供一个public的无参构造方法。而Fruit类没有这个限制)
上述例子创建了一个Fruit类的对象,然后将其和名称”favorite”进行绑定。如果接着执行检索favorite名称,那么将返回fruit对象。在编译Fruit类的时候,需要使用FruitFactory类。如果执行例子两次的时候,将会抛出异常,异常为NameAlreadyBoundException。这是由于favorite已经被绑定。为了使再次绑定成功,需要使用rebind()方法。或者先移除再重新绑定。
添加或者替换绑定
rebind()方法用来添加或者替换一个存在的绑定。它接受和bind()方法相同的参数。但是执行的顺序是如果绑定存在的话,就先解除绑定,然后绑定到指定的新的对象。
Fruit fruit = new Fruit("lemon");
// Perform the bind
ctx.rebind("favorite", fruit);
// Check that it is bound
Object obj = ctx.lookup("favorite");
System.out.println(obj);
此时无论程序执行几次,都会打印出lemon作为结果。
执行完上述程序后,在D:\workspace\JNDITutorial\tmp\tutorial中生成.bindings文件,内容如下:
#This file is used by the JNDI FSContext.
#Tue Dec 04 15:47:06 JST 2007
favorite/RefAddr/0/Type=fruit
favorite/RefAddr/0/Content=lemon
favorite/FactoryName=com.sun.jndi.examples.basics.FruitFactory
favorite/RefAddr/0/Encoding=String
favorite/ClassName=com.sun.jndi.examples.basics.Fruit
移除绑定
通过使用unbind()方法移除绑定。
重命名对象
使用Context.rename()方法重命名对象:
// Rename to old_report.txt
ctx.rename("report.txt", "old_report.txt");
上面的代码将绑定到report.txt的对象绑定到old_report.txt。
创建和销毁上下文
Context接口提供了创建或者销毁子上下文的接口,一个上下文可以被绑定到相同类型的其他上下文。对应到文件系统的话,也就是可以创建或者删除一个子目录。
创建上下文
通过传递上下文的名称给createSubcontext()方法来创建子上下文:
// Create the context
Context result=ctx.createSubcontext(“new”);
执行示例程序后,会在tuitorial目录下创建新的目录new。
销毁上下文
通过调用destroySubcontext()方法来销毁参数指定的上下文。
// Destroy the context
ctx.destroySubcontext(“new”);
结合创建和删除上下文,代码如下:
Context ctx = new InitialContext(env);
try {
ctx.lookup("new");
System.out.println("destroying context new...");
ctx.destroySubcontext("new");
} catch (NameNotFoundException e) {
}
// Create the context
System.out.println("creating context new...");
Context result = ctx.createSubcontext("new");
// Check that it was created by listing its parent
Context newCtx = (Context) ctx.lookup("new");
System.out
.println("the new context:" + newCtx.getNameInNamespace());
// Close the context when we're done
ctx.close();
连续执行两次,结果如下:
creating context new...
the new context:d:\workspace\JNDITutorial\tmp\tutorial\new
destroying context new...
creating context new...
the new context:d:\workspace\JNDITutorial\tmp\tutorial\new
From:一号门
Previous:js找到当前对象的前一个元素,后一个元素
COMMENTS