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}