1 /* 2 * $Id$ 3 * 4 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Oracle designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Oracle in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24 * or visit www.oracle.com if you need additional information or have any 25 * questions. 26 */ 27 package com.sun.javatest.tool; 28 29 import java.net.URL; 30 import java.util.Iterator; 31 import java.util.ListIterator; 32 import java.util.Vector; 33 34 import com.sun.javatest.InterviewParameters; 35 import com.sun.javatest.util.I18NResourceBundle; 36 37 /** 38 * A class to represent a command to be executed. 39 * Commands are typically read from the command line or from command files. 40 */ 41 public abstract class Command 42 { 43 /** 44 * This exception is used to report problems with a specific command. 45 */ 46 public class Fault extends Exception 47 { 48 /** 49 * Create a Fault. 50 * @param i18n A resource bundle in which to find the detail message. 51 * @param s The key for the detail message. 52 */ 53 public Fault(I18NResourceBundle i18n, String s) { 54 super(i18n.getString(s)); 55 } 56 57 /** 58 * Create a Fault. 59 * @param i18n A resource bundle in which to find the detail message. 60 * @param s The key for the detail message. 61 * @param o An argument to be formatted with the detail message by 62 * {@link java.text.MessageFormat#format} 63 */ 64 public Fault(I18NResourceBundle i18n, String s, Object o) { 65 super(i18n.getString(s, o)); 66 } 67 68 /** 69 * Create a Fault. 70 * @param i18n A resource bundle in which to find the detail message. 71 * @param s The key for the detail message. 72 * @param o An array of arguments to be formatted with the detail message by 73 * {@link java.text.MessageFormat#format} 74 */ 75 public Fault(I18NResourceBundle i18n, String s, Object[] o) { 76 super(i18n.getString(s, o)); 77 } 78 79 /** 80 * Create a Fault, by wrapping a CommandContext Fault. 81 * The message string will be propagated directly; 82 * the argument fault will be set as the cause for this fault. 83 * @param e A CommandContext.Fault to wrap. 84 */ 85 public Fault(CommandContext.Fault e) { 86 super(e.getMessage(), e); 87 } 88 89 /** 90 * Get the command that created this fault. 91 * @return the command that created this fault 92 */ 93 public Command getCommand() { 94 return Command.this; 95 } 96 97 } 98 99 /** 100 * Create an instance of a command. 101 * @param name The name for this command. 102 * The name will be saved as the first entry as the argument array. 103 */ 104 protected Command(String name) { 105 args = new Vector<>(); 106 args.add(name); 107 } 108 109 /** 110 * Record another argument in the argument array. 111 * @param arg the argument to be added 112 */ 113 protected void addArg(String arg) { 114 args.add(arg); 115 } 116 117 /** 118 * Get another argument from the iterator, and add it to the argument array. 119 * @param argIter the iterator from which to get the next argument 120 * @return the next argument from the iterator 121 */ 122 protected String nextArg(Iterator<String> argIter) { 123 String s = argIter.next(); 124 addArg(s); 125 return s; 126 } 127 128 /** 129 * Back up the iterator to reject an argument, and remove the corresponding 130 * entry from the argument array. 131 * @param argIter the iterator from which teh argument was obtained 132 */ 133 protected void putbackArg(ListIterator<String> argIter) { 134 argIter.previous(); 135 args.remove(args.size() - 1); 136 } 137 138 /** 139 * Get the array of arguments for this command. 140 * The first element in the array will be the command name; 141 * the subsequent arguments will be the ones added by the addArg method. 142 * @return the array of arguments for this command 143 */ 144 public String[] getArgs() { 145 String[] a = new String[args.size()]; 146 args.copyInto(a); 147 return a; 148 } 149 150 /** 151 * Get a printable representation of this command. 152 * The string is composed of the entries in the argument array. 153 * @return a printable representation of this command 154 */ 155 public String toString() { 156 StringBuffer sb = new StringBuffer(); 157 for (int i = 0; i < args.size(); i++) { 158 if (sb.length() > 0) 159 sb.append(' '); 160 String arg = args.elementAt(i); 161 boolean hasSpace = (arg.indexOf(' ') != -1); 162 boolean hasQuote = (arg.indexOf('"') != -1); 163 boolean hasEscape = (arg.indexOf('\\') != -1); 164 if (hasSpace) 165 sb.append('"'); 166 if (hasQuote || hasEscape) { 167 for (int ci = 0; ci < arg.length(); ci++) { 168 char c = arg.charAt(ci); 169 if (c == '"' || c == '\\') 170 sb.append('\\'); 171 sb.append(c); 172 } 173 } 174 else 175 sb.append(arg); 176 if (hasSpace) 177 sb.append('"'); 178 } 179 return sb.toString(); 180 } 181 182 /** 183 * Get the desktop mode for this command. Valid responses are one of 184 * DEFAULT_DTMODE, DESKTOP_NOT_REQUIRED_DTMODE, DESKTOP_REQUIRED_DTMODE. 185 * The default is DESKTOP_NOT_REQUIRED_DTMODE if isActionCommand is true, 186 * and DESKTOP_DEFAULT_DTMODE otherwise. 187 * @return a value indicating the desktop mode for this command 188 * @see #DEFAULT_DTMODE 189 * @see #DESKTOP_NOT_REQUIRED_DTMODE 190 * @see #DESKTOP_REQUIRED_DTMODE 191 */ 192 public int getDesktopMode() { 193 return (isActionCommand() ? DESKTOP_NOT_REQUIRED_DTMODE : DEFAULT_DTMODE); 194 } 195 196 /** 197 * Get the classpath to load the custom splash screen from. 198 * At this location, it is expected that a resource bundle prefixed with 199 * "splash" will be available. The search strategy given in ResourceBundle 200 * will be used, with the returned File as the classpath for the class loader. 201 * The limited classpath/classloader is used to make this operation as fast 202 * as possible, rather than requiring that the command's entire context be 203 * loaded. 204 * 205 * In the resource bundle, there should be a property named 206 * <code>startup.icon</code>. 207 * @return the location of the splash screen resource bundle 208 * @see java.util.ResourceBundle 209 * @since 4.0 210 */ 211 public URL getCustomSplash() { 212 return null; 213 } 214 215 ClassLoader getCustomHelpLoader() { 216 return null; 217 } 218 219 /** 220 * A value to indicate that a command accepts the default desktop mode. 221 * This means that it neither requires nor discourages the use of a desktop 222 * for its use. 223 * @see #getDesktopMode 224 * @see #DESKTOP_NOT_REQUIRED_DTMODE 225 * @see #DESKTOP_REQUIRED_DTMODE 226 */ 227 public static final int DEFAULT_DTMODE = 0; 228 229 /** 230 * A value to indicate that a command does not require the use of 231 * a desktop to function. 232 * @see #getDesktopMode 233 * @see #DEFAULT_DTMODE 234 * @see #DESKTOP_REQUIRED_DTMODE 235 */ 236 public static final int DESKTOP_NOT_REQUIRED_DTMODE = 1; 237 238 /** 239 * A value to indicate that a command requires the use of 240 * a desktop to function. 241 * @see #getDesktopMode 242 * @see #DEFAULT_DTMODE 243 * @see #DESKTOP_NOT_REQUIRED_DTMODE 244 */ 245 public static final int DESKTOP_REQUIRED_DTMODE = 2; 246 247 /** 248 * Check whether this command is an action command or not. Action commands 249 * are those that do work such as running tests, writing a report, etc. 250 * The default implementation is to return false. 251 * @return true if this command is an action command, and false otherwise 252 */ 253 public boolean isActionCommand() { 254 return false; 255 } 256 257 /** 258 * Execute the work embodied by this command, using the given command context. 259 * @param ctx context information that may be set up by preceding commands. 260 * @throws Command.Fault if there is an error while executing this command 261 */ 262 public abstract void run(CommandContext ctx) throws Fault; 263 264 /** 265 * A convenience method to get the configuration from a command context, 266 * and rewrapping any exception that might occur. 267 * @param ctx the command context from which to get the configuration 268 * @return the current configuration from the command context 269 * @throws Command.Fault if there is a problem obtaining or evaluating 270 * the configuration. 271 */ 272 protected InterviewParameters getConfig(CommandContext ctx) 273 throws Command.Fault 274 { 275 try { 276 return ctx.getConfig(); 277 } 278 catch (CommandContext.Fault e) { 279 throw new Fault(e); 280 } 281 } 282 283 private Vector<String> args; 284 }