Sun JNDI教程翻譯 第二部分 Preparations

本文是JNDI Tutorial系列文章的第二部分:The Basics,介紹了JNDI的一些基礎知識,諸如Naming操作和Directory操作。介紹瞭如何通過編程的方式訪問命名和目錄服務,如何使用JNDI和目錄進行交互。從準備環境到查找對象以及在目錄中進行搜索等操作。
1.        預備知識
在開始之前,需要完成兩件事情,其一就是確保已經獲取需要的軟件,關於需要的軟件,在下面會列舉出來。另外就是,必須做一些編程設置。包括如何創建初始上下文以及如何處理JNDI拋出的異常。除此之外,還有一部分解釋瞭如何執行教程中的例子程序。例子程序用來引導learners建立自己的應用程序。可以通過運行例子來查看描述的行爲。當編寫自己的程序時,當在本機上運行時,看到的結果可能和例子程序有多不同。
下面提到的軟件是必須的:
Java平臺軟件
需要的JDK版本在v1.1.2以上即可。估計現在大多數用戶應該至少使用Java 2 SDK 1.4了吧,越來越多的用戶在使用1.5甚至1.6,所以基本不會需要使用擴展的JNDI。爲了運行applets,可以使用任何兼容Java的Web瀏覽器,例如HotJava,Internet Explorer5(and later),Netscape Comunicator或者Navigator v4。
JNDI軟件
從Java 2 SDK,v1.3開始,JNDI類庫就已經包含在JDK中了。如果使用較早的版本,可以從http://java.sun.com/products/jndi網站下載所需的軟件包。
服務provider軟件
JNDI API是通用的API,可以訪問任何命名和目錄服務。實際的訪問一個命名或者目錄服務時,需要將服務provider插入到JNDI中。一個服務provider就是將JNDI API映射到實際的命名和目錄服務器的調用。典型的,服務provider和命名/目錄服務器的角色是不同的,從客戶端和服務器的角度來說,JNDI和服務provider是客戶端,叫做JNDI客戶端,而命名/目錄服務器是服務器。客戶端和服務器會以多種形式進行交互,一種普通的方式是,它們使用一個網絡協議,這樣客戶端和服務器可以共存在一個網絡環境中。服務器通常支持多種客戶端,而不僅僅是JNDI客戶端,只需要客戶端遵守特定的協議。JNDI對JNDI客戶端和服務器的交互不作任何形式上的規定。一個極端的例子是客戶端和服務器可以是同一個實體。需要獲取使用的服務provider的類文件,例如,如果打算使用JNDI訪問LDAP目錄服務器,那麼就需要一個LDAP服務provider軟件。Java 2 SDK v1.3包含了LDAP、COS命名和RMI註冊的服務provider。如果使用一個更早的JDK,需要獲取服務provider,下載的地址依然是JNDI Web Site。
本教程使用以下兩個服務provider:
¨         文件系統服務provider,用於命名實例
¨         LDAP服務provider,用於目錄和事件通知實例
當使用文件系統服務provider的時候,不需要建立一個服務器,因爲可以使用本地文件系統作爲服務器,當使用LDAP服務provider的時候,需要創建一個自己的服務器或者可以訪問一個既存的服務器。
命名和目錄服務器軟件
在獲取了服務provider軟件之後,就需要創建或者訪問相應的命名和目錄服務器了。創建一個命名或者目錄服務器是典型的網絡系統管理員的工作。不同的供應商的命名和目錄服務器的安裝過程是不同的。一些服務器在安裝的時候要求特殊的機器權限。所以,在安裝的時候需要查看安裝手冊。
在本教程的命名例子中,需要使用文件系統。
在本教程的目錄例子中,需要訪問一個LDAP服務器,一個免費的,公開的LDAP服務器是OpenLDAP,可以下載該LDAP服務器軟件。一些公開的可以訪問的ldap服務器如下:
ldap://ldap.Bigfoot.com
ldap://ldap.four11.com
ldap://ldap.InfoSpace.com
筆者使用的軟件爲開源的ApacheDS目錄服務器,即Apache Directory Server,結合Apache Directory Studio(或者安裝Eclipse插件,其工具本身是基於Eclipse)ldp.exe(Microsoftldp客戶端工具)或者ldapbrowser工具來處理目錄服務器相關的知識。關於ApacheDS,請參考筆者的另外ApacheDS系列文章及Apache官方網站的介紹(http://directory.apache.org)
2.        Contents of the Directory目錄的內容
一旦安裝好目錄後,或者已經可以在程序中和目錄通信後,就可以從目錄中獲取兩種類型的信息:綁定和屬性
目錄可以被看作是由名稱到對象的綁定組成的。也就是說,每個目錄中的對象都有一個對應的名稱。可以通過指定名稱來查找對應的對象。如果在使用諸如文件系統的命名服務的話,那麼文件就是對象,它們被綁定到文件名。
同時存儲在目錄中的還是屬性,一個目錄中的對象,除了有名稱之外,還包含一個可選的屬性集合。可以從目錄中獲取對象的屬性,也可以通過指定特定的屬性來查詢對象。
這部分教程提供了訪問綁定和屬性的例子,關於可以從命名和目錄服務中取得的細節和具體的服務相關。
Directory Schma目錄模式
一個模式指定了目錄中包含的對象的類型。本教程中,目錄包含實體,其中一些實體需要特殊的模式定義。爲了實現這些實體,必須關閉服務器中的模式檢查或者向服務器中添加和本教程對應的模式文件。這些工作是由目錄服務器管理員來完成的。
本教程使用到了以下兩個模式文件,必須安裝在服務器中:
¨         Java對象模式
¨         CORBA對象模式
這些文件的格式具有正式的描述,並且一般不可以直接拷貝粘貼到服務器的配置文件中。特別是RFC 2252中描述的屬性的語法。
在本教程中的java.schema文件和corba.schema文件中定義的內容在ApacheDS中已經包含了這兩個schema,並且包含了一些更多的schemaApacheDS在啓動時加載的schema有如下的schemas
        <bean class="org...schema.bootstrap.AutofsSchema"/>
        <bean class="org...schema.bootstrap.CorbaSchema"/>
        <bean class="org...schema.bootstrap.CoreSchema"/>
       <bean class="org...schema.bootstrap.CosineSchema"/>
        <bean class="org...schema.bootstrapSchema"/>
        <bean class="org...schema.bootstrap.CollectiveSchema"/>
        <bean class="org...schema.bootstrap.InetorgpersonSchema"/>
        <bean class="org...schema.bootstrap.JavaSchema"/>
        <bean class="org...schema.bootstrap.Krb5kdcSchema"/>
        <bean class="org...schema.bootstrap.NisSchema"/>
        <bean class="org...schema.bootstrap.SystemSchema"/>
        <bean class="org...schema.bootstrap.ApachednsSchema"/>
其中導入的java.schema文件和corba.schema文件的內容如下(只截取註釋說明部分):
#java.schema
# 3 Attribute Type Definitions
#
#    The following attribute types are defined in this document:
#
#        javaClassName
#        javaClassNames
#        javaCodebase
#        javaSerializedData
#        javaFactory
#        javaReferenceAddress
#        javaDoc
#
# 4 Object Class Definitions
#
#    The following object classes are defined in this document:
#
#        javaContainer
#        javaObject
#        javaSerializedObject
#        javaMarshalledObject
#        javaNamingReference
 
#corba.schema
# 3. Attribute Type Definitions
#
#    The following attribute types are defined in this document:
#
#        corbaIor
#        corbaRepositoryId
#
 
# 4. Object Class Definitions
#
#    The following object classes are defined in this document:
#
#        corbaContainer
#        corbaObject
#        corbaObjectReference
這裏的java.schemacorba.schema文件都比Sun JNDI Tutorial提供的少了兩個,一個爲
( 2.5.4.13
 NAME 'description'
 EQUALITY caseIgnoreMatch
 SUBSTR caseIgnoreSubstringsMatch
 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024}
)
另一個是:
( 2.5.13.5
 NAME 'caseExactMatch'
 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
)
           description屬性類型在其他的schema(ApacheDS)已經定義,但是caseExactMatch不知道具體是做什麼的,ApacheDS中也沒有找到相關的定義。有待考察!
