JNDI操作步驟
使用JNDI來通路命名服務或者目錄服務,操作步驟如下:
(1)建立一個散清單(hashtable),它包含定義所希望使用的JNDI服務的屬性,所希望連接配接的LDAP伺服器IP位址以及工作的端口。
(2)将與認證成為使用者登入有關的任何資訊添加到散清單中。
(3)建立初始context對象。如果通路命名服務,則使用InitialContext類,如果通路目錄服務,則要使用InitialDirContext類。
(4)使用剛才得到的context對象執行所需的操作(如添加新的條目或者搜尋條目)。
(5)完成操作後關閉context對象。
JNDI允許存儲的對象類型
JNDI最大的功能是能使用LDAP來存儲需要在不同應用之間共享或者留做備用的對象。JNDI允許将下面幾種與Java相關的對象類型存儲到LDAP伺服器内。
(1)串行化的Java對象。這是存儲和取回已經串行化的Java對象的能力。也就是 說要存儲的Java對象必須要實作Referenceable或Serializable接口類,否則該對象不能存儲。
(2)标準的LDAP目錄條目。它提供了操作标準目錄資料的能力。标準目錄資料的資料量比較小,可以在不同的語言之間共享它們。保持目錄資料與程式設計語言的無關性對于要使用幾種不同語言進行開發的大企業裡是非常重要的。
(3)指向RMI Java對象的指針。RMI是用于分布式計算的,通過RMI,一個Java應用可以像本地一樣調用一個遠端類的方法。我們可以把一個可用的RMI類的引用存儲在開發者的LDAP伺服器中,而不必在每個裝有RMI客戶應用的計算機上都保持可用方法的注冊。
JNDI存儲查詢串行化的Java對象
JNDI的主要目标是在網絡上讀/寫Java對象。下面用具體執行個體來了解怎麼使用JNDI。首先通過一個例子來講解怎麼樣在LDAP中儲存串行化的Java對象資料,再用一個例子來說明怎麼對儲存的對象資料進行查詢、調用。
1.儲存資料
在LDAP中儲存資料就是在LDAP伺服器中添加使用條目,也就是把條目綁定在伺服器中。下面先建立一個基本類,再在另一個類中利用JNDI把這個基本類綁定在伺服器中。
4 例6-1 在LDAP中儲存資料。
(1)待綁定的基本類
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;
}
//用于傳回變量Name的值
public String getName() {
return Name;
}
//用于傳回變量Age的值
public String getAge () {
return Age;
}
}
JNDI 定義了一個Serializable接口類來為應用資訊的表達提供一種統一的方式。Serializable接口類包含了諸如位址、類型資訊等用于通路具體對象的資訊。為了能将對象的引用綁定到目錄樹中,該對象的類必須實作Referenceable接口,其中包含了方法 getReference()。開發者可以在該對象上調用getReference()方法來獲得Reference以用于綁定。 Serializable接口與Referenceable接口有頗多相似之處,不同在于Referenceable可引用的對象隻包含一些用于建立實際對象的資訊,而Serializable會包含更多的甚至不适合存儲在目錄結構中的資訊。
(2)綁定儲存對象程式
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以存儲JNDI将用于連接配接目錄服務的環境變量
Hashtable hs = new Hashtable();
//設定連接配接LDAP的實作工廠
hs.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
// 指定LDAP伺服器的主機名和端口号
hs.put(Context.PROVIDER_URL, "ldap://localhost:389 ");
//給環境提供認證方法,有SIMPLE、SSL/TLS和SASL
hs.put(Context.SECURITY_AUTHENTICATION, "simple");
//指定進入的目錄識别名DN
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);
/*建立一個屬性,其屬性名為"mail"*/
Attribute personMail = new BasicAttribute("mail");
//設定屬性"mail"的值為"[email protected]"、"[email protected]"、
"[email protected]"
personMail.add("[email protected]");
personMail.add("[email protected]");
personMail.add("[email protected]");
attrs.put(personMail);
/*建立一個屬性,其屬性名為"uid",值為001*/
attrs.put("uid","001");
/*建立一個屬性,其屬性名為"cn",值為jordan1*/
attrs.put("cn","jordan1");
/*建立一個屬性,其屬性名為"sn",值為NBA */
attrs.put("sn","NBA");
/*建立一個屬性,其屬性名為"ou",值為bull */
attrs.put("ou","bull");
System.out.println("bind object object success " );
/* 在識别名為DN的目錄中增加一個條目*/
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查找綁定的對象和資料,查找出來後,再調用該對象。程式如下所示。
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以存儲JNDI将用于連接配接目錄服務的環境變量
Hashtable hs = new Hashtable();
//設定連接配接Ldap的實作工廠
hs.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
// 指定LDAP伺服器IP位址為本機及端口号為389
hs.put(Context.PROVIDER_URL, "ldap://localhost:389");
try {
// 得到初始目錄環境的一個引用
DirContext ctx = new InitialDirContext(hs);
//利用lookup查找傳回指定DN的條目對象
persons pers =(persons)ctx.lookup("uid=Jordan,ou=Bull,o=NBA");
// 利用遠端對象調用遠端方法,傳回Age變量的值
String age = pers.getAge();
// 利用遠端對象調用遠端方法,傳回Name變量的值
String name = pers.getName();
//輸出Name的值
System.out.println("name is :" + name );
/*根據結點的DN來查找它的所有屬性, 然後再從屬性中得到所有的值,注意一個屬性可
以有多個值*/
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内部完成了。
JNDI查詢修改LDAP目錄條目
前面已經介紹了如何在LDAP伺服器裡存儲一個對象:主要是利用一個DN将對象綁定到LDAP伺服器中,然後用lookup(DN)查找定位到綁定的對象,再對該對象進行操作。但是往往使用DN查找非常難,使用者很難記住DN,是以我們可以使用其他屬性(比如CN=Cherry)來檢索包含那個屬性的條目。下面來介紹JNDI中相關屬性檢索的具體使用。
1.修改條目
很多時候可能要對LDAP伺服器上的條目進行修改,如修改使用者密碼,更新應用的配置等。但修改必須由一個已認證過的使用者來執行,而且通常隻能修改自己的密碼而不能修改其他資訊,管理助手能夠修改電話号碼和郵件位址,而修改使用者辨別這種工作由資料庫管理者完成。
6 例6-3 用JNDI修改LDAP條目。
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();
//設定連接配接LDAP的實作工廠為com.sun.jndi.ldap.LdapCtxFactory
hs.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.
LdapCtxFactory");
//指定提供服務的伺服器IP位址和端口号
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 {
/*指定了JNDI服務提供者中工廠類(factory class)的名稱。Factory負
責為其服務建立适當的InitialContext對象。在上面的代碼片斷中,為檔案
系統服務提供者指定了工廠類*/
DirContext ctx = new InitialDirContext(hs);
System.out.println("成功建立初始化context對象!");
//建立生成一個修改條目類對象,用于存放條目屬性
ModificationItem[] mdi = new ModificationItem[2];
// 把屬性mail的值置為[email protected]
Attribute att0 = new BasicAttribute("mail",
"[email protected]");
// 把屬性call的值置為12745827
Attribute att1 = new BasicAttribute("call","12745827");
//修改指定屬性mail
mdi[0]=new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
att0);
//增加新屬性call到條目
mdi[1]=new ModificationItem(DirContext.ADD_ATTRIBUTE,att1);
// 修改指定DN條目的屬性
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條目。
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();
//設定連接配接LDAP的實作工廠為com.sun.jndi.ldap.LdapCtxFactory
hs.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.
LdapCtxFactory");
//指定提供服務的伺服器IP位址和端口号
hs.put(Context.PROVIDER_URL,"ldap://localhost:389");
//使用簡單認證來認證使用者
hs.put(Context.SECURITY_AUTHENTICATION,"simple");
// 指定DN
hs.put(Context.SECURITY_PRINCIPAL,"uid=Jordan,ou=Bull,o=NBA");
// 指定認證密碼
hs.put(Context.SECURITY_CREDENTIALS,"good");
try {
/*指定了JNDI服務提供者中工廠類(factory class)的名稱。Factory負
責為其服務建立适當的InitialContext對象。在上面的代碼片斷中,為檔案
系統服務提供者指定了工廠類*/
DirContext ctx = new InitialDirContext(hs);
//删除指定DN條目
ctx.destroySubcontext("uid=Jordan,ou=Bull,o=NBA");
}catch(Exception ex ){
ex.printStackTrace();
System.exit(1);
}
}
}