本文主要是介绍JNDI 命名和目录操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Naming and Directory Operations
原文地址: https://docs.oracle.com/javase/tutorial/jndi/TOC.html
你可以使用JNDI进行命名操作,包括读和更新操作命名空间。在本文中描述了以下操作:
- 查找对象
- 列出Context的内容
- 添加,覆盖,去除绑定
- 重命名对象
- 创建和销毁subcontext
配置
在进行任何操作的命名或目录服务之前,您需要先获取inital Context,即开始进入命名空间的起始点。这是因为所有的命名和目录服务的方法都是在某些Context中进行的。要获得inital Context,您必须遵循以下步骤。
- 选择要访问的相应服务的服务提供程序
- 指定inital Context需要的配置。
- 调用InitialContext构造函数
第一步:选择inital Context的服务供应商
您可以通过指定一组 environment properties (Hashtable类型)集合为服务提供商创建inital Context,或者向inital Context添加服务提供程序类的名称
.这个链接提供environment properties 详细的使用教程.https://docs.oracle.com/javase/jndi/tutorial/beyond/env/index.html
如果您使用的是包含在JDK的LDAP服务提供商,那么你的代码如下所示:
Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
在JDK中指定文件系统服务提供商,那么你的代码如下所示:
Hashtable<String, Object> env = new Hashtable>String, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.fscontext.RefFSContextFactory");
您还可以使用系统属性指定服务提供给程序使用:
https://docs.oracle.com/javase/jndi/tutorial/beyond/index.html
第二步:提供inital Context所需要的信息
不同目录的客户端可能需要不同的信息来联系目录。例如,您可能需要指明那个正在运行的服务器,以及需要什么样的信息来识别用户到该目录。这样的信息通过 environment properties传递给服务提供商. JNDI指定一些通用的 environment properties让服务提供商使用.您的服务提供程序文档将提供有关这些属性的详细信息。
LDAP提供程序要求程序指定LDAP服务器的位置,以及用户身份信息。要提供此信息,您可以编写如下代码:
env.put(Context.PROVIDER_URL, "ldap://ldap.wiz.com:389");
env.put(Context.SECURITY_PRINCIPAL, "joeuser");
env.put(Context.SECURITY_CREDENTIALS, "joepassword");
下面示例使用的LDAP服务提供者在JDK。这个例子假设服务器已经启动并使用了本地机器上的端口389与用户名字”o=JNDITutorial”.这是更新目录不需要认证。它们包括下列代码以建立环境
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");
如果您正在使用一个设置不同的目录,那么您就需要相应地设置这些环境属性。你将需要更换机器名”localhost”,您可以运行这些示例在任何非公共目录服务器或您自己的服务器上。你将需要更换机器名”localhost”和用户名o=JNDITutorial。
第三步:创建inital Context
您现在已经准备好创建inital Context。这样做,将先前创建的环境属性提供给InitialContext构造函数:
Context ctx = new InitialContext(env);
现在,您有一个Context 对象的引用,您可以开始访问命名服务。
执行目录操作,你需要使用一个InitialDirContext。要做到这一点,需使用它的构造函数:
DirContext ctx = new InitialDirContext(env);
这个语句返回一个可执行目录操作的DirContext引用对象。
命名异常
当需要的请求操作无法执行时,很多在JNDI包中的方法都有抛出NamingException。通常,你会看到一个try/catch代码块,或者抛出一个NamingException:
try {Context ctx = new InitialContext();Object obj = ctx.lookup("somename");
} catch (NamingException e) {// Handle the errorSystem.err.println(e);
}
异常类的层次结构
JNDI具有丰富的异常层次结构,所有异常都有一个共同的基类:NamingException .
下面是一个使用子类AuthenticationException的例子:
try {Context ctx = new InitialContext();Object obj = ctx.lookup("somename");
} catch (AuthenticationException e) {// attempt to reacquire the authentication information...
} catch (NamingException e) {// Handle the errorSystem.err.println(e);
}
枚举
例如Context.list() 和DirContext.search()都会返回一个NamingEnumeration.在这种情况下,如果发生了一个错误,不返回任何结果,这时NamingException 或其相应的子类将被抛出.
如果出现错误,但也有一些结果会被返回,返回一个NamingEnumeration 以便你能得到这些结果。当所有的结果都用完后,调用NamingEnumeration.hasMore()会造成NamingException (或它的一个子类)被抛出。在这点上,枚举无效,并且没有其他方法能被调用。
例如,如果你执行一个search()并指定一个数(N)限制返回多少个结果集,那么search()将返回一个包含最多N结果的结果集。如果结果数超过N,然后NamingEnumeration.hasMore()为n + 1次调用时,会抛出一个SizeLimitExceededException 。
所有的异常说明可以在这里找到:
https://docs.oracle.com/javase/8/docs/api/javax/naming/package-summary.html
查找对象
通过您要检索的对象的名称,使用 Context.lookup()查找命名服务中的对象。假设有一个对象命名服务中的名称:cn=Rosanna Lee,ou=People。要检索该对象,您将写
Object obj = ctx.lookup("cn=Rosanna Lee,ou=People");
lookup()返回的目标类型取决于底层的命名系统和对象本身相关的数据。一个命名系统可以包含许多不同类型的对象,并且在系统的不同部分中查找对象可能会产生不同类型的对象。在上面的例子中, “cn=Rosanna Lee,ou=People”恰好是绑定到Context的对象((javax.naming.ldap.LdapContext)。你可以用lookup()找到目标类:
例如,下面的代码查找对象 “cn=Rosanna Lee,ou=People”,并转换为LdapContext。
import javax.naming.ldap.LdapContext;
...
LdapContext ctx = (LdapContext) ctx.lookup("cn=Rosanna Lee,ou=People");
完整的示例文件在lookup.java:
https://docs.oracle.com/javase/tutorial/jndi/ops/examples/Lookup.java
这里有2个新的静态方法可查找一个名字在Java SE 6中:
InitialContext.doLookup(Name name)
InitialContext.doLookup(String name)
这些方法提供了一个寻找无需实例化的InitialContext的快捷方式
列出Context的内容
如果不使用Context.lookup()一次得到一个单一的对象,你可以通过使用一个单一的操作列出Context的内容。有两种方法用于列出Context:一个是返回绑定的方法,一个返回name-to-object 类。
- Context.List()
返回一个NameClassPair枚举,每个NameClassPair包含对象名和类名,下面的代码片段列出了”ou=People”目录的内容(即在”ou=People”目录中找到的相应的文件和目录)。
NamingEnumeration list = ctx.list("ou=People");while (list.hasMore()) {NameClassPair nc = (NameClassPair)list.next();System.out.println(nc);
}
运行这个例子产生以下输出:
# java List
cn=Jon Ruiz: javax.naming.directory.DirContext
cn=Scott Seligman: javax.naming.directory.DirContext
cn=Samuel Clemens: javax.naming.directory.DirContext
cn=Rosanna Lee: javax.naming.directory.DirContext
cn=Maxine Erlund: javax.naming.directory.DirContext
cn=Niels Bohr: javax.naming.directory.DirContext
cn=Uri Geller: javax.naming.directory.DirContext
cn=Colleen Sullivan: javax.naming.directory.DirContext
cn=Vinnie Ryan: javax.naming.directory.DirContext
cn=Rod Serling: javax.naming.directory.DirContext
cn=Jonathan Wood: javax.naming.directory.DirContext
cn=Aravindan Ranganathan: javax.naming.directory.DirContext
cn=Ian Anderson: javax.naming.directory.DirContext
cn=Lao Tzu: javax.naming.directory.DirContext
cn=Don Knuth: javax.naming.directory.DirContext
cn=Roger Waters: javax.naming.directory.DirContext
cn=Ben Dubin: javax.naming.directory.DirContext
cn=Spuds Mackenzie: javax.naming.directory.DirContext
cn=John Fowler: javax.naming.directory.DirContext
cn=Londo Mollari: javax.naming.directory.DirContext
cn=Ted Geisel: javax.naming.directory.DirContext
- Context.listBindings()
返回一个Binding枚举,Binding是一个NameClassPair的子类.Binding包含对象的名称和类名称,但也包含对象本身。下面的代码列举”ou=People”的Context,打印出每个绑定的名称和对象。
NamingEnumeration bindings = ctx.listBindings("ou=People");while (bindings.hasMore()) {Binding bd = (Binding)bindings.next();System.out.println(bd.getName() + ": " + bd.getObject());
}
运行这个例子产生以下输出:
# java ListBindings
cn=Jon Ruiz: com.sun.jndi.ldap.LdapCtx@1d4c61c
cn=Scott Seligman: com.sun.jndi.ldap.LdapCtx@1a626f
cn=Samuel Clemens: com.sun.jndi.ldap.LdapCtx@34a1fc
cn=Rosanna Lee: com.sun.jndi.ldap.LdapCtx@176c74b
cn=Maxine Erlund: com.sun.jndi.ldap.LdapCtx@11b9fb1
cn=Niels Bohr: com.sun.jndi.ldap.LdapCtx@913fe2
cn=Uri Geller: com.sun.jndi.ldap.LdapCtx@12558d6
cn=Colleen Sullivan: com.sun.jndi.ldap.LdapCtx@eb7859
cn=Vinnie Ryan: com.sun.jndi.ldap.LdapCtx@12a54f9
cn=Rod Serling: com.sun.jndi.ldap.LdapCtx@30e280
cn=Jonathan Wood: com.sun.jndi.ldap.LdapCtx@16672d6
cn=Aravindan Ranganathan: com.sun.jndi.ldap.LdapCtx@fd54d6
cn=Ian Anderson: com.sun.jndi.ldap.LdapCtx@1415de6
cn=Lao Tzu: com.sun.jndi.ldap.LdapCtx@7bd9f2
cn=Don Knuth: com.sun.jndi.ldap.LdapCtx@121cc40
cn=Roger Waters: com.sun.jndi.ldap.LdapCtx@443226
cn=Ben Dubin: com.sun.jndi.ldap.LdapCtx@1386000
cn=Spuds Mackenzie: com.sun.jndi.ldap.LdapCtx@26d4f1
cn=John Fowler: com.sun.jndi.ldap.LdapCtx@1662dc8
cn=Londo Mollari: com.sun.jndi.ldap.LdapCtx@147c5fc
cn=Ted Geisel: com.sun.jndi.ldap.LdapCtx@3eca90
终止一个NamingEnumeration
一个NamingEnumeration可以有三种方式:自然终止,明确,或意外。
- 当 NamingEnumeration.hasMore()返回false,枚举是完整和有效的终止。
- 你可以明确终止枚举通过调用 NamingEnumeration.close()。这样做为底层实现提供一个提示,以释放与枚举相关联的任何资源。
- 如果 hasMore()或next()抛出一个NamingException,然后枚举有效终止。
为什么有两个不同的列表方法?
list()用于浏览模式的应用程序,只想在一个Context中显示对象的名称。例如,一个浏览器先用Context列出名称,并等待用户选择一个或几个然后显示执行进一步操作的名称。这样的应用程序通常不需要在Context中访问所有的对象。
listbindings()用于需要对Context的全体对象执行操作的应用程序。例如,备份应用程序可能需要在文件目录中的所有对象上执行“文件统计”操作。或者打印机管理程序可能要重新启动一个项目的所有打印机。要执行这样的操作,这些应用程序需要获得在Context中的所有对象。因此,返回对象作为枚举的一部分是更加有利.
应用程序可以使用list()或更昂贵的listBindings(),应根据信息类型的需要.
添加,替换或删除绑定
Context接口包含用于Context的添加、替换和删除绑定的方法
- 添加绑定
Context.bind() 用于添加一个绑定到Context中,它接受被绑定的对象名称和对象作为参数.
// 创建需要绑定的对象
Fruit fruit = new Fruit("orange");// 执行绑定
ctx.bind("cn=Favorite Fruit", fruit);
此示例创建一个水果类的对象并将它绑定到”cn=Favorite Fruit”到名为ctx的Context中。如果你随后用ctx的lookup名为:”cn=Favorite Fruit”,然后你会得到fruit 对象。
如果你运行这个例子两次,然后将抛出异常:NameAlreadyBoundException。这是因为这个名字”cn=Favorite Fruit”已经被绑定了。对于尝试第二次成功,你将不得不使用rebind()。
添加或替换绑定:
rebind()用于添加或替换绑定。它接受和bind()相同的参数,但语义是这样的,如果是已经绑定,那么它将会绑定新的对象。
// Create the object to be bound
Fruit fruit = new Fruit("lemon");// Perform the bind
ctx.rebind("cn=Favorite Fruit", fruit);
当你运行这个例子,它将取代bind()例子创建的对象
移除绑定
移除绑定使用unbind().
// Remove the binding
ctx.unbind("cn=Favorite Fruit");
下面是三个完整的例子:
https://docs.oracle.com/javase/tutorial/jndi/ops/examples/Rebind.java
https://docs.oracle.com/javase/tutorial/jndi/ops/examples/Bind.java
https://docs.oracle.com/javase/tutorial/jndi/ops/examples/Unbind.java
重命名
你可以通过 Context.rename()重命名Context中的对象
// Rename to Scott S
ctx.rename("cn=Scott Seligman", "cn=Scott S");
这个例子重命名对象被绑定到”cn=Scott Seligman”到”cn=Scott S”如下:
// Rename back to Scott Seligman
ctx.rename("cn=Scott S", "cn=Scott Seligman");
创建和销毁subcontext
Context接口包含用于创建和销毁subcontext的方法,一个context必然和另一context 为同一类型.
这里介绍的例子使用一个有属性的对象和创建subcontext到目录中。你可以使用DirContext 关联属相到对象中,同时增加binding和subcontext到命名空间。例如,您可以创建一个对象,并将其绑定到名称空间,并在同一时间关联该对象的属性。这样命名等价没有属性。
createsubcontext()会创建一个新的对象,DirContext.createSubcontext()创建一个子对象,需要指定属性和context
创建一个Context
创建一个Context,你提供给createsubcontext()Context的名称。 createsubcontext()名称的情况下,你想创建及其属性。
// Create attributes to be associated with the new context
Attributes attrs = new BasicAttributes(true); // case-ignore
Attribute objclass = new BasicAttribute("objectclass");
objclass.add("top");
objclass.add("organizationalUnit");
attrs.put(objclass);// Create the context
Context result = ctx.createSubcontext("NewOu", attrs);
此示例创建一个新的语境中被称为”ou=NewOu” 有一个属性”objectclass”的两个值,”top”和 “organizationalUnit”,在CTX的Context。
# java Create
ou=Groups: javax.naming.directory.DirContext
ou=People: javax.naming.directory.DirContext
ou=NewOu: javax.naming.directory.DirContext
此示例创建一个新的背景下,被称为”NewOu”,那是一个CTX的子Context。
销毁Context
销毁Context,你提供给destroysubcontext()Context的名称来摧毁。
// Destroy the context
ctx.destroySubcontext("NewOu");
这是销毁Context的完整代码:
https://docs.oracle.com/javase/tutorial/jndi/ops/examples/Destroy.java
这篇关于JNDI 命名和目录操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!