View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions Copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2012-2014 ForgeRock AS.
15   */
16  
17  package org.forgerock.opendj.examples;
18  
19  import java.util.Collection;
20  
21  import org.forgerock.opendj.ldap.Connection;
22  import org.forgerock.opendj.ldap.LdapException;
23  import org.forgerock.opendj.ldap.LDAPConnectionFactory;
24  import org.forgerock.opendj.ldap.ModificationType;
25  import org.forgerock.opendj.ldap.ResultCode;
26  import org.forgerock.opendj.ldap.RootDSE;
27  import org.forgerock.opendj.ldap.controls.PermissiveModifyRequestControl;
28  import org.forgerock.opendj.ldap.requests.CompareRequest;
29  import org.forgerock.opendj.ldap.requests.ModifyRequest;
30  import org.forgerock.opendj.ldap.requests.Requests;
31  import org.forgerock.opendj.ldap.responses.CompareResult;
32  
33  /**
34   * This command-line client demonstrates adding and removing a member from a
35   * (potentially large) static group.
36   *
37   * The client takes as arguments the host and port of the directory server, the
38   * group DN, the member DN, and whether to "add" or "del" the specified member
39   * from the group. The client uses the Permissive Modify control if it is
40   * available to avoid having to check whether the member belongs to the group or
41   * not.
42   *
43   * This client expects a group that is a <code>groupOfNames</code> such as:
44   *
45   * <pre>
46   * dn: cn=My Static Group,ou=Groups,dc=example,dc=com
47   * cn: My Static Group
48   * objectClass: groupOfNames
49   * objectClass: top
50   * ou: Groups
51   * member: uid=ahunter,ou=People,dc=example,dc=com
52   * member: uid=bjensen,ou=People,dc=example,dc=com
53   * member: uid=tmorris,ou=People,dc=example,dc=com
54   * </pre>
55   *
56   * This client connects as <code>cn=Directory Manager</code> with password
57   * <code>password</code>. Not a best practice; in real code use application
58   * specific credentials to connect, and ensure that your application has access
59   * to use the Permissive Modify control if your directory server supports it.
60   */
61  public final class UpdateGroup {
62  
63      /**
64       * Connect to the directory server to update the group.
65       *
66       * @param args
67       *            The command line arguments: host, port, group-dn, member-dn,
68       *            {add|del}
69       */
70      public static void main(String[] args) {
71          if (args.length != 5) {
72              printUsage();
73          }
74          final String host = args[0];
75          final int port = Integer.parseInt(args[1]);
76          final String groupDN = args[2];
77          final String memberDN = args[3];
78          final ModificationType modType = getModificationType(args[4]);
79  
80          final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port);
81          Connection connection = null;
82          try {
83              connection = factory.getConnection();
84  
85              Collection<String> controls =
86                      RootDSE.readRootDSE(connection).getSupportedControls();
87  
88              final String user = "cn=Directory Manager";
89              final char[] password = "password".toCharArray();
90              connection.bind(user, password);
91  
92              // --- JCite permissive ---
93              if (controls.contains(PermissiveModifyRequestControl.OID)) {
94  
95                  final ModifyRequest request = Requests.newModifyRequest(groupDN)
96                          .addControl(PermissiveModifyRequestControl.newControl(true))
97                          .addModification(modType, "member", memberDN);
98                  connection.modify(request);
99  
100             } else {
101                 // --- JCite permissive ---
102 
103                 // --- JCite without permissive ---
104                 System.out.println("Checking whether the entry with DN "
105                         + memberDN + " belongs to the group with DN " + groupDN
106                         + "...");
107                 final CompareRequest request =
108                         Requests.newCompareRequest(groupDN, "member", memberDN);
109                 CompareResult result = connection.compare(request);
110 
111                 if (modType == ModificationType.ADD
112                         && result.getResultCode() == ResultCode.COMPARE_FALSE) {
113                     System.out.println("Member does not yet belong to group."
114                             + " Adding it...");
115                     final ModifyRequest addMember =
116                             Requests.newModifyRequest(groupDN)
117                                 .addModification(modType, "member", memberDN);
118                     connection.modify(addMember);
119                 }
120 
121                 if (modType == ModificationType.DELETE
122                         && result.getResultCode() == ResultCode.COMPARE_TRUE) {
123                     System.out.println("Member belongs to group."
124                             + " Removing it...");
125                     final ModifyRequest delMember =
126                             Requests.newModifyRequest(groupDN)
127                                 .addModification(modType, "member", memberDN);
128                     connection.modify(delMember);
129                 }
130                 // --- JCite without permissive ---
131             }
132 
133             String op = (modType == ModificationType.ADD) ? "added to" : "deleted from";
134             System.out.println("The entry with DN " + memberDN + " has been "
135                     + op + " the group with DN " + groupDN + ".");
136 
137         } catch (final LdapException e) {
138             System.err.println(e.getMessage());
139             System.exit(e.getResult().getResultCode().intValue());
140             return;
141         } finally {
142             if (connection != null) {
143                 connection.close();
144             }
145         }
146     }
147 
148     /**
149      * Return the modification type for the update operation.
150      * @param operation Operation specified as an argument (add or del).
151      */
152     private static ModificationType getModificationType(String operation) {
153         final boolean isAdd = "add".equalsIgnoreCase(operation);
154         if (!isAdd && !"del".equalsIgnoreCase(operation)) {
155             printUsage();
156         }
157         return isAdd ? ModificationType.ADD : ModificationType.DELETE;
158     }
159 
160     /**
161      * Print usage then exit.
162      */
163     private static void printUsage() {
164         System.err.println("Usage: host port group-dn member-dn {add|del}");
165         System.err.println("For example: localhost 1389 "
166                 + "cn=Static,ou=Groups,dc=example,dc=com "
167                 + "uid=user.5150,ou=People,dc=example,dc=com "
168                 + "del");
169         System.exit(1);
170     }
171 
172     /**
173      * Constructor not used.
174      */
175     private UpdateGroup() {
176         // Not used.
177     }
178 }