6.2 使用JNDI?
6.2.1? JNDI服務提供者
不使用服務提供者就不能用JNDI。一個服務提供者就是一組Java類的集合,它支持開發者同目錄服務進行通信,其方式類似于JDBC驅動程序與數據庫之間的通信方式。能夠用于JNDI的服務提供者必須實現Context接口或Context的擴展接口Directory- Context。
在使用JNDI時,讀者只需要了解JNDI,而服務提供者才關注實際的網絡協議、編碼/解碼值等細節。
當下載SDK軟件開發包時,同時就下載了Sun公司的一些現有的服務提供者。這些服務提供者包括LDAP、NIS、COS(CORBA對象服務)、RMI注冊及文件系統的提供者。如:hashtableObj.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.ldapCtx- Fatory")就是表示使用Sun LDAP服務提供者。當然如果要使用IBM服務提供者時就可以用com.ibm.jndi.LDAPCtxFatory來代替com.sun.jndi.ldap.ldapCtxFatory。
6.2.2? JNDI的包
JNDI中包括5個包。
·?????? javax.naming:主要用于命名操作,它包含了命名服務的類和接口,該包定義了Context接口和InitialContext類;
·?????? javax.naming.directory:主要用于目錄操作,它定義了DirContext接口和InitialDir- Context類;
·?????? javax.naming.event:在命名目錄服務器中請求事件通知;
·?????? javax.naming.ldap:提供LDAP支持;
·?????? javax.naming.spi:允許動態插入不同實現,為不同命名目錄服務供應商的開發人員提供開發和實現的途徑,以便應用程序通過JNDI可以訪問相關服務。
6.2.3? 常用的JNDI操作
常用的JNDI操作如下:
·?????? void bind(String sName,Object object),綁定:把名稱同對象關聯的過程。
·?????? void rebind(String sName,Object object),重新綁定:用來把對象同一個已經存在的名稱重新綁定。一般使用rebind()而不使用bind(),因為當有重名的時候rebind()不會出現異常,而bind()會報異常。
·?????? void unbind(String sName),釋放:用來把對象從目錄中釋放出來。
·?????? void lookup(String sName,Object object),查找:返回目錄總的一個對象。
·?????? void rename(String sOldName,String sNewName),重命名:用來修改對象名稱綁定的名稱。
·?????? NamingEnumeration listBindings(String sName),清單:返回綁定在特定上下文中指定屬性名對象的清單列表,它返回名字、類和對象本身,它用于那些需要對對象進行實際操作的應用。具體使用如下:
java 代碼
?
?? ?? Context?cntxt?=?new?InitialContext(); ?? ?? ?? ?? NamingEnumeration?namEnumList?=?ctxt.listBinding("cntxtName"); ?? ?? ?? ?? while?(?namEnumList.hasMore()?)??{ ?? ?? ????Binding?bnd?=?(Binding)?namEnumList.next(); ?? ?? ????String?sObjName?=?bnd.getName(); ?? ?? ????String?sClassName?=?bnd.getClassName(); ?? ?? ?????? ?? ????SomeObject?objLocal?=?(SomeObject)?bnd.getObject(); ?? ?? } ??
·?????? NamingEnumeration list(String sName)與listBindings(String sName)相似,只是它只返回一系列名字/類映射,它主要是用于上下文瀏覽應用。
6.2.4? JNDI操作步驟
使用JNDI來訪問命名服務或者目錄服務,操作步驟如下:
(1)建立一個散列表(hashtable),它包含定義所希望使用的JNDI服務的屬性,所希望連接的LDAP服務器IP地址以及工作的端口。
(2)將與認證成為用戶登錄有關的任何信息添加到散列表中。
(3)創建初始context對象。如果訪問命名服務,則使用InitialContext類,如果訪問目錄服務,則要使用InitialDirContext類。
(4)使用剛才得到的context對象執行所需的操作(如添加新的條目或者搜索條目)。
(5)完成操作后關閉context對象。
6.2.5? JNDI允許存儲的對象類型
JNDI最大的功能是能使用LDAP來存儲需要在不同應用之間共享或者留做備用的對象。JNDI允許將下面幾種與Java相關的對象類型存儲到LDAP服務器內。
(1)串行化的Java對象。這是存儲和取回已經串行化的Java對象的能力。也就是??? 說要存儲的Java對象必須要實現Referenceable或Serializable接口類,否則該對象不能存儲。
(2)標準的LDAP目錄條目。它提供了操作標準目錄數據的能力。標準目錄數據的數據量比較小,可以在不同的語言之間共享它們。保持目錄數據與編程語言的無關性對于要使用幾種不同語言進行開發的大企業里是非常重要的。
(3)指向RMI Java對象的指針。RMI是用于分布式計算的,通過RMI,一個Java應用可以像本地一樣調用一個遠程類的方法。我們可以把一個可用的RMI類的引用存儲在開發者的LDAP服務器中,而不必在每個裝有RMI客戶應用的計算機上都保持可用方法的注冊。
6.2.6? JNDI存儲查詢串行化的Java對象
JNDI的主要目標是在網絡上讀/寫Java對象。下面用具體實例來了解怎么使用JNDI。首先通過一個例子來講解怎么樣在LDAP中保存串行化的Java對象數據,再用一個例子來說明怎么對保存的對象數據進行查詢、調用。
1.保存數據
在LDAP中保存數據就是在LDAP服務器中添加使用條目,也就是把條目綁定在服務器中。下面先建立一個基本類,再在另一個類中利用JNDI把這個基本類綁定在服務器中。
4 例6-1 ?在LDAP中保存數據。
(1)待綁定的基本類
java 代碼
package?jndi; ?? ?? import?java.io.serializable; ?? ?? public?class?persons??implements?Serializable?{ ?? ?? ????String?Name?=?""; ?? ?? ????String?Age?=""??; ?? ?? ????public?persons?()?{ ?? ?? ????} ?? ?? ?????? ?? ????public?persons?(String?namePara,String?age)?{ ?? ?? ????????Name?=?namePara; ?? ?? ????????Age?=?age; ?? ?? ????} ?? ?? ?????? ?? ????public?String?getName()?{ ?? ?? ????????return?Name; ?? ?? ????} ?? ?? ?????? ?? ????public?String?getAge?()?{ ?? ?? ????return??Age; ?? ?? ????} ?? ?? } ?? ??
JNDI定義了一個Serializable接口類來為應用信息的表達提供一種統一的方式。Serializable接口類包含了諸如地址、類型信息等用于訪問具體對象的信息。為了能將對象的引用綁定到目錄樹中,該對象的類必須實現Referenceable接口,其中包含了方法 getReference()。開發者可以在該對象上調用getReference()方法來獲得Reference以用于綁定。Serializable接口與Referenceable接口有頗多相似之處,不同在于Referenceable可引用的對象只包含一些用于創建實際對象的信息,而Serializable會包含更多的甚至不適合存儲在目錄結構中的信息。
(2)綁定保存對象程序
java 代碼
package?jndi; ?? ?? import?java.util.Hashtable; ?? ?? import?javax.naming.Context; ?? ?? import?javax.naming.NamingException;???? ?? ?? import?javax.naming.directory.*; ?? ?? public?class?ldapDataBind?{ ?? ?? ???public?static?void?main(String[]args){ ?? ?? ????????? ?? ????????Hashtable?hs?=?new?Hashtable(); ?? ?? ?????????? ?? ????????hs.put(Context.INITIAL_CONTEXT_FACTORY,? ?? ?? ??????????????????????"com.sun.jndi.ldap.LdapCtxFactory"); ?? ?? ?????????? ?? ????????hs.put(Context.PROVIDER_URL,?"ldap://localhost:389?"); ?? ?? ?????????? ?? ????????hs.put(Context.SECURITY_AUTHENTICATION,?"simple"); ?? ?? ?????????? ?? ????????hs.put(Context.SECURITY_PRINCIPAL,?"cn=Directory?Manager"); ?? ?? ?????????? ?? ????????hs.put(Context.SECURITY_CREDENTIALS,?"password"); ?? ?? ????????try?{ ?? ?? ????????????? ?? ???????????DirContext?ctx?=?new?InitialDirContext(hs); ?? ?? ????????????? ?? ???????????persons?perObj?=?new?persons("jordan","40"); ?? ?? ????????????? ?? ???????????ctx.rebind?("uid?=?Jordan,ou?=?Bull,o?=?NBA?",perObj); ?? ?? ???????????System.out.println("bind?object?object?success?"?); ?? ?? ??????????????? ?? ?????????????Attributes??attrs?=??new?BasicAttributes(true); ?? ?? ??????????????? ?? ????????????Attribute??personMail??=?new?BasicAttribute("mail"); ?? ?? ?????????????? ?????????????????"xyh@powerise.com.cn"?? ?? ????????????personMail.add("xie@163.com"); ?? ?? ????????????personMail.add("liu@sina.com.cn"); ?? ?? ????????????personMail.add("xyh@powerise.com.cn"); ?? ?? ?????????????attrs.put(personMail); ?? ?? ??????????????? ?? ????????????attrs.put("uid","001"); ?? ?? ?????????????? ?? ????????????attrs.put("cn","jordan1"); ?? ?? ?????????????? ?? ????????????attrs.put("sn","NBA"); ?? ?? ?????????????? ?? ????????????attrs.put("ou","bull"); ?? ?? ????????????System.out.println("bind?object?object?success?"?); ?? ?? ?????????????? ?? ????????????ctx.createSubcontext("uid?=?Jordan,?ou?=?Wizzard,o=NBA",attrs); ?? ?? ????????????? ?? ???????????ctx.close(); ?? ?? ????????}?catch?(NamingException?ex)?{ ?? ?? ???????????System.err.println("bind?object?fail:?"?+?ex.toString()); ?? ?? ????????}?? ?? ?? ???} ?? ?? } ?? ??
2.使用JNDI查找數據
前面已經介紹了怎么樣將對象數據綁定到服務器,現在開始介紹如何取得調用綁定在服務器上的對象數據。
5 例6-2 ?使用JNDI查找數據。
要調用對象數據,首先就必須用JNDI查找綁定的對象和數據,查找出來后,再調用該對象。程序如下所示。
java 代碼
package?jndi; ?? ?? import?java.nutil.Hashtable; ?? ?? import?javax.naming.Context; ?? ?? import?javax.naming.NamingException; ?? ?? import?javax.naming.NamingEnumeration; ?? ?? import?javax.naming.directory.*; ?? ?? public?class?findUseBindObj?{ ?? ?? public?static?void?main(String[]args){ ?? ?? ??????????? ?? ???????Hashtable?hs?=?new?Hashtable(); ?? ?? ?????????? ?? ????????hs.put(Context.INITIAL_CONTEXT_FACTORY, ?? ?? ???????????????????????"com.sun.jndi.ldap.LdapCtxFactory"); ?? ?? ?????????? ?? ????????hs.put(Context.PROVIDER_URL,?"ldap://localhost:389"); ?? ?? ????????try?{ ?? ?? ????????????? ?? ???????????DirContext?ctx?=?new?InitialDirContext(hs); ?? ?? ???????????? ?? ???????????persons?pers?=(persons)ctx.lookup("uid=Jordan,ou=Bull,o=NBA"); ?? ?? ????????????? ?? ???????????String??age????=??pers.getAge(); ?? ?? ????????????? ?? ???????????String??name??=??pers.getName(); ?? ?? ????????????? ?? ???????System.out.println("name?is?:"?+??name?); ?? ?? ???????? ?? ?? ???????Attributes?attrs=ctx.getAttributes("uid=Jordan,ou=Wizzard,o=NBA"); ?? ?? ????????? ?? ???????for(NamingEnumeration?ae?=?attrs.getAll();ae.hasMore();){ ?? ?? ????????????? ?? ???????????Attribute?attr?=?(Attribute)ae.next(); ?? ?? ???????????System.out.println("Attribute?:?"?+?attr.getID()); ?? ?? ???????????????????????? ?? ????????????for(NamingEnumeration?ve?=?attr.getAll();ve.hasMore();){ ?? ?? ????????????????????????System.out.println("??Value?:?"?+?ve.next()); ?? ?? ????????} ?? ?? ????????} ?? ?? ?????????? ?? ????????System.out.println("find?object?success?"?); ?? ?? ?????????? ?? ???????pers.toString(); ?? ?? ??????????? ?? ?? ????????? ?? ???????ctx.close(); ?? ?? ????}?catch?(NamingException?ex)?{ ?? ?? ???????System.err.println(ex.toString()); ?? ?? ????}????? ?? ?? ??} ?? ?? } ?? ??
對于作為引用綁定在目錄樹中的對象,JNDI SPI 指定針對引用創建實際的對象。因此,在程序中只需要認為用lookup()方法返回的對象就是實際對象,而不用在調用什么方法來將引用轉換為實際對象了,因為所有的工作都由JNDI內部完成了。
6.2.7? JNDI查詢修改LDAP目錄條目
前面已經介紹了如何在LDAP服務器里存儲一個對象:主要是利用一個DN將對象綁定到LDAP服務器中,然后用lookup(DN)查找定位到綁定的對象,再對該對象進行操作。但是往往使用DN查找非常難,用戶很難記住DN,因此我們可以使用其他屬性(比如CN=Cherry)來檢索包含那個屬性的條目。下面來介紹JNDI中相關屬性檢索的具體使用。
1.修改條目
很多時候可能要對LDAP服務器上的條目進行修改,如修改用戶密碼,更新應用的配置等。但修改必須由一個已認證過的用戶來執行,而且通常只能修改自己的密碼而不能修改其他信息,管理助手能夠修改電話號碼和郵件地址,而修改用戶標識這種工作由數據庫管理員完成。
6 例6-3? 用JNDI修改LDAP條目。
java 代碼
package?jndi; ?? ?? import?java.nutil.Hashtable; ?? ?? import?javax.naming.Context; ?? ?? import?javax.naming.directory.Attribute; ?? ?? import?javax.naming.directory.Attributes; ?? ?? import?javax.naming.directory.BasicAttribute; ?? ?? import?javax.naming.directory.DirContext; ?? ?? import?javax.naming.directory.InitialDirContext; ?? ?? import?javax.naming.directory.ModificationItem; ?? ?? public?class?jndiPropertyModify?{ ?? ?? ????public?static?void?main(String[]?args){ ?? ?? ????????Hashtable?hs?=?new?Hashtable(); ?? ?? ?????????? ?? ???????hs.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap. ? ????????????LdapCtxFactory"); ?? ?? ?????????? ?? ????????hs.put(Context.PROVIDER_URL,"ldap://localhost:389"); ?? ?? ?????????? ?? ????????hs.put(Context.SECURITY_AUTHENTICATION,"simple");? ?? ?? ????????hs.put(Context.SECURITY_PRINCIPAL,"uid=Jordan,ou=Bull,o=NBA");? ?? ?? ????????hs.put(Context.SECURITY_CREDENTIALS,"good"); ?? ?? ????????try?{ ?? ?? ???????????? ? ?? ?? ???????????DirContext?ctx?=?new?InitialDirContext(hs); ?? ?? ???????????System.out.println("成功創建初始化context對象!"); ?? ?? ???????????????? ?? ???????????ModificationItem[]?mdi?=?new?ModificationItem[2]; ?? ?? ???????????????? ?? ???????????Attribute?att0?=?new?BasicAttribute("mail", ?? ???????????????"jordan@163.com"); ?? ?? ???????????????? ?? ???????????Attribute?att1?=?new?BasicAttribute("call","12745827"); ?? ?? ??????????????? ?? ???????????mdi[0]=new?ModificationItem(DirContext.REPLACE_ATTRIBUTE, ?? ???????????????att0);? ?? ?? ?????????????? ?? ???????????mdi[1]=new?ModificationItem(DirContext.ADD_ATTRIBUTE,att1);? ?? ?? ?????????????? ?? ???????????ctx.modifyAttributes("uid=Jordan,ou=Bull,o=NBA",mdi); ?? ?? ????????}catch(Exception?ex?){ ?? ?? ???????????ex.printStackTrace(); ?? ?? ???????????System.exit(1); ?? ?? ????????} ?? ?? ????} ?? ?? } ?? ??
上面程序的作用是修改前面例子中增加的DN為uid = Jordan,ou = Bull,o = NBA條目的屬性。
在程序中用DirContext.REPLACE_ATTRIBUTE來修改條目的mail屬性,在這里如果原來的mail屬性有多個值時,都會被刪掉,取而代之的是新賦的值。用DirContext. REPLACE_ATTRIBUTE時,如果原來的屬性(mail)不存在時,就增加一個屬性,有則修改。
用DirContext.ADD_ATTRIBUTE來將一個新屬性增加到條目。真正起到修改作用的是ctx.modifyAttributes("uid = Jordan,ou = Bull,o = NBA",mdi)這條語句。
2.刪除條目
有時,當開發者不需要某個條目時,就可以把它從LDAP服務器上刪除。這只要通過調用參數為指定DN條目的DirContext接口的destorySubContext()方法來完成。
7 例6-4? 用JNDI刪除LDAP條目。
java 代碼
package?jndi; ?? ?? import?java.nutil.Hashtable; ?? ?? import?javax.naming.Context; ?? ?? import?javax.naming.directory.Attribute; ?? ?? import?javax.naming.directory.Attributes; ?? ?? import?javax.naming.directory.BasicAttribute; ?? ?? import?javax.naming.directory.DirContext; ?? ?? import?javax.naming.directory.InitialDirContext; ?? ?? import?javax.naming.directory.ModificationItem; ?? ?? public?class?jndiPropertyModify?{ ?? ?? ????public?static?void?main(String[]?args){ ?? ?? ????????Hashtable?hs?=?new?Hashtable(); ?? ?? ?????????? ?? ????????hs.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap. ? ????????????LdapCtxFactory"); ?? ?? ??????????? ?? ????????hs.put(Context.PROVIDER_URL,"ldap://localhost:389"); ?? ?? ??????????? ?? ????????hs.put(Context.SECURITY_AUTHENTICATION,"simple");? ?? ?? ?????????? ?? ????????hs.put(Context.SECURITY_PRINCIPAL,"uid=Jordan,ou=Bull,o=NBA");? ?? ?? ?????????? ?? ????????hs.put(Context.SECURITY_CREDENTIALS,"good"); ?? ?? ????????try?{ ?? ?? ???????????? ? ?? ?? ???????????DirContext?ctx?=?new?InitialDirContext(hs); ?? ?? ??????????????? ?? ???????????ctx.destroySubcontext("uid=Jordan,ou=Bull,o=NBA"); ?? ?? ????????}catch(Exception?ex?){ ?? ?? ???????????ex.printStackTrace(); ?? ?? ???????????System.exit(1); ?? ?? ????????} ?? ?? ????} ?? ?? } ??
總結
以上是生活随笔為你收集整理的《精通J2EE网络编程》中讲的JNDI 6.2 使用JNDI的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。