001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2015 ForgeRock AS. 015 */ 016 017package org.forgerock.opendj.examples; 018 019import static org.forgerock.util.Utils.closeSilently; 020import org.forgerock.opendj.ldap.Connection; 021import org.forgerock.opendj.ldap.LDAPConnectionFactory; 022import org.forgerock.opendj.ldap.LdapException; 023import org.forgerock.opendj.ldap.ResultCode; 024import org.forgerock.opendj.ldap.requests.Requests; 025import org.forgerock.opendj.ldap.responses.BindResult; 026import org.forgerock.opendj.ldap.responses.Result; 027import org.forgerock.util.AsyncFunction; 028import org.forgerock.util.promise.ExceptionHandler; 029import org.forgerock.util.promise.Promise; 030import org.forgerock.util.promise.ResultHandler; 031 032import java.io.BufferedReader; 033import java.io.FileInputStream; 034import java.io.FileNotFoundException; 035import java.io.IOException; 036import java.io.InputStream; 037import java.io.InputStreamReader; 038import java.util.ArrayList; 039import java.util.List; 040import java.util.concurrent.CountDownLatch; 041 042/** 043 * An example client application which applies update operations to a directory server 044 * using the asynchronous APIs. 045 * The update operations are read from an LDIF file, or stdin if no filename is provided. 046 * This example takes the following command line parameters, 047 * reading from stdin if no LDIF file is provided: 048 * 049 * <pre> 050 * {@code <host> <port> <username> <password> [<ldifFile>]} 051 * </pre> 052 */ 053public final class ModifyAsync { 054 /** Connection to the LDAP server. */ 055 private static Connection connection; 056 /** Result for the modify operation. */ 057 private static int resultCode; 058 /** Count down latch to wait for modify operation to complete. */ 059 private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1); 060 061 /** 062 * Main method. 063 * 064 * @param args 065 * The command line arguments: host, port, username, password, 066 * LDIF file name containing the update operations. 067 * Stdin is used if no LDIF file name is provided. 068 */ 069 public static void main(final String[] args) { 070 if (args.length < 4 || args.length > 5) { 071 System.err.println("Usage: host port username password [ldifFileName]"); 072 System.exit(1); 073 } 074 075 // Parse command line arguments. 076 final String hostName = args[0]; 077 final int port = Integer.parseInt(args[1]); 078 final String userName = args[2]; 079 final char[] password = args[3].toCharArray(); 080 081 // Create the LDIF reader using either the named file, if provided, or stdin. 082 InputStream ldif; 083 if (args.length > 4) { 084 try { 085 ldif = new FileInputStream(args[4]); 086 } catch (final FileNotFoundException e) { 087 System.err.println(e.getMessage()); 088 System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); 089 return; 090 } 091 } else { 092 ldif = System.in; 093 } 094 final String[] ldifLines = getInputLines(ldif); 095 096 // Connect to the server, bind, and request the modifications. 097 new LDAPConnectionFactory(hostName, port) 098 .getConnectionAsync() 099 .thenAsync(new AsyncFunction<Connection, BindResult, LdapException>() { 100 @Override 101 public Promise<BindResult, LdapException> apply(Connection connection) 102 throws LdapException { 103 ModifyAsync.connection = connection; 104 return connection.bindAsync( 105 Requests.newSimpleBindRequest(userName, password)); 106 } 107 }) 108 .thenAsync(new AsyncFunction<BindResult, Result, LdapException>() { 109 @Override 110 public Promise<Result, LdapException> apply(BindResult bindResult) 111 throws LdapException { 112 return connection.modifyAsync( 113 Requests.newModifyRequest(ldifLines)); 114 } 115 }) 116 .thenOnResult(new ResultHandler<Result>() { 117 @Override 118 public void handleResult(Result result) { 119 resultCode = result.getResultCode().intValue(); 120 COMPLETION_LATCH.countDown(); 121 } 122 }) 123 .thenOnException(new ExceptionHandler<LdapException>() { 124 @Override 125 public void handleException(LdapException e) { 126 System.err.println(e.getMessage()); 127 resultCode = e.getResult().getResultCode().intValue(); 128 COMPLETION_LATCH.countDown(); 129 } 130 }); 131 132 try { 133 COMPLETION_LATCH.await(); 134 } catch (InterruptedException e) { 135 System.err.println(e.getMessage()); 136 System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); 137 return; 138 } 139 140 closeSilently(connection); 141 System.exit(resultCode); 142 } 143 144 /** 145 * Returns the lines from the input stream. 146 * @param in The input stream. 147 * @return The lines from the input stream. 148 */ 149 private static String[] getInputLines(final InputStream in) { 150 String line; 151 final BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 152 final List<String> lines = new ArrayList<>(); 153 try { 154 while ((line = reader.readLine()) != null) { 155 lines.add(line); 156 } 157 } catch (IOException e) { 158 System.err.println(e.getMessage()); 159 System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); 160 } 161 return lines.toArray(new String[lines.size()]); 162 } 163 164 private ModifyAsync() { 165 // Not used. 166 } 167}