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