001 /*
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
005 *
006 * The contents of this file are subject to the terms of either the GNU
007 * General Public License Version 2 only ("GPL") or the Common Development
008 * and Distribution License("CDDL") (collectively, the "License"). You
009 * may not use this file except in compliance with the License. You can
010 * obtain a copy of the License at
011 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
012 * or packager/legal/LICENSE.txt. See the License for the specific
013 * language governing permissions and limitations under the License.
014 *
015 * When distributing the software, include this License Header Notice in each
016 * file and include the License file at packager/legal/LICENSE.txt.
017 *
018 * GPL Classpath Exception:
019 * Oracle designates this particular file as subject to the "Classpath"
020 * exception as provided by Oracle in the GPL Version 2 section of the License
021 * file that accompanied this code.
022 *
023 * Modifications:
024 * If applicable, add the following below the License Header, with the fields
025 * enclosed by brackets [] replaced by your own identifying information:
026 * "Portions Copyright [year] [name of copyright owner]"
027 *
028 * Contributor(s):
029 * If you wish your version of this file to be governed by only the CDDL or
030 * only the GPL Version 2, indicate your decision by adding "[Contributor]
031 * elects to include this software in this distribution under the [CDDL or GPL
032 * Version 2] license." If you don't indicate a single choice of license, a
033 * recipient has the option to distribute your version of this file under
034 * either the CDDL, the GPL Version 2 or to extend the choice of license to
035 * its licensees as provided above. However, if you add GPL Version 2 code
036 * and therefore, elected the GPL Version 2 license, then the option applies
037 * only if the new code is made subject to such option by the copyright
038 * holder.
039 */
040
041 package com.sun.enterprise.admin.cli;
042
043 import com.sun.enterprise.universal.io.SmartFile;
044 import java.io.File;
045 import java.util.*;
046 import java.util.logging.Logger;
047
048 import org.glassfish.api.admin.*;
049 import org.glassfish.api.admin.CommandModel.ParamModel;
050
051 import com.sun.enterprise.admin.util.CommandModelData.ParamModelData;
052 import com.sun.enterprise.util.HostAndPort;
053 import com.sun.enterprise.universal.i18n.LocalStringsImpl;
054 import org.glassfish.common.util.admin.AsadminInput;
055 import org.glassfish.common.util.admin.AuthTokenManager;
056
057 /**
058 * Representation of the options known to the asadmin program.
059 * These options control the overall behavior of asadmin, e.g.,
060 * the server to contact, and aren't specific to any of the
061 * commands supported by asadmin.
062 * <p>
063 * In GlassFish v3, asadmin program options are normally specified
064 * before the asadmin command name, with command options after the
065 * command name (although intermixed program and command options
066 * are still supported for compatibility).
067 */
068 public class ProgramOptions {
069
070 public enum PasswordLocation {
071 DEFAULT, USER, PASSWORD_FILE, LOGIN_FILE, LOCAL_PASSWORD
072 };
073
074 private static final Set<ParamModel> programOptions;
075
076 // the known program option names
077 public static final String HOST = "host";
078 public static final String PORT = "port";
079 public static final String USER = "user";
080 public static final String PASSWORDFILE = "passwordfile";
081 public static final String TERSE = "terse";
082 public static final String ECHO = "echo";
083 public static final String INTERACTIVE = "interactive";
084 public static final String SECURE = "secure";
085 public static final String HELP = "help";
086 public static final String AUTHTOKEN = AuthTokenManager.AUTH_TOKEN_OPTION_NAME;
087 public static final String AUXINPUT = AsadminInput.CLI_INPUT_OPTION_NAME;
088
089 private static final Logger logger =
090 Logger.getLogger(ProgramOptions.class.getPackage().getName());
091
092 private static final LocalStringsImpl strings =
093 new LocalStringsImpl(ProgramOptions.class);
094
095 private ParameterMap options;
096 private Environment env;
097 private boolean optionsSet;
098 private String password;
099 private PasswordLocation location;
100
101 /*
102 * Information passed in from AsadminMain and used by start-domain.
103 * XXX - this is somewhat of a kludge but this seems the best place
104 * to put it for now
105 */
106 private String classPath;
107 private String className;
108
109 /*
110 * Define the meta-options known by the asadmin command.
111 */
112 static {
113 Set<ParamModel> opts = new HashSet<ParamModel>();
114 addMetaOption(opts, HOST, 'H', String.class, false,
115 CLIConstants.DEFAULT_HOSTNAME);
116 addMetaOption(opts, PORT, 'p', String.class, false,
117 "" + CLIConstants.DEFAULT_ADMIN_PORT);
118 addMetaOption(opts, USER, 'u', String.class, false, null);
119 addMetaOption(opts, PASSWORDFILE, 'W', File.class, false, null);
120 addMetaOption(opts, SECURE, 's', Boolean.class, false, "false");
121 addMetaOption(opts, TERSE, 't', Boolean.class, false, "false");
122 addMetaOption(opts, ECHO, 'e', Boolean.class, false, "false");
123 addMetaOption(opts, INTERACTIVE, 'I', Boolean.class, false, "false");
124 addMetaOption(opts, HELP, '?', Boolean.class, false, "false");
125 addMetaOption(opts, AUXINPUT, '\0', String.class, false, null);
126 addMetaOption(opts, AUTHTOKEN, '\0', String.class, false, null);
127 programOptions = Collections.unmodifiableSet(opts);
128 }
129
130 /**
131 * Helper method to define a meta-option.
132 *
133 * @param name long option name
134 * @param sname short option name
135 * @param type option type (String.class, Boolean.class, etc.)
136 * @param req is option required?
137 * @param def default value for option
138 */
139 private static void addMetaOption(Set<ParamModel> opts, String name,
140 char sname, Class type, boolean req, String def) {
141 ParamModel opt = new ParamModelData(name, type, !req, def,
142 Character.toString(sname));
143 opts.add(opt);
144 }
145
146 /**
147 * Initialize program options based only on environment defaults,
148 * with no options from the command line.
149 */
150 public ProgramOptions(Environment env) throws CommandException {
151 this(new ParameterMap(), env);
152 optionsSet = false;
153 }
154
155 /**
156 * Initialize the programoptions based on parameters parsed
157 * from the command line, with defaults supplied by the
158 * environment.
159 */
160 public ProgramOptions(ParameterMap options, Environment env)
161 throws CommandException {
162 this.env = env;
163 updateOptions(options);
164 }
165
166 /**
167 * Copy constructor. Create a new ProgramOptions with the same
168 * options as the specified ProgramOptions.
169 */
170 public ProgramOptions(ProgramOptions other) {
171 this.options = new ParameterMap(other.options);
172 this.env = other.env;
173 this.password = other.password;
174 this.classPath = other.classPath;
175 this.className = other.className;
176 }
177
178 /**
179 * Update the program options based on the specified
180 * options from the command line.
181 */
182 public void updateOptions(ParameterMap newOptions)
183 throws CommandException {
184 if (options == null)
185 options = newOptions;
186 else {
187 // merge in the new options
188 for (Map.Entry<String, List<String>> e : newOptions.entrySet())
189 options.set(e.getKey(), e.getValue());
190 }
191 optionsSet = true;
192
193 // have to verify port value now
194 String sport = options.getOne(PORT);
195 if (ok(sport)) {
196 String badPortMsg = strings.get("InvalidPortNumber", sport);
197 try {
198 int port = Integer.parseInt(sport);
199 if (port < 1 || port > 65535)
200 throw new CommandException(badPortMsg);
201 } catch (NumberFormatException e) {
202 throw new CommandException(badPortMsg);
203 }
204 }
205 }
206
207 private static boolean ok(String s) {
208 return s != null && s.length() > 0;
209 }
210
211 /**
212 * Return a set of all the valid program options.
213 *
214 * @return the valid program options
215 */
216 public static Collection<ParamModel> getValidOptions() {
217 return programOptions;
218 }
219
220 /**
221 * Copy the program options that were specified on the
222 * command line into the corresponding environment variables.
223 */
224 public void toEnvironment(Environment env) {
225 // copy all the parameters into corresponding environment variables
226 putEnv(env, ECHO);
227 putEnv(env, TERSE);
228 putEnv(env, INTERACTIVE);
229 putEnv(env, HOST);
230 putEnv(env, PORT);
231 putEnv(env, SECURE);
232 putEnv(env, USER);
233 putEnv(env, PASSWORDFILE);
234 putEnv(env, AUTHTOKEN);
235 putEnv(env, AUXINPUT);
236 // XXX - HELP?
237 }
238
239 private void putEnv(Environment env, String name) {
240 String value = options.getOne(name);
241 if (value != null)
242 env.putOption(name, value);
243 }
244
245 /**
246 * @return the host
247 */
248 public String getHost() {
249 String host = options.getOne(HOST);
250 if (!ok(host))
251 host = env.getStringOption(HOST);
252 if (!ok(host))
253 host = CLIConstants.DEFAULT_HOSTNAME;
254 return host;
255 }
256
257 /**
258 * @param host the host to set
259 */
260 public void setHost(String host) {
261 options.set(HOST, host);
262 }
263
264 /**
265 * @return the port
266 */
267 public int getPort() {
268 int port;
269 String sport = options.getOne(PORT);
270 if (!ok(sport))
271 sport = env.getStringOption(PORT);
272 if (ok(sport)) {
273 try {
274 port = Integer.parseInt(sport);
275 if (port < 1 || port > 65535)
276 port = -1; // should've been verified in constructor
277 } catch (NumberFormatException e) {
278 port = -1; // should've been verified in constructor
279 }
280 } else
281 port = CLIConstants.DEFAULT_ADMIN_PORT; // the default port
282 return port;
283 }
284
285 /**
286 * @param port the port to set
287 */
288 public void setPort(int port) {
289 options.set(PORT, Integer.toString(port));
290 }
291
292 /**
293 * Convenience method to set the host and port (and secure)
294 * attributes from a HostAndPort object.
295 *
296 * @param address the HostAndPort object from which to set the attributes
297 */
298 public void setHostAndPort(HostAndPort address) {
299 setHost(address.getHost());
300 setPort(address.getPort());
301 setSecure(address.isSecure());
302 }
303
304 /**
305 * @return the user
306 */
307 public String getUser() {
308 String user = options.getOne(USER);
309 if (!ok(user))
310 user = env.getStringOption(USER);
311 if (!ok(user))
312 user = null; // distinguish between specify the default explicitly
313 return user;
314 }
315
316 /**
317 * @param user the user to set
318 */
319 public void setUser(String user) {
320 logger.finer("Setting user to: " + user);
321 options.set(USER, user);
322 }
323
324 /**
325 * @return the password
326 */
327 public String getPassword() {
328 return password;
329 }
330
331 /**
332 * @return the password location
333 */
334 public PasswordLocation getPasswordLocation() {
335 return location;
336 }
337
338 /**
339 * @param password the password to set
340 */
341 public void setPassword(String password, PasswordLocation location) {
342 logger.finer("Setting password to: " +
343 (ok(password) ? "<non-null>" : "<null>"));
344 this.password = password;
345 this.location = location;
346 }
347
348 /**
349 * @return the passwordFile
350 */
351 public String getPasswordFile() {
352 String passwordFile = options.getOne(PASSWORDFILE);
353
354 if (!ok(passwordFile))
355 passwordFile = env.getStringOption(PASSWORDFILE);
356
357 if (!ok(passwordFile))
358 return null; // no default
359
360 // weird, huh? This means use standard input
361 if (!passwordFile.equals("-"))
362 passwordFile = SmartFile.sanitize(passwordFile);
363
364 return passwordFile;
365 }
366
367 /**
368 * @param passwordFile the passwordFile to set
369 */
370 public void setPasswordFile(String passwordFile) {
371 options.set(PASSWORDFILE, passwordFile);
372 }
373
374 /**
375 * @return the secure
376 */
377 public boolean isSecure() {
378 boolean secure;
379 if (options.containsKey(SECURE)) {
380 String value = options.getOne(SECURE);
381 if (ok(value))
382 secure = Boolean.parseBoolean(value);
383 else
384 secure = true;
385 } else
386 secure = env.getBooleanOption(SECURE);
387 return secure;
388 }
389
390 /**
391 * @param secure the secure to set
392 */
393 public void setSecure(boolean secure) {
394 options.set(SECURE, Boolean.toString(secure));
395 }
396
397 public void setAuthToken(final String token) {
398 options.set(AUTHTOKEN, token);
399 }
400
401 public String getAuthToken() {
402 return getString(AUTHTOKEN);
403 }
404
405 public void setAuxInput(final String authInput) {
406 options.set(AUXINPUT, authInput);
407 }
408
409 public String getAuxInput() {
410 return getString(AUXINPUT);
411 }
412
413 private String getString(final String optionName) {
414 String result;
415 result = options.getOne(optionName);
416 if ( ! ok(result)) {
417 result = env.getStringOption(optionName);
418 if ( ! ok(result)) {
419 result = null;
420 }
421 }
422 return result;
423 }
424
425 /**
426 * @return the terse
427 */
428 public boolean isTerse() {
429 boolean terse;
430 if (options.containsKey(TERSE)) {
431 String value = options.getOne(TERSE);
432 if (ok(value))
433 terse = Boolean.parseBoolean(value);
434 else
435 terse = true;
436 } else
437 terse = env.getBooleanOption(TERSE);
438 return terse;
439 }
440
441 /**
442 * @param terse the terse to set
443 */
444 public void setTerse(boolean terse) {
445 options.set(TERSE, Boolean.toString(terse));
446 }
447
448 /**
449 * @return the echo
450 */
451 public boolean isEcho() {
452 boolean echo;
453 if (options.containsKey(ECHO)) {
454 String value = options.getOne(ECHO);
455 if (ok(value))
456 echo = Boolean.parseBoolean(value);
457 else
458 echo = true;
459 } else
460 echo = env.getBooleanOption(ECHO);
461 return echo;
462 }
463
464 /**
465 * @param echo the echo to set
466 */
467 public void setEcho(boolean echo) {
468 options.set(ECHO, Boolean.toString(echo));
469 }
470
471 /**
472 * @return the interactive
473 */
474 public boolean isInteractive() {
475 boolean interactive;
476 if (options.containsKey(INTERACTIVE)) {
477 String value = options.getOne(INTERACTIVE);
478 if (ok(value))
479 interactive = Boolean.parseBoolean(value);
480 else
481 interactive = true;
482 } else if (env.hasOption(INTERACTIVE)) {
483 interactive = env.getBooleanOption(INTERACTIVE);
484 } else
485 interactive = System.console() != null;
486 return interactive;
487 }
488
489 /**
490 * @param interactive the interactive to set
491 */
492 public void setInteractive(boolean interactive) {
493 options.set(INTERACTIVE, Boolean.toString(interactive));
494 }
495
496 /**
497 * @return the help
498 */
499 public boolean isHelp() {
500 boolean help = false;
501 if (options.containsKey(HELP)) {
502 String value = options.getOne(HELP);
503 if (ok(value))
504 help = Boolean.parseBoolean(value);
505 else
506 help = true;
507 } else
508 help = env.getBooleanOption(HELP);
509 return help;
510 }
511
512 /**
513 * @param help the help to set
514 */
515 public void setHelp(boolean help) {
516 options.set(HELP, Boolean.toString(help));
517 }
518
519 /**
520 * @return were options set on the command line?
521 */
522 public boolean isOptionsSet() {
523 return optionsSet;
524 }
525
526 /**
527 * Set whether the program options have already been set.
528 */
529 public void setOptionsSet(boolean optionsSet) {
530 this.optionsSet = optionsSet;
531 }
532
533 /**
534 * Return an array of asadmin command line options that specify
535 * all the options of this ProgramOptions instance.
536 */
537 public String[] getProgramArguments() {
538 List<String> args = new ArrayList<String>(15);
539 if (ok(getHost())) {
540 args.add("--host");
541 args.add(getHost());
542 }
543 if (getPort() > 0) {
544 args.add("--port");
545 args.add(String.valueOf(getPort()));
546 }
547 if (ok(getUser())) {
548 args.add("--user");
549 args.add(getUser());
550 }
551 if (ok(getPasswordFile())) {
552 args.add("--passwordfile");
553 args.add(getPasswordFile());
554 }
555 if (ok(getAuxInput())) {
556 args.add("--" + AUXINPUT);
557 args.add(getAuxInput());
558 }
559 args.add("--secure=" + String.valueOf(isSecure()));
560 args.add("--terse=" + String.valueOf(isTerse()));
561 args.add("--echo=" + String.valueOf(isEcho()));
562 args.add("--interactive=" + String.valueOf(isInteractive()));
563 String[] a = new String[args.size()];
564 args.toArray(a);
565 return a;
566 }
567
568 /**
569 * @return the classPath
570 */
571 public String getClassPath() {
572 return classPath;
573 }
574
575 /**
576 * @param classPath the classPath to set
577 */
578 public void setClassPath(String classPath) {
579 this.classPath = classPath;
580 }
581
582 /**
583 * @return the className
584 */
585 public String getClassName() {
586 return className;
587 }
588
589 /**
590 * @param className the className to set
591 */
592 public void setClassName(String className) {
593 this.className = className;
594 }
595
596 /**
597 * String representation of the asadmin program options.
598 * Included in the --echo output.
599 */
600 public String toString() {
601 StringBuilder sb = new StringBuilder();
602 if (ok(getHost()))
603 sb.append("--host ").append(getHost()).append(' ');
604 if (getPort() > 0)
605 sb.append("--port ").append(getPort()).append(' ');
606 if (ok(getUser()))
607 sb.append("--user ").append(getUser()).append(' ');
608 if (ok(getPasswordFile()))
609 sb.append("--passwordfile ").
610 append(getPasswordFile()).append(' ');
611 if (isSecure())
612 sb.append("--secure ");
613 sb.append("--interactive=").
614 append(Boolean.toString(isInteractive())).append(' ');
615 sb.append("--echo=").
616 append(Boolean.toString(isEcho())).append(' ');
617 sb.append("--terse=").
618 append(Boolean.toString(isTerse())).append(' ');
619 sb.setLength(sb.length() - 1); // strip trailing space
620 return sb.toString();
621 }
622 }