001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2015 ForgeRock AS. 025 */ 026package org.forgerock.opendj.examples; 027 028import java.io.IOException; 029import java.util.Arrays; 030import java.util.concurrent.CountDownLatch; 031 032import org.forgerock.opendj.ldap.Connection; 033import org.forgerock.opendj.ldap.LDAPConnectionFactory; 034import org.forgerock.opendj.ldap.LdapException; 035import org.forgerock.opendj.ldap.LdapPromise; 036import org.forgerock.opendj.ldap.ResultCode; 037import org.forgerock.opendj.ldap.SearchResultHandler; 038import org.forgerock.opendj.ldap.SearchScope; 039import org.forgerock.opendj.ldap.requests.CancelExtendedRequest; 040import org.forgerock.opendj.ldap.requests.Requests; 041import org.forgerock.opendj.ldap.responses.BindResult; 042import org.forgerock.opendj.ldap.responses.ExtendedResult; 043import org.forgerock.opendj.ldap.responses.Result; 044import org.forgerock.opendj.ldap.responses.SearchResultEntry; 045import org.forgerock.opendj.ldap.responses.SearchResultReference; 046import org.forgerock.opendj.ldif.LDIFEntryWriter; 047import org.forgerock.util.AsyncFunction; 048import org.forgerock.util.promise.ExceptionHandler; 049import org.forgerock.util.promise.Promise; 050import org.forgerock.util.promise.ResultHandler; 051 052/** 053 * An example client application which searches a Directory Server using the 054 * asynchronous APIs. This example takes the following command line parameters: 055 * 056 * <pre> 057 * {@code <host> <port> <username> <password> 058 * <baseDN> <scope> <filter> [<attribute> <attribute> ...]} 059 * </pre> 060 */ 061public final class SearchAsync { 062 // --- JCite search result handler --- 063 private static final class SearchResultHandlerImpl implements SearchResultHandler { 064 /** {@inheritDoc} */ 065 @Override 066 public synchronized boolean handleEntry(final SearchResultEntry entry) { 067 try { 068 if (entryCount < 10) { 069 WRITER.writeComment("Search result entry: " + entry.getName()); 070 WRITER.writeEntry(entry); 071 ++entryCount; 072 } else { // Cancel the search. 073 CancelExtendedRequest request = 074 Requests.newCancelExtendedRequest(requestID); 075 connection.extendedRequestAsync(request) 076 .thenOnResult(new ResultHandler<ExtendedResult>() { 077 @Override 078 public void handleResult(ExtendedResult result) { 079 System.err.println("Cancel request succeeded"); 080 CANCEL_LATCH.countDown(); 081 } 082 }) 083 .thenOnException(new ExceptionHandler<LdapException>() { 084 @Override 085 public void handleException(LdapException exception) { 086 System.err.println("Cancel request failed: " 087 + exception.getResult().getResultCode().intValue() 088 + " " 089 + exception.getResult().getDiagnosticMessage()); 090 CANCEL_LATCH.countDown(); 091 } 092 }); 093 return false; 094 } 095 } catch (final IOException e) { 096 System.err.println(e.getMessage()); 097 resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue(); 098 COMPLETION_LATCH.countDown(); 099 return false; 100 } 101 return true; 102 } 103 104 /** {@inheritDoc} */ 105 @Override 106 public synchronized boolean handleReference(final SearchResultReference reference) { 107 try { 108 WRITER.writeComment("Search result reference: " + reference.getURIs()); 109 } catch (final IOException e) { 110 System.err.println(e.getMessage()); 111 resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue(); 112 COMPLETION_LATCH.countDown(); 113 return false; 114 } 115 return true; 116 } 117 118 } 119 // --- JCite search result handler --- 120 121 // --- JCite decl1 --- 122 private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1); 123 private static final CountDownLatch CANCEL_LATCH = new CountDownLatch(1); 124 private static final LDIFEntryWriter WRITER = new LDIFEntryWriter(System.out); 125 // --- JCite decl1 --- 126 private static String userName; 127 private static String password; 128 private static String baseDN; 129 private static SearchScope scope; 130 private static String filter; 131 private static String[] attributes; 132 private static Connection connection; 133 private static int resultCode; 134 135 // --- JCite decl2 --- 136 static int requestID; 137 static int entryCount; 138 // --- JCite decl2 --- 139 140 /** 141 * Main method. 142 * 143 * @param args 144 * The command line arguments: host, port, username, password, 145 * base DN, scope, filter, and zero or more attributes to be 146 * retrieved. 147 */ 148 public static void main(final String[] args) { 149 if (args.length < 7) { 150 System.err.println("Usage: host port username password baseDN scope " + "filter [attribute ...]"); 151 System.exit(1); 152 } 153 154 // Parse command line arguments. 155 final String hostName = args[0]; 156 final int port = Integer.parseInt(args[1]); 157 userName = args[2]; 158 password = args[3]; 159 baseDN = args[4]; 160 final String scopeString = args[5]; 161 filter = args[6]; 162 if (args.length > 7) { 163 attributes = Arrays.copyOfRange(args, 7, args.length); 164 } else { 165 attributes = new String[0]; 166 } 167 168 scope = SearchScope.valueOf(scopeString); 169 if (scope == null) { 170 System.err.println("Unknown scope: " + scopeString); 171 System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); 172 return; 173 } 174 175 // --- Using Promises --- 176 // Initiate the asynchronous connect, bind, and search. 177 final LDAPConnectionFactory factory = new LDAPConnectionFactory(hostName, port); 178 179 factory.getConnectionAsync() 180 .thenAsync(new AsyncFunction<Connection, BindResult, LdapException>() { 181 @Override 182 public Promise<BindResult, LdapException> apply(Connection connection) 183 throws LdapException { 184 SearchAsync.connection = connection; 185 return connection.bindAsync(Requests 186 .newSimpleBindRequest(userName, password.toCharArray())); 187 } 188 }) 189 .thenAsync(new AsyncFunction<BindResult, Result, LdapException>() { 190 @Override 191 public Promise<Result, LdapException> apply(BindResult result) 192 throws LdapException { 193 LdapPromise<Result> promise = connection.searchAsync( 194 Requests.newSearchRequest(baseDN, scope, filter, attributes), 195 new SearchResultHandlerImpl()); 196 requestID = promise.getRequestID(); 197 return promise; 198 } 199 }) 200 .thenOnResult(new ResultHandler<Result>() { 201 @Override 202 public void handleResult(Result result) { 203 resultCode = result.getResultCode().intValue(); 204 COMPLETION_LATCH.countDown(); 205 } 206 }) 207 .thenOnException(new ExceptionHandler<LdapException>() { 208 @Override 209 public void handleException(LdapException exception) { 210 System.err.println(exception.getMessage()); 211 resultCode = exception.getResult().getResultCode().intValue(); 212 COMPLETION_LATCH.countDown(); 213 } 214 }); 215 // --- Using Promises --- 216 217 // Await completion. 218 try { 219 COMPLETION_LATCH.await(); 220 } catch (final InterruptedException e) { 221 System.err.println(e.getMessage()); 222 System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); 223 return; 224 } 225 226 try { 227 WRITER.flush(); 228 } catch (final IOException e) { 229 System.err.println(e.getMessage()); 230 System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); 231 return; 232 } 233 234 // Await completion of the cancel request. 235 try { 236 CANCEL_LATCH.await(); 237 } catch (final InterruptedException e) { 238 System.err.println(e.getMessage()); 239 System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); 240 return; 241 } 242 243 if (connection != null) { 244 connection.close(); 245 } 246 247 System.exit(resultCode); 248 } 249 250 private SearchAsync() { 251 // Not used. 252 } 253}