Sun JNDI教程翻译 第二部分 Naming Operations

本文是 JNDI Tutorial 系列文章的第二部分: The Basics ,介绍了 JNDI 的一些基础知识,诸如 Naming 操作和 Directory 操作。介绍了如何通过编程的方式访问命名和目录服务,如何使用 JNDI 和目录进行交互。从准备环境到查找对象以及在目录中进行搜索等操作。
本部分主要介绍了关于命名的一些操作 (Naming Operations)
前提条件:创建命名操作所需的文件系统环境,通过执行 Setup 类进行初始化,设置根路径为 d:/workspace/JNDITutorial/tmp/tutorial/
可以通过使用 JNDI 来进行命名操作,例如读操作和更新名称空间操作。本部分内容中将主要介绍以下操作:
在这些例子中使用下面的环境属性初始化 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
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值