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 defaultArguments()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 addStringArgument(String name, String label, String description, String defaultValue, boolean mustSpecify)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 addBooleanArgument(String name, String label, String description, boolean defaultValue, boolean mustSpecify)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 addIntegerArgument(String name, String label, String description, String defaultValue, boolean mustSpecify, int min, int max)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 addSelectedArgument(String name, String label, String description, String defaultValue, boolean mustSpecify, List<String> list)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 argument(String name, Map<String, ? extends Argument> arguments)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 getString(String key)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 toString()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 ArgumentImpl(String name, String label, String description, String value, boolean mustSpecify)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 isValid(String value)164 public abstract boolean isValid(String value); 165 name()166 public String name() { 167 return name; 168 } 169 label()170 public String label() { 171 return label; 172 } 173 description()174 public String description() { 175 return description; 176 } 177 value()178 public String value() { 179 return value; 180 } 181 setValue(String value)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 mustSpecify()189 public boolean mustSpecify() { 190 return mustSpecify; 191 } 192 equals(Object obj)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 hashCode()205 public int hashCode() { 206 return description().hashCode(); 207 } 208 clone()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 toString()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; BooleanArgumentImpl(String name, String label, String description, boolean value, boolean mustSpecify)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 */ setValue(boolean value)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 */ isValid(String value)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 */ stringValueOf(boolean value)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 */ booleanValue()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 IntegerArgumentImpl(String name, String label, String description, String value, boolean mustSpecify, int min, int max)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 */ setValue(int value)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 */ isValid(String value)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 */ isValid(int value)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 */ stringValueOf(int value)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 */ intValue()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 */ max()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 */ min()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; StringArgumentImpl(String name, String label, String description, String value, boolean mustSpecify)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 */ isValid(String value)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 SelectedArgumentImpl(String name, String label, String description, String value, boolean mustSpecify, List<String> choices)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 */ choices()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 */ isValid(String value)421 public boolean isValid(String value) { 422 return choices.contains(value); 423 } 424 } 425 } 426