jndi step by step(2)(轉http://www.cnblogs.com/aurawing/articles/1887036.html)

jndi step by step(2)

(4) 目錄服務操作

1、目錄服務的操作

    我們會用LDAP作爲例子來講解目錄服務的操作。與命名服務不同,目錄服務的內容上下文的初始化方式需要
    改變:

java 代碼
  1. // Set up the environment for creating the initial context   
  2. Hashtable env = new Hashtable();   
  3. env.put(Context.INITIAL_CONTEXT_FACTORY,    
  4.     "com.sun.jndi.ldap.LdapCtxFactory");   
  5. env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");   
  6. DirContext ctx = new InitialDirContext(env);  

 

    1.1、如何讀取屬性

    你可以使用 DirContext.getAttributes() 方法來讀取一個對象的屬性,你需要給這個方法傳遞一個對象的
    名字作爲參數。例如一個對象在命名系統中的名字是“cn=Ted Geisel, ou=People”,那麼我們可以使用如下
    的代碼得到它的屬性:

java 代碼
  1. Attributes answer = ctx.getAttributes("cn=Ted Geisel, ou=People");  

    你也可以輸出 “answer”來看看:

java 代碼
  1. for (NamingEnumeration ae = answer.getAll(); ae.hasMore();) {   
  2.     Attribute attr = (Attribute)ae.next();   
  3.     System.out.println("attribute: " + attr.getID());   
  4.     /* Print each value */  
  5.     for (NamingEnumeration e = attr.getAll(); e.hasMore();   
  6.      System.out.println("value: " + e.next()))   
  7.     ;   
  8. }  

    輸出結果是:

# java GetattrsAll
attribute: sn
value: Geisel
attribute: objectclass
value: top
value: person
value: organizationalPerson
value: inetOrgPerson
attribute: jpegphoto
value: [B@1dacd78b
attribute: mail
value: [email protected]
attribute: facsimiletelephonenumber
value: +1 408 555 2329
attribute: telephonenumber
value: +1 408 555 5252
attribute: cn
value: Ted Geisel

    1.1.1、返回需要的屬性

    有的時候我們只是需要得到一些屬性,而不是全部的屬性。這樣,你可以把屬性作爲一個數組,把這個數組
    作爲參數傳遞給那個方法。

java 代碼
  1. // Specify the ids of the attributes to return   
  2. String[] attrIDs = {"sn""telephonenumber""golfhandicap""mail"};   
  3.   
  4. // Get the attributes requested   
  5. Attributes answer = ctx.getAttributes("cn=Ted Geisel, ou=People", attrIDs);  

    假設我們這個例子裏的這個對象,擁有 "sn", "telephonenumber"和"mail"屬性,但是沒有“golfhandicap”
    屬性,那麼上面的代碼返回的結果就應該是:

# java Getattrs
attribute: sn
value: Geisel
attribute: mail
value: [email protected]
attribute: telephonenumber
value: +1 408 555 5252

    1.2、改變屬性

    DirContext 接口有一些改變對象屬性的方法。

    1.2.1、批量改變屬性
 
    改變屬性的方式之一就是批量改變屬性,也就是使用許多 ModificationItem 對象來修改屬性。
    每個 ModificationItem 對象都會有一個常量,來表示對屬性進行什麼樣的操作。這些常量如下:

ADD_ATTRIBUTE
REPLACE_ATTRIBUTE
REMOVE_ATTRIBUTE

    對屬性的改變會按照隊列的順序來執行,要麼所有的改變都生效,要麼都不生效。
    下面的代碼演示了一個例子。它把“mail”這個屬性的值,改變成了“[email protected]”,給“telephonenumber”
    屬性增加了一個值,並且刪除了“jpegphoto”屬性。

java 代碼
  1. // Specify the changes to make   
  2. ModificationItem[] mods = new ModificationItem[3];   
  3.   
  4. // Replace the "mail" attribute with a new value   
  5. mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,   
  6.     new BasicAttribute("mail""[email protected]"));   
  7.   
  8. // Add an additional value to "telephonenumber"   
  9. mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE,   
  10.     new BasicAttribute("telephonenumber""+1 555 555 5555"));   
  11.   
  12. // Remove the "jpegphoto" attribute   
  13. mods[2] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE,   
  14.     new BasicAttribute("jpegphoto"));  

    上面的代碼中,我們創建了一個修改屬性的 ModificationItem 對象的列表(其實就是一個數組),然後執行
    modifyAttributes() 方法來修改屬性。

java 代碼
  1. // Perform the requested modifications on the named object   
  2. ctx.modifyAttributes(name, mods);  

 

    1.2.2 只修改某幾個屬性

    你可以不使用上面的方式,而對屬性進行某一種操作:

java 代碼
  1. // Save original attributes   
  2. Attributes orig = ctx.getAttributes(name,    
  3. new String[]{"mail""telephonenumber""jpegphoto"});   
  4.   
  5. 。。。。 。。。   
  6.   
  7. // Revert changes   
  8. ctx.modifyAttributes(name, DirContext.REPLACE_ATTRIBUTE, orig);  

 

    1.3、在目錄服務中使用搜索功能

    1.3.1、基本的搜索功能
  
    最基本的搜索功能是可以指定一個對象的名字,和一些要搜索的屬性的名字。
    下面的代碼演示了這個功能。我們要進行這麼一個搜索:對象必須有“sn”屬性,而且數值必須是“Geisel”,
    而且必須有“mail”這個屬性。

 

java 代碼
  1. // Specify the attributes to match   
  2. // Ask for objects that has a surname ("sn") attribute with    
  3. // the value "Geisel" and the "mail" attribute   
  4. Attributes matchAttrs = new BasicAttributes(true); // ignore attribute name case   
  5. matchAttrs.put(new BasicAttribute("sn""Geisel"));   
  6. matchAttrs.put(new BasicAttribute("mail"));   
  7.   
  8. // Search for objects that have those matching attributes   
  9. NamingEnumeration answer = ctx.search("ou=People", matchAttrs);  

    你可以打印出這個結果:

java 代碼
  1. while (answer.hasMore()) {   
  2.     SearchResult sr = (SearchResult)answer.next();   
  3.     System.out.println(">>>" + sr.getName());   
  4.     printAttrs(sr.getAttributes());   
  5. }  

 

    輸出結果:

