jndi step by step (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: Ted.Geisel@JNDITutorial.com
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: Ted.Geisel@JNDITutorial.com
attribute: telephonenumber
value: +1 408 555 5252

    1.2、改变属性

    DirContext 接口有一些改变对象属性的方法。

    1.2.1、批量改变属性
 
    改变属性的方式之一就是批量改变属性,也就是使用许多 ModificationItem 对象来修改属性。
    每个 ModificationItem 对象都会有一个常量,来表示对属性进行什么样的操作。这些常量如下:

ADD_ATTRIBUTE
REPLACE_ATTRIBUTE
REMOVE_ATTRIBUTE

    对属性的改变会按照队列的顺序来执行,要么所有的改变都生效,要么都不生效。
    下面的代码演示了一个例子。它把“mail”这个属性的值,改变成了“geisel@wizards.com”,给“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""geisel@wizards.com"));   
  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: Ted.Geisel@JNDITutorial.com
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 代码
  1. // Specify the ids of the attributes to return   
  2. String[] attrIDs = {"sn""telephonenumber""golfhandicap""mail"};   
  3. SearchControls ctls = new SearchControls();   
  4. ctls.setReturningAttributes(attrIDs);  

 

    1.5 搜索控制
   
    在上面的章节中,我们已经看到了一个类:SearchControls,通过这个类,你可以控制搜索的行为。这里
    我们就来仔细地看看这个类。
 
    1.5.1 搜索范围

    SearchControls 类默认会在整个内容上下文(SearchControls.ONELEVEL_SCOPE)搜索对象,通过设置,你
    可以在某一个范围内搜索对象。

    1.5.1.1 在一个子树上搜索

    通过下面的代码你可以清晰地了解这一功能:

java 代码
  1. // Specify the ids of the attributes to return   
  2. String[] attrIDs = {"sn""telephonenumber""golfhandicap""mail"};   
  3. SearchControls ctls = new SearchControls();   
  4. ctls.setReturningAttributes(attrIDs);   
  5. ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);   
  6.   
  7. // Specify the search filter to match   
  8. // Ask for objects that have the attribute "sn" == "Geisel"   
  9. // and the "mail" attribute   
  10. String filter = "(&(sn=Geisel)(mail=*))";   
  11.   
  12. // Search the subtree for objects by using the filter   
  13. NamingEnumeration answer = ctx.search("", filter, ctls);  

 

    1.5.1.2 根据名字来搜索

    通过下面的代码你可以清晰地了解这一功能:

java 代码
  1. // Specify the ids of the attributes to return   
  2. String[] attrIDs = {"sn""telephonenumber""golfhandicap""mail"};   
  3. SearchControls ctls = new SearchControls();   
  4. ctls.setReturningAttributes(attrIDs);   
  5. ctls.setSearchScope(SearchControls.OBJECT_SCOPE);   
  6.   
  7. // Specify the search filter to match   
  8. // Ask for objects that have the attribute "sn" == "Geisel"   
  9. // and the "mail" attribute   
  10. String filter = "(&(sn=Geisel)(mail=*))";   
  11.   
  12. // Search the subtree for objects by using the filter   
  13. NamingEnumeration answer =    
  14.     ctx.search("cn=Ted Geisel, ou=People", filter, ctls);  

 

    1.5.2 数量的限制

    通过下面的代码你可以控制返回结果的数量:

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

 

    1.5.3 时间的限制

    如果一个搜索耗费了很长的时间,那可不是一个好方法。这里你可以设置超时的时间。

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

 

    参数的单位是毫秒。

    如果发生超时现象,那么就会抛出 TimeLimitExceededException。

    1.6 结合命名服务和目录服务的操作

    我们已经这样的一个概念,就是目录服务是命名服务的一个扩展。例如,之前我们说过命名服务具有 bind(),
    rebind(), createSubcontext() 等方法,但是在目录服务里却没有介绍这些方法。
    其实目录服务里也有这些方法。下面就用 LDAP 作为例子,介绍一下这些方法。

    1.6.1 创建一个具有属性的内容上下文

java 代码
  1. import javax.naming.*;   
  2. import javax.naming.directory.*;   
  3. import java.util.Hashtable;   
  4.   
  5. /**  
  6.   * Demonstrates how to create a new subcontext called "ou=Fruits" with some   
  7.   * attributes.  
  8.   * (Run Destroy after this to remove the subcontext).  
  9.   *  
  10.   * usage: java Create  
  11.   */  
  12. class Create {   
  13.     public static void main(String[] args) {   
  14.   
  15.     // Set up the environment for creating the initial context   
  16.     Hashtable env = new Hashtable(11);   
  17.     env.put(Context.INITIAL_CONTEXT_FACTORY,    
  18.         "com.sun.jndi.ldap.LdapCtxFactory");   
  19.     env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");   
  20.   
  21.     try {   
  22.         // Create the initial context   
  23.         DirContext ctx = new InitialDirContext(env);   
  24.   
  25.         // Create attributes to be associated with the new context   
  26.         Attributes attrs = new BasicAttributes(true); // case-ignore   
  27.         Attribute objclass = new BasicAttribute("objectclass");   
  28.         objclass.add("top");   
  29.         objclass.add("organizationalUnit");   
  30.         attrs.put(objclass);   
  31.   
  32.         // Create the context   
  33.         Context result = ctx.createSubcontext("ou=Fruits", attrs);   
  34.   
  35.         // Check that it was created by listing its parent   
  36.         NamingEnumeration list = ctx.list("");   
  37.   
  38.         // Go through each item in list   
  39.         while (list.hasMore()) {   
  40.         NameClassPair nc = (NameClassPair)list.next();   
  41.         System.out.println(nc);   
  42.         }   
  43.   
  44.         // Close the contexts when we're done   
  45.         result.close();   
  46.         ctx.close();   
  47.     } catch (NamingException e) {   
  48.         System.out.println("Create failed: " + e);   
  49.     }   
  50.     }   
  51. }  

    1.6.2 增加一个具有属性的绑定

