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 2015 ForgeRock AS.
15   */
16  
17  package org.forgerock.opendj.examples;
18  
19  import static org.forgerock.util.Utils.closeSilently;
20  import org.forgerock.i18n.LocalizableMessage;
21  import org.forgerock.opendj.ldap.Connection;
22  import org.forgerock.opendj.ldap.DN;
23  import org.forgerock.opendj.ldap.Entry;
24  import org.forgerock.opendj.ldap.LDAPConnectionFactory;
25  import org.forgerock.opendj.ldap.LdapException;
26  import org.forgerock.opendj.ldap.ResultCode;
27  import org.forgerock.opendj.ldap.requests.Requests;
28  import org.forgerock.opendj.ldap.responses.BindResult;
29  import org.forgerock.opendj.ldap.responses.Result;
30  import org.forgerock.opendj.ldap.schema.Schema;
31  import org.forgerock.opendj.ldap.schema.SchemaValidationPolicy;
32  import org.forgerock.opendj.ldif.LDIFEntryReader;
33  import org.forgerock.util.AsyncFunction;
34  import org.forgerock.util.promise.ExceptionHandler;
35  import org.forgerock.util.promise.Promise;
36  import org.forgerock.util.promise.Promises;
37  import org.forgerock.util.promise.ResultHandler;
38  
39  import java.io.IOException;
40  import java.util.LinkedList;
41  import java.util.List;
42  import java.util.concurrent.CountDownLatch;
43  
44  /**
45   * This example command-line client application validates an entry
46   * against the directory server schema before adding it
47   * using the asynchronous APIs.
48   *
49   * <br>
50   *
51   * This example takes the following command line parameters:
52   *
53   * <pre>
54   *  {@code <host> <port> <bindDN> <bindPassword>}
55   * </pre>
56   *
57   * Then it reads an entry to add from System.in.
58   * If the entry is valid according to the directory schema,
59   * it tries to add the entry to the directory.
60   */
61  public final class UseSchemaAsync {
62      /** Connection to the LDAP server. */
63      private static Connection connection;
64      /** Result for the operation. */
65      private static int resultCode;
66      /** Count down latch to wait for modify operation to complete. */
67      private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1);
68  
69      /**
70       * Main method.
71       *
72       * @param args
73       *            The command line arguments: host, port, bindDN, bindPassword.
74       */
75      public static void main(final String[] args) {
76          if (args.length != 4) {
77              System.err.println("Usage: host port bindDN bindPassword");
78              System.exit(1);
79          }
80  
81          // Parse command line arguments.
82          final String host         = args[0];
83          final int    port         = Integer.parseInt(args[1]);
84          final String bindDn       = args[2];
85          final char[] bindPassword = args[3].toCharArray();
86  
87          // Read an entry from System.in.
88          final Entry entry;
89          try {
90              System.out.println("Enter entry to add in LDIF format:");
91              entry = new LDIFEntryReader(System.in).readEntry();
92          } catch (IOException e) {
93              System.err.println(e.getMessage());
94              System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue());
95              return;
96          }
97          final String entryDn = entry.getName().toString();
98  
99          // Connect, bind, read schema, and add entry if valid according to schema.
100         new LDAPConnectionFactory(host, port)
101                 .getConnectionAsync()
102                 .thenAsync(new AsyncFunction<Connection, BindResult, LdapException>() {
103                     @Override
104                     public Promise<BindResult, LdapException> apply(Connection connection)
105                             throws LdapException {
106                         UseSchemaAsync.connection = connection;
107                         return connection.bindAsync(
108                                 Requests.newSimpleBindRequest(bindDn, bindPassword));
109                     }
110                 })
111                 .thenAsync(new AsyncFunction<BindResult, Schema, LdapException>() {
112                     @Override
113                     public Promise<Schema, LdapException> apply(BindResult bindResult)
114                             throws LdapException {
115                         return Schema.readSchemaForEntryAsync(connection, DN.rootDN());
116                     }
117                 })
118                 .thenAsync(new AsyncFunction<Schema, Result, LdapException>() {
119                     @Override
120                     public Promise<Result, LdapException> apply(Schema schema)
121                             throws LdapException {
122                         final List<LocalizableMessage> schemaErrors = new LinkedList<>();
123                         boolean isValid = schema.validateEntry(
124                                 entry,
125                                 SchemaValidationPolicy.defaultPolicy(),
126                                 schemaErrors);
127                         if (isValid) {
128                             System.out.println("Processing ADD request for " + entryDn);
129                             return connection.addAsync(Requests.newAddRequest(entry));
130                         } else {
131                             for (LocalizableMessage error : schemaErrors) {
132                                 System.err.println(error);
133                             }
134                             return Promises.newExceptionPromise(
135                                     LdapException.newLdapException(
136                                             ResultCode.CLIENT_SIDE_PARAM_ERROR,
137                                             "Entry does not conform to schema."));
138                         }
139                     }
140                 })
141                 .thenOnResult(new ResultHandler<Result>() {
142                     @Override
143                     public void handleResult(Result result) {
144                         System.out.println("ADD operation successful for DN " + entryDn);
145                         resultCode = result.getResultCode().intValue();
146                         COMPLETION_LATCH.countDown();
147                     }
148                 })
149                 .thenOnException(new ExceptionHandler<LdapException>() {
150                     @Override
151                     public void handleException(LdapException e) {
152                         System.err.println(e.getMessage());
153                         resultCode = e.getResult().getResultCode().intValue();
154                         COMPLETION_LATCH.countDown();
155                     }
156                 });
157 
158         try {
159             COMPLETION_LATCH.await();
160         }  catch (InterruptedException e) {
161             System.err.println(e.getMessage());
162             System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue());
163             return;
164         }
165 
166         closeSilently(connection);
167         System.exit(resultCode);
168     }
169 
170     private UseSchemaAsync() {
171         // Not used.
172     }
173 }