1 /* 2 * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.jdi; 27 28 import com.sun.tools.jdi.*; 29 import com.sun.jdi.*; 30 import com.sun.jdi.connect.*; 31 import com.sun.jdi.InternalException; 32 import java.util.Collections; 33 import java.util.Collection; 34 import java.util.Map; 35 import java.util.List; 36 import java.util.ArrayList; 37 import java.util.Iterator; 38 import java.util.ResourceBundle; 39 import java.io.Serializable; 40 41 abstract class ConnectorImpl implements Connector { 42 Map<String,Argument> defaultArguments = new java.util.LinkedHashMap<String,Argument>(); 43 44 // Used by BooleanArgument 45 static String trueString = null; 46 static String falseString; 47 48 public Map<String,Argument> defaultArguments() { 49 Map<String,Argument> defaults = new java.util.LinkedHashMap<String,Argument>(); 50 Collection<Argument> values = defaultArguments.values(); 51 52 Iterator<Argument> iter = values.iterator(); 53 while (iter.hasNext()) { 54 ArgumentImpl argument = (ArgumentImpl)iter.next(); 55 defaults.put(argument.name(), (Argument)argument.clone()); 56 } 57 return defaults; 58 } 59 60 void addStringArgument(String name, String label, String description, 61 String defaultValue, boolean mustSpecify) { 62 defaultArguments.put(name, 63 new StringArgumentImpl(name, label, 64 description, 65 defaultValue, 66 mustSpecify)); 67 } 68 69 void addBooleanArgument(String name, String label, String description, 70 boolean defaultValue, boolean mustSpecify) { 71 defaultArguments.put(name, 72 new BooleanArgumentImpl(name, label, 73 description, 74 defaultValue, 75 mustSpecify)); 76 } 77 78 void addIntegerArgument(String name, String label, String description, 79 String defaultValue, boolean mustSpecify, 80 int min, int max) { 81 defaultArguments.put(name, 82 new IntegerArgumentImpl(name, label, 83 description, 84 defaultValue, 85 mustSpecify, 86 min, max)); 87 } 88 89 void addSelectedArgument(String name, String label, String description, 90 String defaultValue, boolean mustSpecify, 91 List<String> list) { 92 defaultArguments.put(name, 93 new SelectedArgumentImpl(name, label, 94 description, 95 defaultValue, 96 mustSpecify, list)); 97 } 98 99 ArgumentImpl argument(String name, Map<String, ? extends Argument> arguments) 100 throws IllegalConnectorArgumentsException { 101 102 ArgumentImpl argument = (ArgumentImpl)arguments.get(name); 103 if (argument == null) { 104 throw new IllegalConnectorArgumentsException( 105 "Argument missing", name); 106 } 107 String value = argument.value(); 108 if (value == null || value.length() == 0) { 109 if (argument.mustSpecify()) { 110 throw new IllegalConnectorArgumentsException( 111 "Argument unspecified", name); 112 } 113 } else if(!argument.isValid(value)) { 114 throw new IllegalConnectorArgumentsException( 115 "Argument invalid", name); 116 } 117 118 return argument; 119 } 120 121 122 private ResourceBundle messages = null; 123 124 String getString(String key) { 125 if (messages == null) { 126 messages = ResourceBundle.getBundle("com.sun.tools.jdi.resources.jdi"); 127 } 128 return messages.getString(key); 129 } 130 131 public String toString() { 132 String string = name() + " (defaults: "; 133 Iterator<Argument> iter = defaultArguments().values().iterator(); 134 boolean first = true; 135 while (iter.hasNext()) { 136 ArgumentImpl argument = (ArgumentImpl)iter.next(); 137 if (!first) { 138 string += ", "; 139 } 140 string += argument.toString(); 141 first = false; 142 } 143 string += ")"; 144 return string; 145 } 146 147 abstract class ArgumentImpl implements Connector.Argument, Cloneable, Serializable { 148 private String name; 149 private String label; 150 private String description; 151 private String value; 152 private boolean mustSpecify; 153 154 ArgumentImpl(String name, String label, String description, 155 String value, 156 boolean mustSpecify) { 157 this.name = name; 158 this.label = label; 159 this.description = description; 160 this.value = value; 161 this.mustSpecify = mustSpecify; 162 } 163 164 public abstract boolean isValid(String value); 165 166 public String name() { 167 return name; 168 } 169 170 public String label() { 171 return label; 172 } 173 174 public String description() { 175 return description; 176 } 177 178 public String value() { 179 return value; 180 } 181 182 public void setValue(String value) { 183 if (value == null) { 184 throw new NullPointerException("Can't set null value"); 185 } 186 this.value = value; 187 } 188 189 public boolean mustSpecify() { 190 return mustSpecify; 191 } 192 193 public boolean equals(Object obj) { 194 if ((obj != null) && (obj instanceof Connector.Argument)) { 195 Connector.Argument other = (Connector.Argument)obj; 196 return (name().equals(other.name())) && 197 (description().equals(other.description())) && 198 (mustSpecify() == other.mustSpecify()) && 199 (value().equals(other.value())); 200 } else { 201 return false; 202 } 203 } 204 205 public int hashCode() { 206 return description().hashCode(); 207 } 208 209 public Object clone() { 210 try { 211 return super.clone(); 212 } catch (CloneNotSupportedException e) { 213 // Object should always support clone 214 throw new InternalException(); 215 } 216 } 217 218 public String toString() { 219 return name() + "=" + value(); 220 } 221 } 222 223 class BooleanArgumentImpl extends ConnectorImpl.ArgumentImpl 224 implements Connector.BooleanArgument { 225 private static final long serialVersionUID = 1624542968639361316L; 226 BooleanArgumentImpl(String name, String label, String description, 227 boolean value, 228 boolean mustSpecify) { 229 super(name, label, description, null, mustSpecify); 230 if(trueString == null) { 231 trueString = getString("true"); 232 falseString = getString("false"); 233 } 234 setValue(value); 235 } 236 237 /** 238 * Sets the value of the argument. 239 */ 240 public void setValue(boolean value) { 241 setValue(stringValueOf(value)); 242 } 243 244 /** 245 * Performs basic sanity check of argument. 246 * @return <code>true</code> if value is a string 247 * representation of a boolean value. 248 * @see #stringValueOf(boolean) 249 */ 250 public boolean isValid(String value) { 251 return value.equals(trueString) || value.equals(falseString); 252 } 253 254 /** 255 * Return the string representation of the <code>value</code> 256 * parameter. 257 * Does not set or examine the value or the argument. 258 * @return the localized String representation of the 259 * boolean value. 260 */ 261 public String stringValueOf(boolean value) { 262 return value? trueString : falseString; 263 } 264 265 /** 266 * Return the value of the argument as a boolean. Since 267 * the argument may not have been set or may have an invalid 268 * value {@link #isValid(String)} should be called on 269 * {@link #value()} to check its validity. If it is invalid 270 * the boolean returned by this method is undefined. 271 * @return the value of the argument as a boolean. 272 */ 273 public boolean booleanValue() { 274 return value().equals(trueString); 275 } 276 } 277 278 class IntegerArgumentImpl extends ConnectorImpl.ArgumentImpl 279 implements Connector.IntegerArgument { 280 private static final long serialVersionUID = 763286081923797770L; 281 private final int min; 282 private final int max; 283 284 IntegerArgumentImpl(String name, String label, String description, 285 String value, 286 boolean mustSpecify, int min, int max) { 287 super(name, label, description, value, mustSpecify); 288 this.min = min; 289 this.max = max; 290 } 291 292 /** 293 * Sets the value of the argument. 294 * The value should be checked with {@link #isValid(int)} 295 * before setting it; invalid values will throw an exception 296 * when the connection is established - for example, 297 * on {@link LaunchingConnector#launch} 298 */ 299 public void setValue(int value) { 300 setValue(stringValueOf(value)); 301 } 302 303 /** 304 * Performs basic sanity check of argument. 305 * @return <code>true</code> if value represents an int that is 306 * <code>{@link #min()} <= value <= {@link #max()}</code> 307 */ 308 public boolean isValid(String value) { 309 if (value == null) { 310 return false; 311 } 312 try { 313 return isValid(Integer.decode(value).intValue()); 314 } catch(NumberFormatException exc) { 315 return false; 316 } 317 } 318 319 /** 320 * Performs basic sanity check of argument. 321 * @return <code>true</code> if 322 * <code>{@link #min()} <= value <= {@link #max()}</code> 323 */ 324 public boolean isValid(int value) { 325 return min <= value && value <= max; 326 } 327 328 /** 329 * Return the string representation of the <code>value</code> 330 * parameter. 331 * Does not set or examine the value or the argument. 332 * @return the String representation of the 333 * int value. 334 */ 335 public String stringValueOf(int value) { 336 // *** Should this be internationalized???? 337 // *** Even Brian Beck was unsure if an Arabic programmer 338 // *** would expect port numbers in Arabic numerals, 339 // *** so punt for now. 340 return ""+value; 341 } 342 343 /** 344 * Return the value of the argument as a int. Since 345 * the argument may not have been set or may have an invalid 346 * value {@link #isValid(String)} should be called on 347 * {@link #value()} to check its validity. If it is invalid 348 * the int returned by this method is undefined. 349 * @return the value of the argument as a int. 350 */ 351 public int intValue() { 352 if (value() == null) { 353 return 0; 354 } 355 try { 356 return Integer.decode(value()).intValue(); 357 } catch(NumberFormatException exc) { 358 return 0; 359 } 360 } 361 362 /** 363 * The upper bound for the value. 364 * @return the maximum allowed value for this argument. 365 */ 366 public int max() { 367 return max; 368 } 369 370 /** 371 * The lower bound for the value. 372 * @return the minimum allowed value for this argument. 373 */ 374 public int min() { 375 return min; 376 } 377 } 378 379 class StringArgumentImpl extends ConnectorImpl.ArgumentImpl 380 implements Connector.StringArgument { 381 private static final long serialVersionUID = 7500484902692107464L; 382 StringArgumentImpl(String name, String label, String description, 383 String value, 384 boolean mustSpecify) { 385 super(name, label, description, value, mustSpecify); 386 } 387 388 /** 389 * Performs basic sanity check of argument. 390 * @return <code>true</code> always 391 */ 392 public boolean isValid(String value) { 393 return true; 394 } 395 } 396 397 class SelectedArgumentImpl extends ConnectorImpl.ArgumentImpl 398 implements Connector.SelectedArgument { 399 private static final long serialVersionUID = -5689584530908382517L; 400 private final List<String> choices; 401 402 SelectedArgumentImpl(String name, String label, String description, 403 String value, 404 boolean mustSpecify, List<String> choices) { 405 super(name, label, description, value, mustSpecify); 406 this.choices = Collections.unmodifiableList(new ArrayList<String>(choices)); 407 } 408 409 /** 410 * Return the possible values for the argument 411 * @return {@link List} of {@link String} 412 */ 413 public List<String> choices() { 414 return choices; 415 } 416 417 /** 418 * Performs basic sanity check of argument. 419 * @return <code>true</code> if value is one of {@link #choices()}. 420 */ 421 public boolean isValid(String value) { 422 return choices.contains(value); 423 } 424 } 425 } 426