不同的目錄服務器配置這些模式的方法不同,本教程包含了一些安裝Java和CORBA模式的工具,用於將模式安裝在允許模式被LDAP進行修改的目錄服務器上。也包含一些工具用於更新一個既存的目錄,但是該目錄包含一些老版本的模式,下面是一個工具可以完成的任務列表:
創建Java Schema
創建CORBA Schema
更新一個使用老版本Java Schema的目錄中的實體
更新一個使用老版本CORBA Schema的目錄中的實體
              根據相應的README文件來運行這些程序。
Providing Directory Content for This Tutorial爲本教程提供目錄內容
運行Setup程序來創建文件系統名稱空間。這個程序創建了一個文件樹,根據需要列表和查詢對象的需要,創建了一個普通的參考。運行這個程序的時候,需要設置一個測試的名稱空間。例如:
java Setup /tmp/tutorial,在windows系統中,使用d:/workspace/JNDITutorial/tmp/tutorial。
創建完成的目錄結構如下圖所示:
在d:/workspace/JNDITutorial/tmp/tutorial目錄中創建了上圖所示的目錄,並在一些目錄中填充了文件。
在本教程中的目錄例子中,通過使用配置文件(tutorial.ldif)來創建LDAP目錄。如果在使用一個既存的服務器,可能會看到不同的結果,在向服務器中加載tutorial.ldif文件之前,必須先跟隨指南進行服務器schema的更新。(在ApacheDS中這部分已經更新完成)
首先參照筆者的關於ApacheDS的相關文章,創建分區suffix爲o=JNDITutorial的分區作爲root命名上下文,然後通過使用ApacheDS Tool或者Studio Tool導入ldif文件。爲了保持文檔的完整性,筆者簡要介紹上述步驟。
首先修改$ApacheDS_HOME/conf/server.xml文件,找到如下元素後進行修改:
    <property name="contextPartitionConfigurations">
      <set>
        <ref bean="examplePartitionConfiguration"/>
        <ref bean="sevenSeasPartitionConfiguration"/>
        <ref bean="JNDITutorialPartitionConfiguration"/>
      </set>
    </property>
