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
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2008 Sun Microsystems, Inc.
026 */
027
028 package org.opends.server.util.cli;
029
030 import java.util.ArrayList;
031 import java.util.HashSet;
032 import java.util.List;
033
034 import org.opends.server.util.SetupUtils;
035 import org.opends.server.util.args.Argument;
036 import org.opends.server.util.args.BooleanArgument;
037 import org.opends.server.util.args.FileBasedArgument;
038
039 /**
040 * Class used to be able to generate the non interactive mode.
041 *
042 */
043 public class CommandBuilder
044 {
045 // The command name.
046 private String commandName;
047
048 // The subcommand name.
049 private String subcommandName;
050
051 private ArrayList<Argument> args = new ArrayList<Argument>();
052 private HashSet<Argument> obfuscatedArgs = new HashSet<Argument>();
053
054 // The value used to display arguments that must be obfuscated (such as
055 // passwords). This does not require localization (since the output of
056 // command builder by its nature is not localized).
057 private final static String OBFUSCATED_VALUE = "******";
058
059 /**
060 * The constructor for the CommandBuilder.
061 * @param commandName the command name.
062 */
063 public CommandBuilder(String commandName)
064 {
065 this(commandName, null);
066 }
067
068 /**
069 * The constructor for the CommandBuilder.
070 * @param commandName the command name.
071 * @param subcommandName the subcommand name.
072 */
073 public CommandBuilder(String commandName, String subcommandName)
074 {
075 this.commandName = commandName;
076 this.subcommandName = subcommandName;
077 }
078
079 /**
080 * Adds an argument to the list of the command builder.
081 * @param argument the argument to be added.
082 */
083 public void addArgument(Argument argument)
084 {
085 // We use an ArrayList to be able to provide the possibility of updating
086 // the position of the attributes.
087 if (!args.contains(argument))
088 {
089 args.add(argument);
090 }
091 }
092
093 /**
094 * Adds an argument whose values must be obfuscated (passwords for instance).
095 * @param argument the argument to be added.
096 */
097 public void addObfuscatedArgument(Argument argument)
098 {
099 addArgument(argument);
100 obfuscatedArgs.add(argument);
101 }
102
103 /**
104 * Removes the provided argument from this CommandBuilder.
105 * @param argument the argument to be removed.
106 * @return <CODE>true</CODE> if the attribute was present and removed and
107 * <CODE>false</CODE> otherwise.
108 */
109 public boolean removeArgument(Argument argument)
110 {
111 obfuscatedArgs.remove(argument);
112 return args.remove(argument);
113 }
114
115 /**
116 * Appends the arguments of another command builder to this command builder.
117 * @param builder the CommandBuilder to append.
118 */
119 public void append(CommandBuilder builder)
120 {
121 for (Argument arg : builder.args)
122 {
123 if (builder.isObfuscated(arg))
124 {
125 addObfuscatedArgument(arg);
126 }
127 else
128 {
129 addArgument(arg);
130 }
131 }
132 }
133
134 /**
135 * Returns the String representation of this command builder (i.e. what we
136 * want to show to the user).
137 * @return the String representation of this command builder (i.e. what we
138 * want to show to the user).
139 */
140 public String toString()
141 {
142 return toString(false);
143 }
144
145 /**
146 * Returns the String representation of this command builder (i.e. what we
147 * want to show to the user).
148 * @param showObfuscated displays in clear the obfuscated values.
149 * @return the String representation of this command builder (i.e. what we
150 * want to show to the user).
151 */
152 private String toString(boolean showObfuscated)
153 {
154 StringBuilder builder = new StringBuilder();
155 builder.append(commandName);
156 if (subcommandName != null)
157 {
158 builder.append(" "+subcommandName);
159 }
160 for (Argument arg : args)
161 {
162 String argName;
163 if (arg.getLongIdentifier() != null)
164 {
165 argName = "--"+arg.getLongIdentifier();
166 }
167 else
168 {
169 argName = "-"+arg.getShortIdentifier();
170 }
171 String separator;
172 if (SetupUtils.isWindows())
173 {
174 separator = " ";
175 }
176 else
177 {
178 separator = " \\\n ";
179 }
180
181 if (arg instanceof BooleanArgument)
182 {
183 builder.append(separator+argName);
184 }
185 else if (arg instanceof FileBasedArgument)
186 {
187 for (String value :
188 ((FileBasedArgument)arg).getNameToValueMap().keySet())
189 {
190 builder.append(separator+argName+" ");
191 if (isObfuscated(arg) && !showObfuscated)
192 {
193 value = OBFUSCATED_VALUE;
194 }
195 else
196 {
197 value = escapeValue(value);
198 }
199 builder.append(value);
200 }
201 }
202 else
203 {
204 for (String value : arg.getValues())
205 {
206 builder.append(separator+argName+" ");
207 if (isObfuscated(arg) && !showObfuscated)
208 {
209 value = OBFUSCATED_VALUE;
210 }
211 else
212 {
213 value = escapeValue(value);
214 }
215 builder.append(value);
216 }
217 }
218 }
219 return builder.toString();
220 }
221
222 /**
223 * Clears the arguments.
224 */
225 public void clearArguments()
226 {
227 args.clear();
228 obfuscatedArgs.clear();
229 }
230
231 /**
232 * Returns the list of arguments.
233 * @return the list of arguments.
234 */
235 public List<Argument> getArguments()
236 {
237 return args;
238 }
239
240 /**
241 * Tells whether the provided argument's values must be obfuscated or not.
242 * @param argument the argument to handle.
243 * @return <CODE>true</CODE> if the attribute's values must be obfuscated and
244 * <CODE>false</CODE> otherwise.
245 */
246 private boolean isObfuscated(Argument argument)
247 {
248 return obfuscatedArgs.contains(argument);
249 }
250
251 // Chars that require special treatment when passing them to command-line.
252 private final char[] charsToEscape = {' ', '\t', '\n', '|', ';', '<', '>',
253 '(', ')', '$', '`', '\\', '"', '\''};
254 /**
255 * This method simply takes a value and tries to transform it (with escape or
256 * '"') characters so that it can be used in a command line.
257 * @param value the String to be treated.
258 * @return the transformed value.
259 */
260 private String escapeValue(String value)
261 {
262 StringBuilder b = new StringBuilder();
263 if (SetupUtils.isUnix())
264 {
265 for (int i=0 ; i<value.length(); i++)
266 {
267 char c = value.charAt(i);
268 boolean charToEscapeFound = false;
269 for (int j=0; j<charsToEscape.length && !charToEscapeFound; j++)
270 {
271 charToEscapeFound = c == charsToEscape[j];
272 }
273 if (charToEscapeFound)
274 {
275 b.append('\\');
276 }
277 b.append(c);
278 }
279 }
280 else
281 {
282 b.append('"').append(value).append('"');
283 }
284
285 return b.toString();
286 }
287 }