java 代码
  1. import javax.naming.*;   
  2. import javax.naming.directory.*;   
  3.   
  4. import java.util.Hashtable;   
  5.   
  6. /**  
  7.   * Demonstrates how to add a binding and its attributes to a context.  
  8.   * (Use Rebind example to overwrite binding; use Unbind to remove binding.)  
  9.   *  
  10.   * usage: java Bind  
  11.   */  
  12.   
  13. class Bind {   
  14.     public static void main(String[] args) {   
  15.   
  16.     // Set up the environment for creating the initial context   
  17.     Hashtable env = new Hashtable(11);   
  18.     env.put(Context.INITIAL_CONTEXT_FACTORY,    
  19.         "com.sun.jndi.ldap.LdapCtxFactory");   
  20.     env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");   
  21.   
  22.     try {   
  23.         // Create the initial context   
  24.         DirContext ctx = new InitialDirContext(env);   
  25.   
  26.         // Create object to be bound   
  27.         Fruit fruit = new Fruit("orange");   
  28.   
  29.         // Create attributes to be associated with object   
  30.         Attributes attrs = new BasicAttributes(true); // case-ignore   
  31.         Attribute objclass = new BasicAttribute("objectclass");   
  32.         objclass.add("top");   
  33.         objclass.add("organizationalUnit");   
  34.         attrs.put(objclass);   
  35.   
  36.         // Perform bind   
  37.         ctx.bind("ou=favorite, ou=Fruits", fruit, attrs);   
  38.   
  39.         // Check that it is bound   
  40.         Object obj = ctx.lookup("ou=favorite, ou=Fruits");   
  41.         System.out.println(obj);   
  42.   
  43.         // Get its attributes   
  44.         Attributes retattrs = ctx.getAttributes("ou=favorite, ou=Fruits");   
  45.         GetattrsAll.printAttrs(retattrs);   
  46.   
  47.         // Close the context when we're done   
  48.         ctx.close();   
  49.     } catch (NamingException e) {   
  50.         System.out.println("Operation failed: " + e);   
  51.     }   
  52.     }   
  53. }  

    1.6.3 替换一个具有属性的绑定

java 代码
  1. import javax.naming.*;   
  2. import javax.naming.directory.*;   
  3.   
  4. import java.util.Hashtable;   
  5.   
  6. /**  
  7.   * Demonstrates how to replace a binding and its attributes to a context.  
  8.   * (Use after Bind example; use Unbind to remove binding.)  
  9.   *  
  10.   * usage: java Rebind  
  11.   */  
  12.   
  13. class Rebind {   
  14.     public static void main(String[] args) {   
  15.   
  16.     // Set up the environment for creating the initial context   
  17.     Hashtable env = new Hashtable(11);   
  18.     env.put(Context.INITIAL_CONTEXT_FACTORY,    
  19.         "com.sun.jndi.ldap.LdapCtxFactory");   
  20.     env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");   
  21.   
  22.     try {   
  23.         // Create the initial context   
  24.         DirContext ctx = new InitialDirContext(env);   
  25.   
  26.         // Create object to be bound   
  27.         Fruit fruit = new Fruit("lemon");   
  28.   
  29.         // Create attributes to be associated with object   
  30.         Attributes attrs = new BasicAttributes(true); // case-ignore   
  31.         Attribute objclass = new BasicAttribute("objectclass");   
  32.         objclass.add("top");   
  33.         objclass.add("organizationalUnit");   
  34.         attrs.put(objclass);   
  35.   
  36.         // Perform bind   
  37.         ctx.rebind("ou=favorite, ou=Fruits", fruit, attrs);   
  38.   
  39.         // Check that it is bound   
  40.         Object obj = ctx.lookup("ou=favorite, ou=Fruits");   
  41.         System.out.println(obj);   
  42.   
  43.         // Get its attributes   
  44.         Attributes retattrs = ctx.getAttributes("ou=favorite, ou=Fruits");   
  45.         GetattrsAll.printAttrs(retattrs);   
  46.   
  47.         // Close the context when we're done   
  48.         ctx.close();   
  49.     } catch (NamingException e) {   
  50.         System.out.println("Operation failed: " + e);   
  51.     }   
  52.     }   
  53. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值