然後拷貝<bean id="sevenSeasPartitionConfiguration"元素的內容,並粘貼,在這個基礎上進行如下的修改,修改後的結果如下:
<bean id="JNDITutorialPartitionConfiguration" class="org...MutableBTreePartitionConfiguration">
    <property name="name" value="JNDITutorial" />
    <property name="cacheSize" value="100"/>
    <property name="suffix" value="o=JDNITutorial" />
 
    <!-- the optimizer is enabled by default but may not always be what     -->
    <!-- you want if your queries are really simple                         -->
    <property name="optimizerEnabled" value="true" />
 
    <!--
      Synchronization on writes does not wait for synch operations
      to flush dirty pages. Writes persist immediately to disk at
      a cost to performance with increased data integrity. Otherwise
      the periodic synch operation will flush dirty pages using the
      synchPeriodMillis parameter in the main configuration.
    -->
    <property name="synchOnWrite" value="true" />
    <property name="indexedAttributes">
      <set>
        <bean class="org...MutableIndexConfiguration">
          <property name="attributeId" value="o" />
          <property name="cacheSize" value="100" />
        </bean>
        <bean class="org...MutableIndexConfiguration">
          <property name="attributeId" value="ou" />
          <property name="cacheSize" value="100" />
        </bean>
        <bean class="org...MutableIndexConfiguration">
          <property name="attributeId" value="krb5PrincipalName" />
          <property name="cacheSize" value="100" />
        </bean>
        <bean class="org...MutableIndexConfiguration">
          <property name="attributeId" value="uid" />
          <property name="cacheSize" value="100" />
        </bean>
        <bean class="org...MutableIndexConfiguration">
          <property name="attributeId" value="objectClass" />
          <property name="cacheSize" value="100" />
        </bean>
      </set>
    </property>
    <property name="contextEntry">
      <value>
        objectClass: top
        objectClass: organization
        objectClass: extensibleObject
        o: JNDITutorial
      </value>
    </property>
 </bean>
重新啓動服務器,確認啓動成功,然後再Eclipse(已經安裝ApacheDS插件)中設置連接到LDAP服務器的參數如下:
點擊OK,由於此時LDAP中還沒有數據,所以左側的LDAP Browser顯示結果如下(只有一個根實體):
通過ldapbrowser查看結果如下:
最後導入tutorial.ldif文件,選中JNDITutorial節點,右鍵選擇導入,如圖所示:
 
