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 2008-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2012-2015 ForgeRock AS.
026 */
027
028package org.opends.quicksetup;
029
030import org.forgerock.i18n.LocalizableMessage;
031import org.forgerock.i18n.LocalizableMessageBuilder;
032
033import static org.opends.messages.AdminToolMessages.*;
034import static com.forgerock.opendj.cli.Utils.wrapText;
035
036import org.opends.quicksetup.util.Utils;
037import com.forgerock.opendj.cli.ClientException;
038import com.forgerock.opendj.cli.ConsoleApplication;
039import com.forgerock.opendj.cli.Menu;
040import com.forgerock.opendj.cli.MenuBuilder;
041import com.forgerock.opendj.cli.MenuResult;
042
043import java.util.List;
044
045import org.forgerock.i18n.slf4j.LocalizedLogger;
046
047/**
048 * Supports user interactions for a command line driven application.
049 */
050public class CliUserInteraction extends ConsoleApplication
051        implements UserInteraction {
052  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
053
054  private final boolean isInteractive;
055  private final boolean isForceOnError;
056
057  /**
058   * Creates an instance that will use standard streams for interaction and with
059   * the provided CLI arguments.
060   * @param ud The CLI arguments.
061   */
062  public CliUserInteraction(UserData ud) {
063    isInteractive = ud == null || ud.isInteractive();
064    isForceOnError = ud != null && ud.isForceOnError();
065  }
066
067  /** {@inheritDoc} */
068  public Object confirm(LocalizableMessage summary, LocalizableMessage details,
069                        LocalizableMessage title, MessageType type, LocalizableMessage[] options,
070                        LocalizableMessage def) {
071    return confirm(summary, details, null, title, type, options, def, null);
072  }
073
074  /** {@inheritDoc} */
075  public Object confirm(LocalizableMessage summary, LocalizableMessage details, LocalizableMessage fineDetails,
076                        LocalizableMessage title, MessageType type, LocalizableMessage[] options,
077                        LocalizableMessage def, LocalizableMessage viewDetailsOption) {
078    MenuBuilder<Integer> builder = new MenuBuilder<>(this);
079
080    LocalizableMessageBuilder b = new LocalizableMessageBuilder();
081    b.append(summary);
082    b.append(Constants.LINE_SEPARATOR);
083    b.append(details);
084    builder.setPrompt(b.toMessage());
085
086    int defInt = -1;
087    for (int i=0; i<options.length; i++)
088    {
089      builder.addNumberedOption(options[i], MenuResult.success(i+1));
090      if (options[i].equals(def))
091      {
092        defInt = i+1;
093      }
094    }
095
096    if (fineDetails != null) {
097      LocalizableMessage detailsPrompt = viewDetailsOption;
098      if (detailsPrompt == null)
099      {
100        detailsPrompt = INFO_CLI_VIEW_DETAILS.get();
101      }
102      builder.addNumberedOption(detailsPrompt,
103          MenuResult.success(options.length + 1));
104    }
105
106    builder.setDefault(LocalizableMessage.raw(String.valueOf(defInt)),
107        MenuResult.success(defInt));
108
109    Menu<Integer> menu = builder.toMenu();
110
111    Object returnValue = null;
112    boolean menuDisplayed = false;
113    while (returnValue == null) {
114      int respInt;
115      try
116      {
117        if (menuDisplayed)
118        {
119          println();
120          builder.setPrompt(null);
121          menu = builder.toMenu();
122        }
123        MenuResult<Integer> m = menu.run();
124        menuDisplayed = true;
125
126        if (m.isSuccess())
127        {
128          respInt = m.getValue();
129        }
130        else
131        {
132          // Should never happen.
133          throw new RuntimeException();
134        }
135      }
136      catch (ClientException ce)
137      {
138        respInt = defInt;
139        logger.warn(LocalizableMessage.raw("Error reading input: "+ce, ce));
140      }
141      if (fineDetails != null && respInt == options.length + 1) {
142        println();
143        println(String.valueOf(fineDetails));
144      } else {
145        returnValue = options[respInt - 1];
146      }
147    }
148    return returnValue;
149  }
150
151  /** {@inheritDoc} */
152  public String createUnorderedList(List<?> list) {
153    StringBuilder sb = new StringBuilder();
154    if (list != null) {
155      for (Object o : list) {
156        sb.append(/*bullet=*/"* ");
157        sb.append(o);
158        sb.append(Constants.LINE_SEPARATOR);
159      }
160    }
161    return sb.toString();
162  }
163
164  private void println(String text) {
165    text = Utils.convertHtmlBreakToLineSeparator(text);
166    text = Utils.stripHtml(text);
167    text = wrapText(text, Utils.getCommandLineMaxLineWidth());
168    getErrorStream().println(text);
169  }
170
171  /** {@inheritDoc} */
172  public boolean isAdvancedMode() {
173    return false;
174  }
175
176  /** {@inheritDoc} */
177  public boolean isInteractive() {
178    return isInteractive;
179  }
180
181  /** {@inheritDoc} */
182  @Override
183  public boolean isMenuDrivenMode() {
184    return true;
185  }
186
187  /** {@inheritDoc} */
188  public boolean isQuiet() {
189    return false;
190  }
191
192  /** {@inheritDoc} */
193  public boolean isScriptFriendly() {
194    return false;
195  }
196
197  /** {@inheritDoc} */
198  public boolean isVerbose() {
199    return true;
200  }
201
202  /** {@inheritDoc} */
203  public boolean isCLI()
204  {
205    return true;
206  }
207
208  /** {@inheritDoc} */
209  public boolean isForceOnError() {
210    return isForceOnError;
211  }
212}