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 providerjar包加入到classpath中,文件爲fscontext.jarproviderutil.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
  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章