注意:Sun JNDITutorial中說明,在tutorial.ldif中以distinguished name:”o=JNDITutorial”作爲根命名上下文,如果使用的目錄服務器不是這樣的話,可能會發生錯誤,但是由於筆者已經使用ApacheDS創建了o=JNDITutorial這個根上下文,所以需要修改一下tutorial.ldif文件的內容,修改後的文件內容如下:
#刪除藍色的部分
dn: o=JNDITutorial
o: JNDITutorial
objectclass: top
objectclass: organization
 
dn: ou=Groups, o=JNDITutorial
ou: Groups
objectclass: top
objectclass: organizationalunit
......
導入完成的結果如圖所示:
至此創建LDAP root naming context完成,由於ApacheDS默認情況下有些檢索的權限設置,所以需要進行修改,關於修改的過程,請參考筆者的其他文章。
 
包和類路徑
爲了在程序中使用JNDI,需要完成以下編譯和執行環境的配置。
引入JNDI類。以下是JNDI package:
    * javax.naming(in the API reference documentation)
    * javax.naming.directory(in the API reference documentation)
    * javax.naming.event(in the API reference documentation)
    * javax.naming.ldap(in the API reference documentation)
    * javax.naming.spi(in the API reference documentation)
在本教程中使用到的類和接口都屬於前兩個package。在使用的時候需要單個引入需要的類或者接口,或者將兩個package全部引入,例如:
import javax.naming.*;
import javax.naming.directory.*;
編譯環境。在編譯JNDI程序時,需要訪問JNDI類,Java2 SDK v1.3已經包含了JNDI類,如果使用的是以前的JDK版本,那麼需要進行JNDI的配置。(筆者認爲現在基本上很少有使用1.3版本以前的JDK,所以這部分就不翻譯了)
運行環境。運行JNDI程序時,需要可以訪問JNDI類以及程序用到的服務提供商的類。Java 2 Runtime Environment(JRE) v1.3已經提供了JNDI類和LDAP、COS命名、RMI註冊的服務供應商的類。如果使用的是其他的服務供應商,那麼需要下載特定的檔案文件(jar/zip),並將其放在JAVA_HOME/jre/l ib/ext目錄,其中JAVA_HOME是包含JRE的目錄。同樣,如果使用的老版本的JRE,那麼需要在JNDI Web網站下載JNDI類。該網站同時提供了一些其他的服務provider,可以下載或者使用其他供應商的provider。
如果使用的JRE版本爲JRE v1.2,那麼需要按照Java擴展方法來安裝JNDI類,具體方法參考本文末尾部分附錄。
Naming Exceptions
當請求的操作不能被處理時,很多JNDI package中的方法拋出一個NamingExcetpion異常。通常情況下需要使用try—catch來拋出---捕獲異常。
try {
    Context ctx = new InitialContext();
    Object obj = ctx.lookup("somename");
} catch (NamingException e) {
    // Handle the error
    System.err.println(e);
}
異常類繼承層次。在JNDI中,有很多類繼承NamingException這個異常類,異常類的名字是自說明的,即異常類的名字說明了異常的種類。如果需要對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 error
    System.err.println(e);
}
枚舉。諸如Context.list()和DirContext.search()這樣的操作返回一個NamingEnumeration對象。在這些情況下如果發生異常並且沒有檢索結果返回的話,將拋出一個NamingException或者其適當的子類。如果發生異常但是返回了結果,那麼將返回一個NamingEnumeration對象,以便獲取那些結果。當所有結果都獲取後,調用NamingEnumeration.hasMore()會拋出NamingException或其子類來提示發生了錯誤。此時enumeration已經失效,任何對其的調用都會發生錯誤。
例如,如果執行search()方法,並指定返回結果的限制爲n,這是檢索結果返回的enumeration最多包含n個結果。如果結果的數量大於n的話,那麼調用NamingEnumeration.hasMore()時,就會拋出一個SizeLimitExceededException。
// Set the search controls to limit the count to 1
SearchControls ctls = new SearchControls();
ctls.setCountLimit(1);
 
