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 */ 026 027package org.forgerock.opendj.examples; 028 029import static org.forgerock.util.Utils.closeSilently; 030import org.forgerock.opendj.ldap.Connection; 031import org.forgerock.opendj.ldap.LDAPConnectionFactory; 032import org.forgerock.opendj.ldap.LdapException; 033import org.forgerock.opendj.ldap.ResultCode; 034import org.forgerock.opendj.ldap.requests.Requests; 035import org.forgerock.opendj.ldap.responses.BindResult; 036import org.forgerock.opendj.ldap.responses.Result; 037import org.forgerock.util.AsyncFunction; 038import org.forgerock.util.promise.ExceptionHandler; 039import org.forgerock.util.promise.Promise; 040import org.forgerock.util.promise.ResultHandler; 041 042import java.io.BufferedReader; 043import java.io.FileInputStream; 044import java.io.FileNotFoundException; 045import java.io.IOException; 046import java.io.InputStream; 047import java.io.InputStreamReader; 048import java.util.ArrayList; 049import java.util.List; 050import java.util.concurrent.CountDownLatch; 051 052/** 053 * An example client application which applies update operations to a directory server 054 * using the asynchronous APIs. 055 * The update operations are read from an LDIF file, or stdin if no filename is provided. 056 * This example takes the following command line parameters, 057 * reading from stdin if no LDIF file is provided: 058 * 059 * <pre> 060 * {@code <host> <port> <username> <password> [<ldifFile>]} 061 * </pre> 062 */ 063public final class ModifyAsync { 064 /** Connection to the LDAP server. */ 065 private static Connection connection; 066 /** Result for the modify operation. */ 067 private static int resultCode; 068 /** Count down latch to wait for modify operation to complete. */ 069 private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1); 070 071 /** 072 * Main method. 073 * 074 * @param args 075 * The command line arguments: host, port, username, password, 076 * LDIF file name containing the update operations. 077 * Stdin is used if no LDIF file name is provided. 078 */ 079 public static void main(final String[] args) { 080 if (args.length < 4 || args.length > 5) { 081 System.err.println("Usage: host port username password [ldifFileName]"); 082 System.exit(1); 083 } 084 085 // Parse command line arguments. 086 final String hostName = args[0]; 087 final int port = Integer.parseInt(args[1]); 088 final String userName = args[2]; 089 final char[] password = args[3].toCharArray(); 090 091 // Create the LDIF reader using either the named file, if provided, or stdin. 092 InputStream ldif; 093 if (args.length > 4) { 094 try { 095 ldif = new FileInputStream(args[4]); 096 } catch (final FileNotFoundException e) { 097 System.err.println(e.getMessage()); 098 System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); 099 return; 100 } 101 } else { 102 ldif = System.in; 103 } 104 final String[] ldifLines = getInputLines(ldif); 105 106 // Connect to the server, bind, and request the modifications. 107 new LDAPConnectionFactory(hostName, port) 108 .getConnectionAsync() 109 .thenAsync(new AsyncFunction<Connection, BindResult, LdapException>() { 110 @Override 111 public Promise<BindResult, LdapException> apply(Connection connection) 112 throws LdapException { 113 ModifyAsync.connection = connection; 114 return connection.bindAsync( 115 Requests.newSimpleBindRequest(userName, password)); 116 } 117 }) 118 .thenAsync(new AsyncFunction<BindResult, Result, LdapException>() { 119 @Override 120 public Promise<Result, LdapException> apply(BindResult bindResult) 121 throws LdapException { 122 return connection.modifyAsync( 123 Requests.newModifyRequest(ldifLines)); 124 } 125 }) 126 .thenOnResult(new ResultHandler<Result>() { 127 @Override 128 public void handleResult(Result result) { 129 resultCode = result.getResultCode().intValue(); 130 COMPLETION_LATCH.countDown(); 131 } 132 }) 133 .thenOnException(new ExceptionHandler<LdapException>() { 134 @Override 135 public void handleException(LdapException e) { 136 System.err.println(e.getMessage()); 137 resultCode = e.getResult().getResultCode().intValue(); 138 COMPLETION_LATCH.countDown(); 139 } 140 }); 141 142 try { 143 COMPLETION_LATCH.await(); 144 } catch (InterruptedException e) { 145 System.err.println(e.getMessage()); 146 System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); 147 return; 148 } 149 150 closeSilently(connection); 151 System.exit(resultCode); 152 } 153 154 /** 155 * Returns the lines from the input stream. 156 * @param in The input stream. 157 * @return The lines from the input stream. 158 */ 159 private static String[] getInputLines(final InputStream in) { 160 String line; 161 final BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 162 final List<String> lines = new ArrayList<>(); 163 try { 164 while ((line = reader.readLine()) != null) { 165 lines.add(line); 166 } 167 } catch (IOException e) { 168 System.err.println(e.getMessage()); 169 System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); 170 } 171 return lines.toArray(new String[lines.size()]); 172 } 173 174 private ModifyAsync() { 175 // Not used. 176 } 177}