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-2016 ForgeRock AS.
15   */
16  package org.forgerock.opendj.examples;
17  
18  import java.io.IOException;
19  import java.util.Arrays;
20  import java.util.concurrent.CountDownLatch;
21  
22  import org.forgerock.opendj.ldap.Connection;
23  import org.forgerock.opendj.ldap.LDAPConnectionFactory;
24  import org.forgerock.opendj.ldap.LdapException;
25  import org.forgerock.opendj.ldap.LdapPromise;
26  import org.forgerock.opendj.ldap.ResultCode;
27  import org.forgerock.opendj.ldap.SearchResultHandler;
28  import org.forgerock.opendj.ldap.SearchScope;
29  import org.forgerock.opendj.ldap.requests.CancelExtendedRequest;
30  import org.forgerock.opendj.ldap.requests.Requests;
31  import org.forgerock.opendj.ldap.responses.BindResult;
32  import org.forgerock.opendj.ldap.responses.ExtendedResult;
33  import org.forgerock.opendj.ldap.responses.Result;
34  import org.forgerock.opendj.ldap.responses.SearchResultEntry;
35  import org.forgerock.opendj.ldap.responses.SearchResultReference;
36  import org.forgerock.opendj.ldif.LDIFEntryWriter;
37  import org.forgerock.util.AsyncFunction;
38  import org.forgerock.util.promise.ExceptionHandler;
39  import org.forgerock.util.promise.Promise;
40  import org.forgerock.util.promise.ResultHandler;
41  
42  /**
43   * An example client application which searches a Directory Server using the
44   * asynchronous APIs. This example takes the following command line parameters:
45   *
46   * <pre>
47   *  {@code <host> <port> <username> <password>
48   *      <baseDN> <scope> <filter> [<attribute> <attribute> ...]}
49   * </pre>
50   */
51  public final class SearchAsync {
52      // --- JCite search result handler ---
53      private static final class SearchResultHandlerImpl implements SearchResultHandler {
54          @Override
55          public synchronized boolean handleEntry(final SearchResultEntry entry) {
56              try {
57                  if (entryCount < 10) {
58                      WRITER.writeComment("Search result entry: " + entry.getName());
59                      WRITER.writeEntry(entry);
60                      ++entryCount;
61                  } else { // Cancel the search.
62                      CancelExtendedRequest request =
63                              Requests.newCancelExtendedRequest(requestID);
64                      connection.extendedRequestAsync(request)
65                              .thenOnResult(new ResultHandler<ExtendedResult>() {
66                                  @Override
67                                  public void handleResult(ExtendedResult result) {
68                                      System.err.println("Cancel request succeeded");
69                                      CANCEL_LATCH.countDown();
70                                  }
71                              })
72                              .thenOnException(new ExceptionHandler<LdapException>() {
73                                  @Override
74                                  public void handleException(LdapException exception) {
75                                      System.err.println("Cancel request failed: "
76                                              + exception.getResult().getResultCode().intValue()
77                                              + " "
78                                              + exception.getResult().getDiagnosticMessage());
79                                      CANCEL_LATCH.countDown();
80                                  }
81                              });
82                      return false;
83                  }
84              } catch (final IOException e) {
85                  System.err.println(e.getMessage());
86                  resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue();
87                  COMPLETION_LATCH.countDown();
88                  return false;
89              }
90              return true;
91          }
92  
93          @Override
94          public synchronized boolean handleReference(final SearchResultReference reference) {
95              try {
96                  WRITER.writeComment("Search result reference: " + reference.getURIs());
97              } catch (final IOException e) {
98                  System.err.println(e.getMessage());
99                  resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue();
100                 COMPLETION_LATCH.countDown();
101                 return false;
102             }
103             return true;
104         }
105 
106     }
107     // --- JCite search result handler ---
108 
109     // --- JCite decl1 ---
110     private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1);
111     private static final CountDownLatch CANCEL_LATCH = new CountDownLatch(1);
112     private static final LDIFEntryWriter WRITER = new LDIFEntryWriter(System.out);
113     // --- JCite decl1 ---
114     private static String userName;
115     private static String password;
116     private static String baseDN;
117     private static SearchScope scope;
118     private static String filter;
119     private static String[] attributes;
120     private static Connection connection;
121     private static int resultCode;
122 
123     // --- JCite decl2 ---
124     static int requestID;
125     static int entryCount;
126     // --- JCite decl2 ---
127 
128     /**
129      * Main method.
130      *
131      * @param args
132      *            The command line arguments: host, port, username, password,
133      *            base DN, scope, filter, and zero or more attributes to be
134      *            retrieved.
135      */
136     public static void main(final String[] args) {
137         if (args.length < 7) {
138             System.err.println("Usage: host port username password baseDN scope " + "filter [attribute ...]");
139             System.exit(1);
140         }
141 
142         // Parse command line arguments.
143         final String hostName = args[0];
144         final int port = Integer.parseInt(args[1]);
145         userName = args[2];
146         password = args[3];
147         baseDN = args[4];
148         final String scopeString = args[5];
149         filter = args[6];
150         if (args.length > 7) {
151             attributes = Arrays.copyOfRange(args, 7, args.length);
152         } else {
153             attributes = new String[0];
154         }
155 
156         scope = SearchScope.valueOf(scopeString);
157         if (scope == null) {
158             System.err.println("Unknown scope: " + scopeString);
159             System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue());
160             return;
161         }
162 
163         // --- Using Promises ---
164         // Initiate the asynchronous connect, bind, and search.
165         final LDAPConnectionFactory factory = new LDAPConnectionFactory(hostName, port);
166 
167         factory.getConnectionAsync()
168                 .thenAsync(new AsyncFunction<Connection, BindResult, LdapException>() {
169                     @Override
170                     public Promise<BindResult, LdapException> apply(Connection connection)
171                             throws LdapException {
172                         SearchAsync.connection = connection;
173                         return connection.bindAsync(Requests
174                                 .newSimpleBindRequest(userName, password.toCharArray()));
175                     }
176                 })
177                 .thenAsync(new AsyncFunction<BindResult, Result, LdapException>() {
178                     @Override
179                     public Promise<Result, LdapException> apply(BindResult result)
180                             throws LdapException {
181                         LdapPromise<Result> promise = connection.searchAsync(
182                                 Requests.newSearchRequest(baseDN, scope, filter, attributes),
183                                 new SearchResultHandlerImpl());
184                         requestID = promise.getRequestID();
185                         return promise;
186                     }
187                 })
188                 .thenOnResult(new ResultHandler<Result>() {
189                     @Override
190                     public void handleResult(Result result) {
191                         resultCode = result.getResultCode().intValue();
192                         COMPLETION_LATCH.countDown();
193                     }
194                 })
195                 .thenOnException(new ExceptionHandler<LdapException>() {
196                     @Override
197                     public void handleException(LdapException exception) {
198                         System.err.println(exception.getMessage());
199                         resultCode = exception.getResult().getResultCode().intValue();
200                         COMPLETION_LATCH.countDown();
201                     }
202                 });
203         // --- Using Promises ---
204 
205         // Await completion.
206         try {
207             COMPLETION_LATCH.await();
208         } catch (final InterruptedException e) {
209             System.err.println(e.getMessage());
210             System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue());
211             return;
212         }
213 
214         try {
215             WRITER.flush();
216         } catch (final IOException e) {
217             System.err.println(e.getMessage());
218             System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue());
219             return;
220         }
221 
222         // Await completion of the cancel request.
223         try {
224             CANCEL_LATCH.await();
225         } catch (final InterruptedException e) {
226             System.err.println(e.getMessage());
227             System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue());
228             return;
229         }
230 
231         if (connection != null) {
232             connection.close();
233         }
234 
235         System.exit(resultCode);
236     }
237 
238     private SearchAsync() {
239         // Not used.
240     }
241 }