View Javadoc

1   /*
2    * CDDL HEADER START
3    *
4    * The contents of this file are subject to the terms of the
5    * Common Development and Distribution License, Version 1.0 only
6    * (the "License").  You may not use this file except in compliance
7    * with the License.
8    *
9    * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
10   * or http://forgerock.org/license/CDDLv1.0.html.
11   * See the License for the specific language governing permissions
12   * and limitations under the License.
13   *
14   * When distributing Covered Code, include this CDDL HEADER in each
15   * file and include the License file at legal-notices/CDDLv1_0.txt.
16   * If applicable, add the following below this CDDL HEADER, with the
17   * fields enclosed by brackets "[]" replaced with your own identifying
18   * information:
19   *      Portions Copyright [yyyy] [name of copyright owner]
20   *
21   * CDDL HEADER END
22   *
23   *
24   *      Copyright 2009-2010 Sun Microsystems, Inc.
25   *      Portions copyright 2011-2012 ForgeRock AS
26   */
27  
28  package org.forgerock.opendj.examples;
29  
30  import java.io.IOException;
31  import java.util.Arrays;
32  import java.util.concurrent.CountDownLatch;
33  
34  import org.forgerock.opendj.ldap.Connection;
35  import org.forgerock.opendj.ldap.ErrorResultException;
36  import org.forgerock.opendj.ldap.FutureResult;
37  import org.forgerock.opendj.ldap.LDAPConnectionFactory;
38  import org.forgerock.opendj.ldap.ResultCode;
39  import org.forgerock.opendj.ldap.ResultHandler;
40  import org.forgerock.opendj.ldap.SearchResultHandler;
41  import org.forgerock.opendj.ldap.SearchScope;
42  import org.forgerock.opendj.ldap.requests.BindRequest;
43  import org.forgerock.opendj.ldap.requests.CancelExtendedRequest;
44  import org.forgerock.opendj.ldap.requests.Requests;
45  import org.forgerock.opendj.ldap.requests.SearchRequest;
46  import org.forgerock.opendj.ldap.responses.BindResult;
47  import org.forgerock.opendj.ldap.responses.ExtendedResult;
48  import org.forgerock.opendj.ldap.responses.Result;
49  import org.forgerock.opendj.ldap.responses.SearchResultEntry;
50  import org.forgerock.opendj.ldap.responses.SearchResultReference;
51  import org.forgerock.opendj.ldif.LDIFEntryWriter;
52  
53  /**
54   * An example client application which searches a Directory Server using the
55   * asynchronous APIs. This example takes the following command line parameters:
56   *
57   * <pre>
58   *  &lt;host> &lt;port> &lt;username> &lt;password>
59   *      &lt;baseDN> &lt;scope> &lt;filter> [&lt;attibute> &lt;attribute> ...]
60   * </pre>
61   */
62  public final class SearchAsync {
63      private static final class BindResultHandlerImpl implements ResultHandler<BindResult> {
64  
65          /**
66           * {@inheritDoc}
67           */
68          @Override
69          public void handleErrorResult(final ErrorResultException error) {
70              System.err.println(error.getMessage());
71              resultCode = error.getResult().getResultCode().intValue();
72              COMPLETION_LATCH.countDown();
73          }
74  
75          /**
76           * {@inheritDoc}
77           */
78          @Override
79          public void handleResult(final BindResult result) {
80              // Bind succeeded: initiate search.
81              final SearchRequest request =
82                      Requests.newSearchRequest(baseDN, scope, filter, attributes);
83              final FutureResult<Result> futureResult =
84                      connection.searchAsync(request, null, new SearchResultHandlerImpl());
85              requestID = futureResult.getRequestID();
86          }
87  
88      }
89  
90      private static final class ConnectResultHandlerImpl implements ResultHandler<Connection> {
91  
92          /**
93           * {@inheritDoc}
94           */
95          @Override
96          public void handleErrorResult(final ErrorResultException error) {
97              System.err.println(error.getMessage());
98              resultCode = error.getResult().getResultCode().intValue();
99              COMPLETION_LATCH.countDown();
100         }
101 
102         /**
103          * {@inheritDoc}
104          */
105         @Override
106         public void handleResult(final Connection connection) {
107             // Connect succeeded: save connection and initiate bind.
108             SearchAsync.connection = connection;
109 
110             final BindRequest request =
111                     Requests.newSimpleBindRequest(userName, password.toCharArray());
112             connection.bindAsync(request, null, new BindResultHandlerImpl());
113         }
114 
115     }
116 
117     private static final class SearchResultHandlerImpl implements SearchResultHandler {
118 
119         /**
120          * {@inheritDoc}
121          */
122         @Override
123         public synchronized boolean handleEntry(final SearchResultEntry entry) {
124             try {
125                 if (entryCount < 10) {
126                     WRITER.writeComment("Search result entry: " + entry.getName().toString());
127                     WRITER.writeEntry(entry);
128                     ++entryCount;
129                 } else { // Cancel the search.
130                     CancelExtendedRequest request = Requests.newCancelExtendedRequest(requestID);
131                     connection.extendedRequestAsync(request, null, new CancelResultHandlerImpl());
132                     return false;
133                 }
134             } catch (final IOException e) {
135                 System.err.println(e.getMessage());
136                 resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue();
137                 COMPLETION_LATCH.countDown();
138                 return false;
139             }
140             return true;
141         }
142 
143         /**
144          * {@inheritDoc}
145          */
146         @Override
147         public void handleErrorResult(final ErrorResultException error) {
148             System.err.println(error.getMessage());
149             resultCode = error.getResult().getResultCode().intValue();
150             COMPLETION_LATCH.countDown();
151         }
152 
153         /**
154          * {@inheritDoc}
155          */
156         @Override
157         public synchronized boolean handleReference(final SearchResultReference reference) {
158             try {
159                 WRITER.writeComment("Search result reference: " + reference.getURIs().toString());
160             } catch (final IOException e) {
161                 System.err.println(e.getMessage());
162                 resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue();
163                 COMPLETION_LATCH.countDown();
164                 return false;
165             }
166             return true;
167         }
168 
169         /**
170          * {@inheritDoc}
171          */
172         @Override
173         public void handleResult(final Result result) {
174             resultCode = result.getResultCode().intValue();
175             COMPLETION_LATCH.countDown();
176         }
177 
178     }
179 
180     private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1);
181     private static final CountDownLatch CANCEL_LATCH = new CountDownLatch(1);
182     private static final LDIFEntryWriter WRITER = new LDIFEntryWriter(System.out);
183     private static String userName;
184     private static String password;
185     private static String baseDN;
186     private static SearchScope scope;
187     private static String filter;
188     private static String[] attributes;
189     private static Connection connection = null;
190     private static int resultCode = 0;
191 
192     static int requestID;
193     static int entryCount = 0;
194 
195     private static final class CancelResultHandlerImpl implements ResultHandler<ExtendedResult> {
196 
197         @Override
198         public void handleErrorResult(final ErrorResultException error) {
199             System.err.println("Cancel request failed with result code: "
200                     + error.getResult().getResultCode().intValue());
201             CANCEL_LATCH.countDown();
202         }
203 
204         @Override
205         public void handleResult(final ExtendedResult result) {
206             System.err.println("Cancel request succeeded");
207             CANCEL_LATCH.countDown();
208         }
209 
210     }
211 
212     /**
213      * Main method.
214      *
215      * @param args
216      *            The command line arguments: host, port, username, password,
217      *            base DN, scope, filter, and zero or more attributes to be
218      *            retrieved.
219      */
220     public static void main(final String[] args) {
221         if (args.length < 7) {
222             System.err.println("Usage: host port username password baseDN scope "
223                     + "filter [attribute ...]");
224             System.exit(1);
225         }
226 
227         // Parse command line arguments.
228         final String hostName = args[0];
229         final int port = Integer.parseInt(args[1]);
230         userName = args[2];
231         password = args[3];
232         baseDN = args[4];
233         final String scopeString = args[5];
234         filter = args[6];
235         if (args.length > 7) {
236             attributes = Arrays.copyOfRange(args, 7, args.length);
237         } else {
238             attributes = new String[0];
239         }
240 
241         if (scopeString.equalsIgnoreCase("base")) {
242             scope = SearchScope.BASE_OBJECT;
243         } else if (scopeString.equalsIgnoreCase("one")) {
244             scope = SearchScope.SINGLE_LEVEL;
245         } else if (scopeString.equalsIgnoreCase("sub")) {
246             scope = SearchScope.WHOLE_SUBTREE;
247         } else if (scopeString.equalsIgnoreCase("subordinates")) {
248             scope = SearchScope.SUBORDINATES;
249         } else {
250             System.err.println("Unknown scope: " + scopeString);
251             System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue());
252             return;
253         }
254 
255         // Initiate the asynchronous connect, bind, and search.
256         final LDAPConnectionFactory factory = new LDAPConnectionFactory(hostName, port);
257         factory.getConnectionAsync(new ConnectResultHandlerImpl());
258 
259         // Await completion.
260         try {
261             COMPLETION_LATCH.await();
262         } catch (final InterruptedException e) {
263             System.err.println(e.getMessage());
264             System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue());
265             return;
266         }
267 
268         try {
269             WRITER.flush();
270         } catch (final IOException e) {
271             System.err.println(e.getMessage());
272             System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue());
273             return;
274         }
275 
276         // Await completion of the cancel request.
277         try {
278             CANCEL_LATCH.await();
279         } catch (final InterruptedException e) {
280             System.err.println(e.getMessage());
281             System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue());
282             return;
283         }
284 
285         if (connection != null) {
286             connection.close();
287         }
288 
289         System.exit(resultCode);
290     }
291 
292     private SearchAsync() {
293         // Not used.
294     }
295 }