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}