# java SearchRetAll
>>>cn=Ted Geisel
attribute: sn
value: Geisel
attribute: objectclass
value: top
value: person
value: organizationalPerson
value: inetOrgPerson
attribute: jpegphoto
value: [B@1dacd78b
attribute: mail
value: [email protected]
attribute: facsimiletelephonenumber
value: +1 408 555 2329
attribute: cn
value: Ted Geisel
attribute: telephonenumber
value: +1 408 555 5252

    1.3.2、返回指定的屬性

    上一個例子返回了滿足條件的全部屬性,當然你也可以只返回需要的屬性,這僅僅需要把需要返回的屬性,
    作爲一個數組參數傳遞給 search() 方法。

java 代碼
  1. // Specify the ids of the attributes to return   
  2. String[] attrIDs = {"sn""telephonenumber""golfhandicap""mail"};   
  3.   
  4. // Search for objects that have those matching attributes   
  5. NamingEnumeration answer = ctx.search("ou=People", matchAttrs, attrIDs);  

 

    1.4、搜索過濾

    在這裏,你可以學到一個高級點的搜索方式,就是在搜索中使用過濾。在搜索中實現過濾,我們需要使用
    表達式來實現這個功能。下面的這個表達式就表示搜索條件是:對象必須有“sn”屬性,而且數值必須是
    “Geisel”,而且必須有“mail”這個屬性:

(&(sn=Geisel)(mail=*))

    下面的例子告訴你如何使用表達式來搜索:

java 代碼
  1. // Create the default search controls   
  2. SearchControls ctls = new SearchControls();   
  3.   
  4. // Specify the search filter to match   
  5. // Ask for objects that have the attribute "sn" == "Geisel"   
  6. // and the "mail" attribute   
  7. String filter = "(&(sn=Geisel)(mail=*))";   
  8.   
  9. // Search for objects using the filter   
  10. NamingEnumeration answer = ctx.search("ou=People", filter, ctls);   

 

    下面這個列表有助你使用表達式:

       符號                   描述
        &       conjunction (i.e., and -- all in list must be true) 
        |       disjunction (i.e., or -- one or more alternatives must be true) 
        !       negation (i.e., not -- the item being negated must not be true) 
        =       equality (according to the matching rule of the attribute) 
        ~=      approximate equality (according to the matching rule of the attribute) 
        >=      greater than (according to the matching rule of the attribute) 
        <=      less than (according to the matching rule of the attribute) 
        =*      presence (i.e., the entry must have the attribute but its value is irrelevant) 
        *       wildcard (indicates zero or more characters can occur in that position);
                used when specifying attribute values to match 
        /       escape (for escaping '*', '(', or ')' when they occur inside an attribute value) 

    表達式中的每一個項目,都必須使用屬性的名字,也可以使用屬性的數值。例如“sn=Geisel”意味着屬性
    “sn”的值爲“Geisel”,而 "mail=*" 意味着屬性 “mail” 必須存在,但是可以爲任意值。
    每一個項目必須是在括號中,例如 "(sn=Geisel)"。不同的括號間使用邏輯判斷符號來連接起來。
    例如 "(| (& (sn=Geisel) (mail=*)) (sn=L*))"。這表示 屬性中 sn 必須等於Geisel 並且有 mail 這個
    屬性 或者 有 sn 這個屬性。
    詳細的內容,請參考 http://www.ietf.org/rfc/rfc2254.txt


    當然了,你也可以只返回指定的屬性,而不是全部的屬性。

java 代碼
     // Specify the ids of the attributes to return         String[] attrIDs = {"sn""telephonenumber""golfhandicap""mail"};         SearchControls ctls = new SearchControls();         ctls.setReturningAttributes(attrIDs);  

 

    1.5 搜索控制
   
    在上面的章節中,我們已經看到了一個類:SearchControls,通過這個類,你可以控制搜索的行爲。這裏
    我們就來仔細地看看這個類。
 
    1.5.1 搜索範圍

    SearchControls 類默認會在整個內容上下文(SearchControls.ONELEVEL_SCOPE)搜索對象,通過設置,你
    可以在某一個範圍內搜索對象。

    1.5.1.1 在一個子樹上搜索

    通過下面的代碼你可以清晰地瞭解這一功能:

java 代碼
     // Specify the ids of the attributes to return         String[] attrIDs = {"sn""telephonenumber""golfhandicap""mail"};         SearchControls ctls = new SearchControls();         ctls.setReturningAttributes(attrIDs);         ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);                 // Specify the search filter to match         // Ask for objects that have the attribute "sn" == "Geisel"         // and the "mail" attribute         String filter = "(&(sn=Geisel)(mail=*))";                 // Search the subtree for objects by using the filter         NamingEnumeration answer = ctx.search("", filter, ctls);  

 

    1.5.1.2 根據名字來搜索

    通過下面的代碼你可以清晰地瞭解這一功能:

java 代碼
     // Specify the ids of the attributes to return         String[] attrIDs = {"sn""telephonenumber""golfhandicap""mail"};         SearchControls ctls = new SearchControls();         ctls.setReturningAttributes(attrIDs);         ctls.setSearchScope(SearchControls.OBJECT_SCOPE);                 // Specify the search filter to match         // Ask for objects that have the attribute "sn" == "Geisel"         // and the "mail" attribute         String filter = "(&(sn=Geisel)(mail=*))";                 // Search the subtree for objects by using the filter         NamingEnumeration answer =              ctx.search("cn=Ted Geisel, ou=People", filter, ctls);  

 

    1.5.2 數量的限制

    通過下面的代碼你可以控制返回結果的數量:

java 代碼
     // Set the search controls to limit the count to 1         SearchControls ctls = new SearchControls();         ctls.setCountLimit(1);  

 

    1.5.3 時間的限制

    如果一個搜索耗費了很長的時間,那可不是一個好方法。這裏你可以設置超時的時間。

java 代碼
     // Set the search controls to limit the time to 1 second (1000 ms)         SearchControls ctls = new SearchControls();         ctls.setTimeLimit(1000);  

 

    參數的單位是毫秒。

    如果發生超時現象,那麼就會拋出 TimeLimitExceededException。

    1.6 結合命名服務和目錄服務的操作

    我們已經這樣的一個概念,就是目錄服務是命名服務的一個擴展。例如,之前我們說過命名服務具有 bind(),
    rebind(), createSubcontext() 等方法,但是在目錄服務裏卻沒有介紹這些方法。
    其實目錄服務裏也有這些方法。下面就用 LDAP 作爲例子,介紹一下這些方法。

    1.6.1 創建一個具有屬性的內容上下文

java 代碼
     import javax.naming.*;         import javax.naming.directory.*;         import java.util.Hashtable;                 /**          * Demonstrates how to create a new subcontext called "ou=Fruits" with some           * attributes.          * (Run Destroy after this to remove the subcontext).          *          * usage: java Create          */        class Create {             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.ldap.LdapCtxFactory");             env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");                     try {                 // Create the initial context                 DirContext ctx = new InitialDirContext(env);                         // 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("ou=Fruits", attrs);                         // Check that it was created by listing its parent                 NamingEnumeration list = ctx.list("");                         // Go through each item in list                 while (list.hasMore()) {                 NameClassPair nc = (NameClassPair)list.next();                 System.out.println(nc);                 }                         // Close the contexts when we're done                 result.close();                 ctx.close();             } catch (NamingException e) {                 System.out.println("Create failed: " + e);             }             }         }  

    1.6.2 增加一個具有屬性的綁定

java 代碼
     import javax.naming.*;         import javax.naming.directory.*;                 import java.util.Hashtable;                 /**          * Demonstrates how to add a binding and its attributes to a context.          * (Use Rebind example to overwrite binding; use Unbind to remove binding.)          *          * usage: java Bind          */                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.ldap.LdapCtxFactory");             env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");                     try {                 // Create the initial context                 DirContext ctx = new InitialDirContext(env);                         // Create object to be bound                 Fruit fruit = new Fruit("orange");                         // Create attributes to be associated with object                 Attributes attrs = new BasicAttributes(true); // case-ignore                 Attribute objclass = new BasicAttribute("objectclass");                 objclass.add("top");                 objclass.add("organizationalUnit");                 attrs.put(objclass);                         // Perform bind                 ctx.bind("ou=favorite, ou=Fruits", fruit, attrs);                         // Check that it is bound                 Object obj = ctx.lookup("ou=favorite, ou=Fruits");                 System.out.println(obj);                         // Get its attributes                 Attributes retattrs = ctx.getAttributes("ou=favorite, ou=Fruits");                 GetattrsAll.printAttrs(retattrs);                         // Close the context when we're done                 ctx.close();             } catch (NamingException e) {                 System.out.println("Operation failed: " + e);             }             }         }  

    1.6.3 替換一個具有屬性的綁定

java 代碼

    

 

(5) 高級應用之Name

1、jndi 高級應用之 Name

    1.1、什麼是 Name?
   
    這之前的文檔中,我們所用的例子裏,對象的名字都是 java.lang.String 類型的,也就是字符串類型。
    在這個文檔裏,我們則會介紹一些其他的對象名字類型,如 Name,以及他們的使用方法。
    我們首先會講講什麼是字符串的名字和結構化的名字,以及它們的存在的必要性。
    然後,我們會介紹2個結構化名字的類:(複合名字)composite 和 (混合名字)compound。
    最後,我們介紹如何在對象名字中使用特殊字符,以及如何解析和構成一個複雜的對象的名字。
   
    1.2、字符串名字 vs 結構化名字
   
    在 Context 和 DirContext 接口裏,每一個命名服務的方法都有2種方式,一個是接受字符串類型的名字,
    一個是接受結構化的名字(Name 類的對象)。例如:
   
lookup(java.lang.String)
lookup(javax.naming.Name)

    1.2.1、字符串名字
   
    使用字符串類型的名字,可以讓你不必再生成一個CompositeName類的對象。例如下面的代碼是相同的:

java 代碼
  1. Object obj1 = ctx.lookup("cn=Ted Geisel, ou=People, o=JNDITutorial");   
  2.   
  3. CompositeName cname = new CompositeName(   
  4.     "cn=Ted Geisel, ou=People, o=JNDITutorial");   
  5. Object obj2 = ctx.lookup(cname);  

 

    1.2.1、結構化的名字
   
    結構化的名字的對象可以是 CompositeName 或 CompoundName 類的對象,或者是任何一個實現了 “Name ”
    接口的類。
    如果是 CompositeName 類的實例,那麼就被認爲是一個複合的名字(composite name)。所謂的複合名字就
    是可以在一個名字裏使用多個命名服務系統,而不是僅僅一個。
    如果是 compound 類的實例,那麼就被認爲是混合的名字(compound name)。混合的名字只包含一個命名服務
    系統。
   
    1.2.2、那麼該使用哪種名字呢?
   
    一般來說,如果用戶可以提供字符串類型的名字,那麼就使用字符串類型的名字;可是如果用戶提供的是一
    個組合的名字,那麼就應該使用結構化的名字了。
    例如一個應用如果會涉及多個命名服務系統,那麼就應該使用結構化的名字了。
   
    1.3 複合名字(composite name)
   
    複合名字就是跨越多個命名系統的名字。例如:
   
cn=homedir,cn=Jon Ruiz,ou=People/tutorial/report.txt

    這個名字裏包含了兩個命名系統:一個 LDAP 系統 "cn=homedir,cn=Jon Ruiz,ou=People" 和一個文件系統
    "tutorial/report.txt"。當你把這個字符串傳遞給 Context 的 look 方法,那麼就會從 LDAP 系統裏查找
    那個文件,然後返回那個對象(一個文件對象的實例)。當然,這取決於特定的SPI。例如:

java 代碼
  1. File f = (File)ctx.lookup(   
  2.     "cn=homedir,cn=Jon Ruiz,ou=People/tutorial/report.txt");   

 

    1.3.1、字符串的表現形式
   
    我們可以這樣想像,一個複合的名字是由不同的“組件”組成的。所謂的“組件”,我們可以想象成是一個名字
    的一小部分,每一個組件表示一個命名服務系統。每一個組件都由正斜槓“/”分開。
    例如 :cn=homedir,cn=Jon Ruiz,ou=People/tutorial/report.txt
    包含三個組件:
   
cn=homedir,cn=Jon Ruiz,ou=People
tutorial
report.txt

    第一個組件屬於LDAP命名服務系統,第2和第3個組件屬於文件命名服務系統。正如我們從這個例子裏看到的,
    多個組件(tutorial 和 report.txt)可以屬於同一個命名服務系統,但是一個組件是不能跨越多個命名服務
    系統的。
   
    除了使用正斜槓“/”外,複合名字還允許使用其它三個特殊符號:反斜槓“/",單引號"'",雙引號" " "。
    這三個符號是內置的符號,也就是說他們三個具有特殊的用途。
   
    反斜槓“/”的作用是轉譯字符。反斜槓“/”之後的字符,會被認爲是普通字符。
    例如“a//b”,其中的“/”是不會被認爲是不同的命名服務系統的分隔符號。
   
    雙引號和單引號可以讓引號內的字符成爲普通字符,例如下面的用法都是一樣的:
   
a//b//c//d
"a/b/c/d"
'a/b/b/d'

    可見,有的時候使用引號還是很方便的。
   
    複合的名字也可以是空的,空的複合名字意味着沒有組件,一般用空的字符串表示。
   
    複合名字的組件也可以是空的,例如:
   
/abc
abc/
abc//xyz

    1.3.2、複合名字的類
   
    CompositeName 類是用來構成複合名字的類。你可以給它的構造函數傳遞一個複合名字的字符串。
    例如:

java 代碼
  1. import javax.naming.CompositeName;   
  2. import javax.naming.InvalidNameException;   
  3.   
  4. /**  
  5.   * Demonstrates how to construct a composite name given its  
  6.   * string representation  
  7.   *  
  8.   * usage: java ConstructComposite   
  9.   */  
  10. class ConstructComposite {   
  11.     public static void main(String[] args) {   
  12.     if (args.length != 1) {   
  13.         System.out.println("usage: java ConstructComposite <string></string>");   
  14.         System.exit(-1);   
  15.     }   
  16.     String name = args[0];   
  17.     try {   
  18.         CompositeName cn = new CompositeName(name);   
  19.         System.out.println(cn + " has " + cn.size() + " components: ");   
  20.         for (int i = 0; i < cn.size(); i++) {   
  21.         System.out.println(cn.get(i));   
  22.         }   
  23.     } catch (InvalidNameException e) {   
  24.         System.out.println("Cannot parse name: " + name);   
  25.     }   
  26.     }   
  27. }   

 

    運行這個例子,輸出的結果就是:
   
a/b/c has 3 components:
a
b
c

    CompositeName 類有許多方法,例如查看,修改,比較,以及得到一個複合名字的字符串表現形式。
   
    1.3.3、訪問複合名字裏的組件
   
    可以通過下列方法訪問復和名字裏的組件:
   
get(int posn)
getAll()
getPrefix(int posn)
getSuffix(int posn)
clone()

    如果你想得到特定位置的組件的名字,那麼使用 get(int posn) 方法就非常合適。
   
    getAll() 方法可以返回全部的組件的名字。
    例如:

java 代碼
  1. try {   
  2.     CompositeName cn = new CompositeName(name);   
  3.     System.out.println(cn + " has " + cn.size() + " components: ");   
  4.     for (Enumeration all = cn.getAll(); all.hasMoreElements();) {   
  5.     System.out.println(all.nextElement());   
  6.     }   
  7. catch (InvalidNameException e) {   
  8.     System.out.println("Cannot parse name: " + name);   
  9. }  

    你可以用 getPrefix(int posn) 和 getSuffix(int posn)來從前端或者後端查找組件的名字,如:

java 代碼
  1. CompositeName cn = new CompositeName("one/two/three");   
  2. Name suffix = cn.getSuffix(1);  // 1 <= index < cn.size()   
  3. Name prefix = cn.getPrefix(1);  // 0 <= index < 1  

 

    運行結果:
   
two/three
one

    1.3.4、修改一個複合名字
   
    你可以通過下列方法修改一個複合名字:

add(String comp)
add(int posn, String comp)
addAll(Name comps)
addAll(Name suffix)
addAll(int posn, Name suffix)
remove(int posn)

    當你創建了一個複合名字實例後,你可以對它進行修改。看看下面的例子:

java 代碼
  1. CompositeName cn = new CompositeName("1/2/3");   
  2. CompositeName cn2 = new CompositeName("4/5/6");   
  3. System.out.println(cn.addAll(cn2));           // 1/2/3/4/5/6   
  4. System.out.println(cn.add(0"abc"));         // abc/1/2/3/4/5/6   
  5. System.out.println(cn.add("xyz"));            // abc/1/2/3/4/5/6/xyz   
  6. System.out.println(cn.remove(1));             // 1   
  7. System.out.println(cn);               // abc/2/3/4/5/6/xyz   

 

    1.3.4、比較複合名字
   
    你可以通過以下的方法對複合名字進行比較:
   
compareTo(Object name)
equals(Object name)
endsWith(Name name)
startsWith(Name name)
isEmpty()

    你可以使用 compareTo(Object name) 方法對一個複合名字的列表進行排序。下面是一個例子:

java 代碼
  1. import javax.naming.CompositeName;   
  2. import javax.naming.InvalidNameException;   
  3.   
  4. /**  
  5.   * Demonstrates how to sort a list of composite names.  
  6.   *  
  7.   * usage: java SortComposites [<name></name>]*  
  8.   */  
  9. class SortComposites {   
  10.     public static void main(String[] args) {   
  11.     if (args.length == 0) {   
  12.         System.out.println("usage: java SortComposites [<names></names>]*");   
  13.         System.exit(-1);   
  14.     }   
  15.     CompositeName[] names = new CompositeName[args.length];   
  16.     try {   
  17.         for (int i = 0; i < names.length; i++) {   
  18.         names[i] = new CompositeName(args[i]);   
  19.         }   
  20.   
  21.         sort(names);   
  22.   
  23.         for (int i = 0; i < names.length; i++) {   
  24.         System.out.println(names[i]);   
  25.         }   
  26.     } catch (InvalidNameException e) {   
  27.         System.out.println(e);   
  28.     }   
  29.     }   
  30.   
  31.     /**  
  32.      * Use bubble sort.  
  33.      */  
  34.     private static void sort(CompositeName[] names) {   
  35.     int bound = names.length-1;   
  36.     CompositeName tmp;   
  37.   
  38.     while (true) {   
  39.         int t = -1;   
  40.         for (int j=0; j < bound; j++) {   
  41.         int c = names[j].compareTo(names[j+1]);   
  42.         if (c > 0) {   
  43.             tmp = names[j];   
  44.             names[j] = names[j+1];   
  45.             names[j+1] = tmp;   
  46.             t = j;   
  47.         }   
  48.         }   
  49.         if (t == -1break;   
  50.         bound = t;   
  51.     }   
  52.     }   
  53. }  

    equals() 方法可以讓你比較兩個複合名字是否相同。只有兩個複合名字有相同的組件,而且順序一樣,
    會返回 true。
   
    使用 startsWith() 和 endsWith()方法,你可以判斷複合名字是以什麼字符串開頭和以什麼字符串結尾。
   
    isEmpty() 方法可以讓你知道一個複合名字是否爲空。你也可以使用 size() == 0 來實現同樣的功能。
   
    下面是一些例子:

java 代碼
  1. CompositeName one = new CompositeName("cn=fs/o=JNDITutorial/tmp/a/b/c");   
  2. CompositeName two = new CompositeName("tmp/a/b/c");   
  3. CompositeName three = new CompositeName("cn=fs/o=JNDITutorial");   
  4. CompositeName four = new CompositeName();   
  5.   
  6. System.out.println(one.equals(two));        // false   
  7. System.out.println(one.startsWith(three));  // true   
  8. System.out.println(one.endsWith(two));      // true   
  9. System.out.println(one.startsWith(four));   // true   
  10. System.out.println(one.endsWith(four));     // true   
  11. System.out.println(one.endsWith(three));    // false   
  12. System.out.println(one.isEmpty());      // false   
  13. System.out.println(four.isEmpty());     // true   
  14. System.out.println(four.size() == 0);       // true  

    1.3.5、複合名字的字符串表現形式
   
    你可以使用 toString() 方法來實現這個功能。
    下面是一個例子:

java 代碼
  1. import javax.naming.CompositeName;   
  2. import javax.naming.InvalidNameException;   
  3.   
  4. /**  
  5.   * Demonstrates how to get the string representation of a composite name.  
  6.   *  
  7.   * usage: java CompositeToString   
  8.   */  
  9. class CompositeToString {   
  10.     public static void main(String[] args) {   
  11.     if (args.length != 1) {   
  12.         System.out.println("usage: java CompositeToString <string></string>");   
  13.         System.exit(-1);   
  14.     }   
  15.     String name = args[0];   
  16.     try {   
  17.         CompositeName cn = new CompositeName(name);   
  18.         String str = cn.toString();   
  19.         System.out.println(str);   
  20.         CompositeName cn2 = new CompositeName(str);   
  21.         System.out.println(cn.equals(cn2));     // true   
  22.     } catch (InvalidNameException e) {   
  23.         System.out.println("Cannot parse name: " + name);   
  24.     }   
  25.     }   
  26. }  

    1.3.5、複合名字作爲Context的參數
   
    直接看一個例子,非常簡單:

java 代碼
  1. // Create the initial context   
  2. Context ctx = new InitialContext(env);   
  3.        
  4. // Parse the string name into a CompositeName   
  5. Name cname = new CompositeName(   
  6.     "cn=homedir,cn=Jon Ruiz,ou=people/tutorial/report.txt");   
  7.   
  8. // Perform the lookup using the CompositeName   
  9. File f = (File) ctx.lookup(cname);  

 

    1.4、混合名字
   
    混合名字不是跨越命名系統的,例如:
   
    cn=homedir,cn=Jon Ruiz,ou=People
   
    它和複合名字有些類似,我們也可以把它看成是由不同的組件組成的,這個名字裏包含了三個組件:
   
    ou=People
    cn=Jon Ruiz
    cn=homedir
   
    1.4.1、混合名字和複合名字的關係
   
    當你給 Context.lookup() 傳遞一個字符串的時候,首先 lookup 方法會把這個字符串作爲複合名字來看
    待,這個複合名字可能只包含一個組件。但是一個組件可能會包含幾個混合名字。
   
    1.4.2、混合名字的字符串表現方式
   
    正如上面所說的,一個混合名字是由很多的組件組成的。組件之間的分隔符號依賴於特定的命名服務系統。
    例如在 LDAP 裏,分隔符好就是“,”,因此,下面的這個混合名字
   
ou=People
cn=Jon Ruiz
cn=homedir

    的字符串形式就是 cn=homedir,cn=Jon Ruiz,ou=People

    1.4.3、混合名字的類
   
    處理混合名字,我們可以使用 CompoundName 類。你可以向它的構造函數傳遞混合名字的字符串,並且還
    得設置一些必要的屬性,這些屬性一般都是特定的命名服務系統的一些規則。
   
    實際上,只有當你準備編寫一個SPI的時候,纔會去使用裝個構造函數。作爲一個開發者,一般你只是會
    涉及混合名字裏的各個組件而已。
    下面是一個例子:

java 代碼
  1. import javax.naming.*;   
  2. import java.util.Hashtable;   
  3.   
  4. /**  
  5.   * Demonstrates how to get a name parser and parse a name.  
  6.   *  
  7.   * usage: java ParseCompound  
  8.   */  
  9. class ParseCompound {   
  10.     public static void main(String[] args) {   
  11.     // Set up environment for creating initial context   
  12.     Hashtable env = new Hashtable(11);   
  13.     env.put(Context.INITIAL_CONTEXT_FACTORY,    
  14.         "com.sun.jndi.ldap.LdapCtxFactory");   
  15.     env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");   
  16.   
  17.     try {   
  18.         // Create the initial context   
  19.         Context ctx = new InitialContext(env);   
  20.   
  21.         // Get the parser for this namespace   
  22.         NameParser parser = ctx.getNameParser("");   
  23.   
  24.         // Parse name   
  25.         Name compoundName = parser.parse("cn=John,ou=People,ou=Marketing");   
  26.   
  27.         // List components in name   
  28.         for (int i = 0; i < compoundName.size(); i++) {   
  29.         System.out.println(compoundName.get(i));   
  30.         }   
  31.   
  32.         // Close ctx when done   
  33.         ctx.close();   
  34.     } catch (NamingException e) {   
  35.         System.out.println(e);   
  36.     }   
  37.     }   
  38. }   

    1.4.4、操作混合名字類
   
    注意,上面的例子中,我們使用 NameParser.parse() 來返回一個實現了Name接口的對象。這個接口可以
    是  CompositeName類 或 CompoundName類。這就意味着,你可以訪問或者修改一個混合名字對象,就好
    像我們在複合名字裏做的一樣!
    下面是一個例子:

java 代碼
  1. // Get the parser for this namespace   
  2. NameParser parser = ctx.getNameParser("");   
  3.   
  4. // Parse the name   
  5. Name cn = parser.parse("cn=John,ou=People,ou=Marketing");   
  6.   
  7. // Remove the second component from the head   
  8. System.out.println(cn.remove(1));          // ou=People   
  9.   
  10. // Add to the head (first)   
  11. System.out.println(cn.add(0"ou=East"));  // cn=John,ou=Marketing,ou=East   
  12.   
  13. // Add to the tail (last)   
  14. System.out.println(cn.add("cn=HomeDir"));  // cn=HomeDir,cn=John,ou=Marketing,ou=East  

 

    輸出結果:
   
ou=People
cn=John,ou=Marketing,ou=East
cn=HomeDir,cn=John,ou=Marketing,ou=East

    需要的注意的是,LDAP系統裏,組件的順序是從右到左的。也就是右邊是名字的開頭,而左邊是名字
    的結尾!
   
    下面這個例子是修改混合名字的:

java 代碼
  1. import javax.naming.*;   
  2. import java.util.Hashtable;   
  3. import java.io.File;   
  4.   
  5. /**  
  6.   * Demonstrates how to modify a compound name by adding and removing components.  
  7.   * Uses file system syntax.  
  8.   *  
  9.   * usage: java ModifyCompoundFile  
  10.   */  
  11. class ModifyCompoundFile {   
  12.     public static void main(String[] args) {   
  13.     // Set up environment for creating initial context   
  14.     Hashtable env = new Hashtable(11);   
  15.     env.put(Context.INITIAL_CONTEXT_FACTORY,    
  16.         "com.sun.jndi.fscontext.RefFSContextFactory");   
  17.   
  18.     try {   
  19.         // Create the initial context   
  20.         Context ctx = new InitialContext(env);   
  21.   
  22.         // Get the parser for this namespace   
  23.         NameParser parser = ctx.getNameParser("");   
  24.   
  25.         // Parse name   
  26.         Name cn = parser.parse("Marketing" + File.separator +    
  27.         "People" + File.separator +   
  28.         "John");   
  29.   
  30.         // Remove 2nd component from head   
  31.         System.out.println(cn.remove(1));             // People   
  32.   
  33.         // Add to head (first)   
  34.         System.out.println(cn.add(0"East"));     
  35.                         // East/Marketing/John   
  36.   
  37.         // Add to tail (last)   
  38.         System.out.println(cn.add("HomeDir"));   
  39.                         // /East/Marketing/John/HomeDir   
  40.   
  41.         // Close ctx when done   
  42.         ctx.close();   
  43.     } catch (NamingException e) {   
  44.         System.out.println(e);   
  45.     }   
  46.     }   
  47. }  

 

    這個例子使用了文件系統,而不是LDAP系統,輸出結果:
   
People
East/Marketing/John
East/Marketing/John/HomeDir

    1.4.5、混合名字作爲Context的參數
   
    我們只用一個例子就可以了:

java 代碼
  1. // Create the initial context   
  2. Context ctx = new InitialContext(env);   
  3.   
  4. // Get the parser for the namespace   
  5. NameParser parser = ctx.getNameParser("");   
  6.   
  7. // Parse the string name into a compound name   
  8. Name compound = parser.parse("cn=Jon Ruiz,ou=people");   
  9.   
  10. // Perform the lookup using the compound name   
  11. Object obj = ctx.lookup(compound);  

    1.4.6、取得完整的混合名字
   
    有的時候,你可能需要根據一個混合名字來的完整的名字。例如一個DNS,你只知道一部分如“www.abc.com”,
    但實際上它的完整的DNS是“www.abc.com.cn”。
   
    其實這個功能已經超出了jndi 的 api 所控制的範圍了,因爲 jndi 是不能決定完整的名字到底是什麼樣子,
    那必須依賴特定的命名服務系統。
   
    但是,jndi 仍然提供了一個接口 Context.getNameInNamespace()。這個方法的返回結果,依賴於你所使用
    的命名服務系統。
   
    下面是一個例子:
   

java 代碼
  1. // Create the initial context   
  2. Context ctx = new InitialContext(env);   
  3.   
  4. // Perform the lookup    
  5. Context jon = (Context)ctx.lookup("cn=Jon Ruiz,ou=people");   
  6.   
  7. String fullname = jon.getNameInNamespace();  

 

    輸出結果:
   
    cn=Jon Ruiz,ou=people,o=JNDItutorial

   
    1.5、名字解析
   
    名字解析的意思就是根據一個名字的字符串形式,把它解析成結構化的形式,如混合名字或複合名字。
    jndi API裏包含了這樣的接口,其接口的實現,依賴於特定的SPI。
   
    1.5.1、解析複合名字
   
    下面是一個例子:

java 代碼
  1. // Parse the string name into a CompositeName   
  2. Name cname = new CompositeName(   
  3.     "cn=homedir,cn=Jon Ruiz,ou=people/tutorial/report.txt");  

    其實這個用法我們早就在前面看過了。
   
    1.5.2、解析混合名字
   
    爲了解析混合名字,你必須使用 NameParser 接口,這個接口有一個方法:

java 代碼
  1. Name parse(String name) throws InvalidNameException  

    首先,你必須從 SPI 裏得到一個 NameParser 接口的實現:

java 代碼
  1. // Create the initial context   
  2. Context ctx = new InitialContext();   
  3.   
  4. // Get the parser for LDAP   
  5. NameParser ldapParser =    
  6.     ctx.getNameParser("ldap://localhost:389/o=jnditutorial");   
  7.   
  8. // Get the parser for filenames   
  9. NameParser fsParser = ctx.getNameParser("file:/");  

    一旦你得到了 NameParser 實例,你就可以用它來把字符串形式的名字轉換成結構化的名字。

java 代碼
  1. // Parse the name using the LDAP parser   
  2. Name compoundName = ldapParser.parse("cn=John Smith, ou=People, o=JNDITutorial");   
  3.   
  4. // Parse the name using the LDAP parser   
  5. Name compoundName = fsParser.parse("tmp/tutorial/beyond/names/parse.html");  

    如果解析錯誤,那麼會得到 InvalidNameException 。
   
    儘管 parse() 方法可以返回一個結構化的名字,但是我們還是建議僅僅用它來處理混合名字,而不要
    處理複合名字。
    parse()返回的對象未必一定是 CompoundName 類,只要返回的對象實現了 Name 接口就可以--這依賴
    於特定的SPI。
   
   
    1.6、動態生成複合名字
   
    之前我們介紹了訪問,操作複合名字的方法。但是還有一些難以處理的情況需要我們去面對。
    例如,如果你要給一個複合名字增加一個組件的話,你是增加複合名字的組件還是混合名字的組件?
    如果是混合名字的組件,那麼使用什麼規則呢?
    例如我們有這樣一個複合名字:
   
    cn=homedir,cn=Jon Ruiz/tutorial
   
    現在你需要增加一個文件名字,如果是windows系統,那麼就是:
   
    cn=homedir,cn=Jon Ruiz/tutorial/report.txt
   
    然後我們再增加一個LDAP混合名字 ou=People,那麼就需要使用LDAP的規則:
   
    cn=homedir,cn=Jon Ruiz,ou=People/tutorial/report.txt
   
    在這個例子中,我們使用了不同的命名服務系統,我們需要知道什麼時候因該使用什麼樣的命名系統
    的規則,這真的很麻煩。
   
    爲了解決這個問題,jndi API 提供了一個接口 Context.composeName(),它用來動態的組裝名字,
    當然依賴於特定的SPI了。
    你需要給它提供兩個參數:一個是需要追加的組件,一個是被追加的組件的名字。
   
    下面是一個例子:

  1. // Create the initial context  
  2. Context ctx = new InitialContext(env);  
  3.   
  4. // Compose a name within the LDAP namespace  
  5. Context ldapCtx = (Context)ctx.lookup("cn=Jon Ruiz,ou=people");  
  6. String ldapName = ldapCtx.composeName("cn=homedir""cn=Jon Ruiz,ou=people");  
  7. System.out.println(ldapName);  
  8.   
  9. // Compose a name when it crosses into the next naming system  
  10. Context homedirCtx = (Context)ctx.lookup(ldapName);  
  11. String compositeName = homedirCtx.composeName("tutorial", ldapName);  
  12. System.out.println(compositeName);  
  13.   
  14. // Compose a name within the File namespace  
  15. Context fileCtx = (Context)ctx.lookup(compositeName);  
  16. String fileName = fileCtx.composeName("report.txt", compositeName);  
  17. System.out.println(fileName); 

(6) 高級應用之 環境屬性

1、環境屬性

    在之前的文檔裏,我們已經學會如何去初始化一個內容上下文,例如:

java 代碼
  1. Hashtable env = new Hashtable();   
  2. env.put(Context.INITIAL_CONTEXT_FACTORY,    
  3.     "com.sun.jndi.ldap.LdapCtxFactory");   
  4. env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");   
  5.   
  6. Context ctx = new InitialContext(env);  

 

    這個例子中的 Hashtable,就是一個環境屬性,或者簡單的說是“環境”。
    這個章節裏,我們要介紹的就是這個“環境屬性”,看看他們是如何發揮作用的,以及如何使用的等等。
   
    JNDI其實只是一個接口,爲了訪問一個命名/目錄服務,你必須依賴特定的SPI。這就需要進行一些配置,
    你得告訴JNDI,你需要的SPI是什麼。
   
    下面是一些不同種類的環境屬性:
   
    a> 標準的
    b> 描述服務的
    c> 描述特性的
    d> 描述提供者的。
   
    下面是標準的環境屬性:

   

 

    1.1、環境屬性
   
    配置環境屬性可以通過兩種方式:一個是把一個Hashtable傳遞給InitialContext的構造函數,另一個
    是用一個 .properties 文件。
    一些JNDI的環境屬性還可以通過系統變量或者Applet參數來設置。
   
    1.1.1、應用程序資源文件(.properties文件)
   
    你可以在 .properties文件 裏指定JNDI的配置。這個文件的名字應該是 jndi.properties。例如下面
    就是一個 jndi.properties的例子:
   
java.naming.factory.object=com.sun.jndi.ldap.AttrsToCorba:com.wiz.from.Person
java.naming.factory.state=com.sun.jndi.ldap.CorbaToAttrs:com.wiz.from.Person
java.naming.factory.control=com.sun.jndi.ldap.ResponseControlFactory
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
java.naming.provider.url=ldap://localhost:389/o=jnditutorial
com.sun.jndi.ldap.netscape.schemaBugs=true

    首先,應用程序會從classpath 裏面載入 jndi.properties,如果沒有發現,那麼會載入JAVA_HOME/lib/
    jndi.properties。
   
    注意:如果你使用這種方式配置JNDI,那麼當找不到裝個文件的時候,會拋出異常。
   
    當然,我們初始化內容上下文的用法也需要修改一下:

java 代碼
  1. InitialContext ctx = new InitialContext();  

 

    1.1.2、通過系統變量設置JNDI
   
    我們可以使用如下的方式來實現這個功能:
   
    # java -Djava.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory /
      -Djava.naming.provider.url=ldap://localhost:389/o=jnditutorial /
      List

    1.1.3、Applet的方式設置JDNI
   
    看這個例子:

java 代碼
  1. name=java.naming.factory.initial   
  2. value=com.sun.jndi.ldap.LdapCtxFactory>   
  3.   
  4.     
  5. name=java.naming.provider.url   
  6. value=ldap://localhost:389/o=jnditutorial>  

    同時初始內容上下文也需要修改:

java 代碼
  1. // Put this applet instance into the environment   
  2. Hashtable env = new Hashtable();   
  3. env.put(Context.APPLET, this);   
  4.   
  5. // Pass the environment to the initial context constructor   
  6. Context ctx = new InitialContext(env);   
  7.   
  8. // List the objects    
  9. NamingEnumeration enum = ctx.list(target);   
  10. while (enum.hasMore()) {   
  11.      out.println(enum.next());   
  12. }   
  13. ctx.close();  

    1.2、內容上下文環境的探討
   
    我們已經知道可以通過三種方式來設置JDNI的屬性。但是,如果我們同時使用了兩種方式會
    怎麼樣呢?看看下面的例子:

java 代碼
  1. // Initial environment with various properties   
  2. Hashtable env = new Hashtable();   
  3. env.put(Context.INITIAL_CONTEXT_FACTORY,     
  4.     "com.sun.jndi.fscontext.FSContextFactory");   
  5. env.put(Context.PROVIDER_URL, "file:/");   
  6. env.put(Context.OBJECT_FACTORIES, "foo.bar.ObjFactory");   
  7. env.put("foo""bar");   
  8.   
  9. // Call the constructor   
  10. Context ctx = new InitialContext(env);   
  11.   
  12. // See what environment properties you have   
  13. System.out.println(ctx.getEnvironment());  

 

    我們同時配置一個jndi.properties在classpath裏:
   
java.naming.factory.object=com.sun.jndi.ldap.AttrsToCorba:com.wiz.from.Person
java.naming.factory.state=com.sun.jndi.ldap.CorbaToAttrs:com.wiz.from.Person
java.naming.factory.control=com.sun.jndi.ldap.ResponseControlFactory
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
java.naming.provider.url=ldap://localhost:389/o=jnditutorial
com.sun.jndi.ldap.netscape.schemaBugs=true

    然後看看運行的結果:
   
com.sun.jndi.ldap.netscape.schemaBugs=true
java.naming.factory.object=foo.bar.ObjFactory:com.sun.jndi.ldap.AttrsToCorba:com.wiz.from.Person
java.naming.factory.initial=com.sun.jndi.fscontext.FSContextFactory
foo=bar
java.naming.provider.url=file:/
java.naming.factory.state=com.sun.jndi.ldap.CorbaToAttrs:com.wiz.from.Person
java.naming.factory.control=com.sun.jndi.ldap.ResponseControlFactory

    下面來分析一下這個結果:
   
    a> 在 Hashtable 裏的“foo”項,和在文件裏的 “com.sun.jndi.ldap.netscape.schemaBugs”,
       都出現在結果裏。
    b> “java.naming.factory.object” 項是兩者的組合。
    c> 其他的屬性如“java.naming.factory.initial” 都是用的 Hashtable裏的。
   
    是不是有些混亂?如果我們要使用多個SPI該怎麼辦?沒關係,我們在下一個小結裏介紹這個問題。
   
    1.3、定製使用SPI
   
    你可以通過一個SPI的屬性文件,來爲某一個SPI進行單獨的設置。這個文件也是 .properties 文件。
    SPI的屬性文件應該類似下面:
   
    前綴/jndiprovider.properties
   
    這個前綴是什麼呢?就是這個SPI實現的內容上下文類(Context)的包的結構。
    例如,我們要使用的是 com.sun.jndi.ldap.LdapCtx 這個內容上下文,那麼對應於它的屬性配置
    文件就應該是:"com/sun/jndi/ldap/jndiprovider.properties"。
    一個應用可以使用多個這樣的屬性配置文件。
   
    那麼我們爲什麼要使用屬性配置文件?
    有兩個原因。第一,我們可以單獨的配置某一個命名/服務系統。第二,部署的時候會有用。例如,
    你可以單獨配置一個針對LDAP的屬性,而不用去修改 jndi.properties,或者增加系統變量。
   
    但是,我們也並不是可以在SPI屬性配置文件裏設置全部的屬性,我們可以設置的屬性如下:
   
java.naming.factory.object
java.naming.factory.state
java.naming.factory.control
java.naming.factory.url.pkgs

    不過並不象 jndi.properties 或者 那個Hastable,SPI屬性配置文件裏的屬性不會自動載入到環境
    裏,只有SPI調用了下列方法時纔會這樣做:
   
NamingManager.getObjectInstance(Object, Name, Context, Hashtable)
DirectoryManager.getObjectInstance(Object, Name, Context, Hashtable, Attributes)
NamingManager.getStateToBind(Object, Name, Context, Hashtable)
DirectoryManager.getStateToBind(Object, Name, Context, Hashtable, Attributes)
ControlFactory.getControlInstance(Control, Context, Hashtable)

    例如,假設我們使用一個LDAP服務,它的實現類是com.sun.jndi.ldap.LdapCtx,當這個類調用
    DirectoryManager.getObjectInstance() 方法時,JNDI將會從com/sun/jndi/ldap/jndiprovider.properties
    裏找到“java.naming.factory.object”項,然後把它追加到環境裏已經定義的項裏(例如那個Hashtable
    或者 jndi.properties)。

import javax.naming.*;         import javax.naming.directory.*;                 import java.util.Hashtable;                 /**          * Demonstrates how to replace a binding and its attributes to a context.          * (Use after Bind example; use Unbind to remove binding.)          *          * usage: java Rebind          */                class Rebind {             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.ldap.LdapCtxFactory");             env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");                     try {                 // Create the initial context                 DirContext ctx = new InitialDirContext(env);                         // Create object to be bound                 Fruit fruit = new Fruit("lemon");                         // Create attributes to be associated with object                 Attributes attrs = new BasicAttributes(true); // case-ignore                 Attribute objclass = new BasicAttribute("objectclass");                 objclass.add("top");                 objclass.add("organizationalUnit");                 attrs.put(objclass);                         // Perform bind                 ctx.rebind("ou=favorite, ou=Fruits", fruit, attrs);                         // Check that it is bound                 Object obj = ctx.lookup("ou=favorite, ou=Fruits");                 System.out.println(obj);                         // Get its attributes                 Attributes retattrs = ctx.getAttributes("ou=favorite, ou=Fruits");                 GetattrsAll.printAttrs(retattrs);                         // Close the context when we're done                 ctx.close();             } catch (NamingException e) {                 System.out.println("Operation failed: " + e);             }             }        
發佈了153 篇原創文章 · 獲贊 5 · 訪問量 44萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章