本教程中的樣例代碼中,爲了便於閱讀,都省略了try-catch子句,因爲在教程中使用的代碼都是片段,而在源代碼中都包含了完整的try-catch子句。
javax.naming package中的異常如下:
javax.naming.directory package中的異常如下:
javax.naming.ldap package中的異常如下
InitialContext
在執行任何命名或者目錄操作之前,需要獲取一個initial context---到一個名稱空間的切入點。這是由於所有對命名和目錄服務的操作都是相對於上下文的。可以通過以下步驟獲取一個initial context:
¨         選擇對應服務的服務provider
¨         指定initial context需要的配置屬性
¨         調用InitialContext類的構造器
設置服務provider。通過設置environment properties(Hashtable)來指定initial context使用的服務provider,並添加服務provider類的名字到環境屬性。例如,如果使用Sun的LDAP服務provider,可以使用下面的代碼來添加服務provider:
Hashtable env=new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,”com.sun.jndi.ldap.LdapCtxFactory”);
如果要指定Sun的文件系統服務provider,則爲如下代碼:
Hashtable env=new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,”com.sun.jndi.fxcontext.RefFSContextFactory”);
注:還可以通過system properties來指定服務provider。關於system properties和environment properties的詳細介紹,在後面的教程中會涉及。
設置其他屬性。不同的目錄服務可能需要不同的信息。例如LDAP服務器需要指定LDAP服務器的鏈接地址,綁定的用戶名和密碼,如下所示:
env.put(Context.PROVIDER_URL,”ldap://localhost:389”);
env.put(Context.SECURITY_PRINCIPAL,”joeuser”);
env.put(Context.SECURITY_CREDENTIALS,”joepassword”);
而對於文件系統來說,需要的知識一個服務的URL:
env.put(Context.PROVIDER_URL,”file:/tmp/tutorial/”);
本教程中的LDAP服務器的地址爲ldap://localhost:289/o=JNDITutorial,文件系統的路徑爲D:/workspace/JNDITutorial/tmp/tutorial/。
創建InitialContext。現在已經準備好創建initial context,將前面創建的env參數傳遞給InitialContext構造器即可。
Context ctx=new InitialContext(env);
當執行目錄操作時,需要使用InitialDirContext,使用下面的構造器來構造:
DirContext ctx=new InitialDirContext(env);
 
Names
Context和DirContext接口都包含了重載的方法,一個接受java.lang.String參數,另外一個接受Name類的參數。當Name和java.lang.String參數只是簡單的表示同一個名稱時,每對衝在的函數是相同的。
 
附:Java擴展方法
The extension mechanism was introduced as a new feature in the JavaTM 1.2 platform. The extension mechanism provides a standard, scalable way to make custom APIs available to all applications running on the Java platform. As of the Java 1.3 platform release, Java extensions are also referred to as optional packages. This trail may use both terms interchangeably.
Extensions are groups of packages and classes that augment the Java platform through the extension mechanism. The extension mechanism enables the runtime environment to find and load extension classes without the extension classes having to be named on the class path. In that respect, extension classes are similar to the Java platform's core classes. That's also where extensions get their name -- they, in effect, extend the platform's core API.
Since this mechanism extends the platform's core API, its use should be judiciously applied. Most commonly it is used for well standarized interfaces such as those defined by the Java Community ProcessSM, although it may also be appropriate for site wide interfaces.
As the diagram indicates, extensions act as "add-on" modules to the Java platform. Their classes and public APIs are automatically available to any applications running on the platform.
The extension mechanism also provides a means for extension classes to be downloaded from remote locations for use by applets.
Extensions are bundled as Java Archive (JAR) files, and this trail assumes that you are familiar with the JAR file format. If you're not up to speed on JAR files, you might want to review some JAR-file documentation before proceeding with the lessons in this trail:
This trail has two lessons:
This section shows you what you need to do to add an extension to your Java platform and how applets can benefit from the extension mechanism by downloading remote extension classes.
This section describes security privileges and permissions that are granted to extensions on your platform. You'll see how to use the Java platform's security architecture if you're writing extensions classes of your own.
Additional Documentation
You can find further information about extensions in the The Java Extensions Mechanism section of the JDK documentation. 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章