1 19 20 package org.netbeans.modules.debugger.jpda.models; 21 22 import com.sun.jdi.*; 23 import java.beans.Customizer ; 24 import java.beans.PropertyChangeEvent ; 25 26 import java.beans.PropertyChangeListener ; 27 import java.beans.PropertyChangeSupport ; 28 import java.util.ArrayList ; 29 import java.util.HashSet ; 30 import java.util.List ; 31 import java.util.Set ; 32 import java.io.PushbackReader ; 33 import java.io.StringReader ; 34 import java.io.IOException ; 35 import java.util.logging.Level ; 36 import java.util.logging.Logger ; 37 38 import org.netbeans.api.debugger.jpda.InvalidExpressionException; 39 import org.netbeans.api.debugger.jpda.Field; 40 import org.netbeans.api.debugger.jpda.JPDADebugger; 41 import org.netbeans.api.debugger.jpda.ObjectVariable; 42 import org.netbeans.api.debugger.jpda.Super; 43 import org.netbeans.api.debugger.jpda.Variable; 44 import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl; 45 import org.netbeans.modules.debugger.jpda.expr.JDIObjectVariable; 46 import org.openide.util.NbBundle; 47 import org.openide.util.WeakListeners; 48 49 50 53 class AbstractVariable implements JDIObjectVariable, Customizer , Cloneable { 54 57 private static final Logger logger = Logger.getLogger("org.netbeans.modules.debugger.jpda.getValue"); 59 private Value value; 60 private JPDADebuggerImpl debugger; 61 private String id; 62 private String genericType; 63 private Field[] fields; 64 private Field[] staticFields; 65 private Field[] inheritedFields; 66 private volatile boolean refreshFields; 67 68 private Set <PropertyChangeListener > listeners = new HashSet <PropertyChangeListener >(); 69 private DebuggetStateListener stateChangeListener = new DebuggetStateListener(); 70 71 72 AbstractVariable ( 73 JPDADebuggerImpl debugger, 74 Value value, 75 String id 76 ) { 77 this.debugger = debugger; 78 this.value = value; 79 this.id = id; 80 if (this.id == null) 81 this.id = Integer.toString(super.hashCode()); 82 debugger.addPropertyChangeListener(JPDADebugger.PROP_STATE, 83 WeakListeners.propertyChange(stateChangeListener, debugger)); 84 } 85 86 AbstractVariable (JPDADebuggerImpl debugger, Value value, String genericSignature, 87 String id) { 88 this.debugger = debugger; 89 this.value = value; 90 try { 91 if (genericSignature != null) { 92 this.genericType = getTypeDescription(new PushbackReader (new StringReader (genericSignature), 1)); 93 } 94 } catch (IOException e) { 95 } 97 this.id = id; 98 if (this.id == null) 99 this.id = Integer.toString (super.hashCode()); 100 debugger.addPropertyChangeListener(JPDADebugger.PROP_STATE, 101 WeakListeners.propertyChange(stateChangeListener, debugger)); 102 } 103 104 105 107 112 public String getValue () { 113 Value v = getInnerValue (); 114 if (v == null) return "null"; 115 if (v instanceof VoidValue) return "void"; 116 if (v instanceof CharValue) 117 return "\'" + v.toString () + "\'"; 118 if (v instanceof PrimitiveValue) 119 return v.toString (); 120 if (v instanceof StringReference) 121 return "\"" + 122 ((StringReference) v).value () 123 + "\""; 124 if (v instanceof ClassObjectReference) 125 return "class " + ((ClassObjectReference) v).reflectedType ().name (); 126 if (v instanceof ArrayReference) 127 return "#" + ((ArrayReference) v).uniqueID () + 128 "(length=" + ((ArrayReference) v).length () + ")"; 129 return "#" + ((ObjectReference) v).uniqueID (); 130 } 131 132 137 public void setValue (String expression) throws InvalidExpressionException { 138 String oldValue = getValue(); 139 if (expression.equals(oldValue)) { 140 return ; } 142 Value value; 143 Value oldV = getInnerValue(); 144 if (oldV instanceof CharValue && expression.startsWith("'") && expression.endsWith("'") && expression.length() > 1) { 145 value = oldV.virtualMachine().mirrorOf(expression.charAt(1)); 146 } else if (oldV instanceof StringReference && expression.startsWith("\"") && expression.endsWith("\"") && expression.length() > 1) { 147 value = oldV.virtualMachine().mirrorOf(expression.substring(1, expression.length() - 1)); 148 } else { 149 value = debugger.evaluateIn (expression); 151 } 152 setValue (value); 154 setInnerValue (value); 156 PropertyChangeEvent evt = new PropertyChangeEvent (this, "value", null, value); 158 Object [] ls; 159 synchronized (listeners) { 160 ls = listeners.toArray(); 161 } 162 for (int i = 0; i < ls.length; i++) { 163 ((PropertyChangeListener ) ls[i]).propertyChange(evt); 164 } 165 } 168 169 172 protected void setValue (Value value) throws InvalidExpressionException { 173 throw new InternalError (); 174 } 175 176 public void setObject(Object bean) { 177 try { 178 if (bean instanceof String ) { 179 setValue((String ) bean); 180 } else { 183 throw new IllegalArgumentException (""+bean); 184 } 185 } catch (InvalidExpressionException ieex) { 186 IllegalArgumentException iaex = new IllegalArgumentException (ieex.getLocalizedMessage()); 187 iaex.initCause(ieex); 188 throw iaex; 189 } 190 } 191 192 197 public int getFieldsCount () { 198 Value v = getInnerValue (); 199 if (v == null) return 0; 200 if (v instanceof ArrayReference) { 201 try { 202 return ((ArrayReference) v).length (); 203 } catch (ObjectCollectedException ocex) { 204 return 0; 205 } 206 } else { 207 if (fields == null || refreshFields) { 208 initFields (); 209 } 210 return fields.length; 211 } 212 } 213 214 221 public Field getField (String name) { 222 if (getInnerValue() == null) return null; 223 com.sun.jdi.Field f; 224 try { 225 f = ((ReferenceType) this.getInnerValue().type()).fieldByName(name); 226 } catch (ObjectCollectedException ocex) { 227 return null; 228 } 229 if (f == null) return null; 230 return this.getField ( 231 f, 232 (ObjectReference) getInnerValue (), 233 getID() 234 ); 235 } 236 237 241 public Field[] getFields (int from, int to) { 242 Value v = getInnerValue (); 243 if (v == null) return new Field[] {}; 244 try { 245 if (v instanceof ArrayReference && (from > 0 || to < ((ArrayReference) v).length())) { 246 Type type = v.type (); 248 ReferenceType rt = (ReferenceType) type; 249 if (to == 0) to = ((ArrayReference) v).length(); 250 Field[] elements = getFieldsOfArray ( 251 (ArrayReference) v, 252 ((ArrayType) rt).componentTypeName (), 253 this.getID (), 254 from, to); 255 return elements; 256 } else { 257 if (fields == null || refreshFields) { 259 initFields (); 260 } 261 if (to != 0) { 262 to = Math.min(fields.length, to); 263 from = Math.min(fields.length, from); 264 Field[] fv = new Field [to - from]; 265 System.arraycopy (fields, from, fv, 0, to - from); 266 return fv; 267 } 268 return fields; 269 } 270 } catch (ObjectCollectedException ocex) { 271 return new Field[] {}; 272 } 273 } 274 275 280 public Field[] getAllStaticFields (int from, int to) { 281 Value v = getInnerValue (); 282 if (v == null || v instanceof ArrayReference) { 283 return new Field[] {}; 284 } 285 if (fields == null || refreshFields) { 286 initFields (); 287 } 288 if (to != 0) { 289 to = Math.min(staticFields.length, to); 290 from = Math.min(staticFields.length, from); 291 FieldVariable[] fv = new FieldVariable [to - from]; 292 System.arraycopy (staticFields, from, fv, 0, to - from); 293 return fv; 294 } 295 return staticFields; 296 } 297 298 303 public Field[] getInheritedFields (int from, int to) { 304 Value v = getInnerValue (); 305 if (v == null || v instanceof ArrayReference) { 306 return new Field[] {}; 307 } 308 if (fields == null || refreshFields) { 309 initFields (); 310 } 311 if (to != 0) { 312 to = Math.min(inheritedFields.length, to); 313 from = Math.min(inheritedFields.length, from); 314 FieldVariable[] fv = new FieldVariable [to - from]; 315 System.arraycopy (inheritedFields, from, fv, 0, to - from); 316 return fv; 317 } 318 return inheritedFields; 319 } 320 321 public Super getSuper () { 322 if (getInnerValue () == null) 323 return null; 324 try { 325 Type t = this.getInnerValue().type(); 326 if (!(t instanceof ClassType)) 327 return null; 328 ClassType superType = ((ClassType) t).superclass (); 329 if (superType == null) 330 return null; 331 return new SuperVariable( 332 debugger, 333 (ObjectReference) this.getInnerValue(), 334 superType, 335 this.id 336 ); 337 } catch (ObjectCollectedException ocex) { 338 return null; 339 } 340 } 341 342 348 public String getToStringValue () throws InvalidExpressionException { 349 try { 350 Value v = getInnerValue (); 351 if (v == null) return null; 352 353 if (!(v.type () instanceof ClassType)) 354 return getValue (); 355 if (v instanceof CharValue) 356 return "\'" + v.toString () + "\'"; 357 if (v instanceof StringReference) 358 return "\"" + 359 ((StringReference) v).value () 360 + "\""; 361 Method toStringMethod = ((ClassType) v.type ()). 362 concreteMethodByName ("toString", "()Ljava/lang/String;"); 363 StringReference sr = (StringReference) debugger.invokeMethod ( 364 (ObjectReference) v, 365 toStringMethod, 366 new Value [0] 367 ); 368 if (sr == null) { 369 return null; 370 } else { 371 return sr.value (); 372 } 373 } catch (VMDisconnectedException ex) { 374 return NbBundle.getMessage(AbstractVariable.class, "MSG_Disconnected"); 375 } catch (ObjectCollectedException ocex) { 376 return NbBundle.getMessage(AbstractVariable.class, "MSG_ObjCollected"); 377 } 378 } 379 380 390 public Variable invokeMethod ( 391 String methodName, 392 String signature, 393 Variable[] arguments 394 ) throws NoSuchMethodException , InvalidExpressionException { 395 try { 396 397 if (this.getInnerValue () == null) return null; 399 Method method = null; 400 if (signature != null) 401 method = ((ClassType) this.getInnerValue ().type ()). 402 concreteMethodByName (methodName, signature); 403 else { 404 List l = ((ClassType) this.getInnerValue ().type ()). 405 methodsByName (methodName); 406 int j, jj = l.size (); 407 for (j = 0; j < jj; j++) 408 if ( !((Method) l.get (j)).isAbstract () && 409 ((Method) l.get (j)).argumentTypeNames ().size () == 0 410 ) { 411 method = (Method) l.get (j); 412 break; 413 } 414 } 415 416 if (method == null) { 418 List l = ((ClassType) this.getInnerValue ().type ()). 419 methodsByName (methodName); 420 int j, jj = l.size (); 421 for (j = 0; j < jj; j++) 422 System.out.println (((Method) l.get (j)).signature ()); 423 throw new NoSuchMethodException ( 424 this.getInnerValue ().type ().name () + "." + 425 methodName + " : " + signature 426 ); 427 } 428 429 Value[] vs = new Value [arguments.length]; 431 int i, k = arguments.length; 432 for (i = 0; i < k; i++) 433 vs [i] = ((AbstractVariable) arguments [i]).getInnerValue (); 434 Value v = debugger.invokeMethod ( 435 (ObjectReference) this.getInnerValue(), 436 method, 437 vs 438 ); 439 440 if (v instanceof ObjectReference) 442 return new AbstractVariable ( debugger, 444 (ObjectReference) v, 445 id + method + "^" 446 ); 447 return new AbstractVariable (debugger, v, id + method); 448 } catch (VMDisconnectedException ex) { 449 return null; 450 } catch (ObjectCollectedException ocex) { 451 return null; 452 } 453 } 454 455 460 public String getType () { 461 if (genericType != null) return genericType; 462 if (getInnerValue () == null) return ""; 463 try { 464 return this.getInnerValue().type().name (); 465 } catch (VMDisconnectedException vmdex) { 466 return NbBundle.getMessage(AbstractVariable.class, "MSG_Disconnected"); 468 } catch (ObjectCollectedException ocex) { 469 return NbBundle.getMessage(AbstractVariable.class, "MSG_ObjCollected"); 471 } 472 } 473 474 public boolean equals (Object o) { 475 return (o instanceof AbstractVariable) && 476 (id.equals (((AbstractVariable) o).id)); 477 } 478 479 public int hashCode () { 480 return id.hashCode (); 481 } 482 483 484 486 protected Value getInnerValue () { 487 return value; 488 } 489 490 protected void setInnerValue (Value v) { 491 value = v; 492 fields = null; 493 staticFields = null; 494 inheritedFields = null; 495 } 496 497 public Value getJDIValue() { 498 return value; 499 } 500 501 protected final JPDADebuggerImpl getDebugger() { 502 return debugger; 503 } 504 505 protected final String getID () { 506 return id; 507 } 508 509 private static String getTypeDescription (PushbackReader signature) 510 throws IOException { 511 int c = signature.read(); 512 switch (c) { 513 case 'Z': 514 return "boolean"; 515 case 'B': 516 return "byte"; 517 case 'C': 518 return "char"; 519 case 'S': 520 return "short"; 521 case 'I': 522 return "int"; 523 case 'J': 524 return "long"; 525 case 'F': 526 return "float"; 527 case 'D': 528 return "double"; 529 case '[': 530 { 531 int arrayCount = 1; 532 for (; ;arrayCount++) { 533 if ((c = signature.read()) != '[') { 534 signature.unread(c); 535 break; 536 } 537 } 538 return getTypeDescription(signature) + " " + brackets(arrayCount); 539 } 540 case 'L': 541 { 542 StringBuffer typeName = new StringBuffer (50); 543 for (;;) { 544 c = signature.read(); 545 if (c == ';') { 546 int idx = typeName.lastIndexOf("/"); 547 return idx == -1 ? 548 typeName.toString() : typeName.substring(idx + 1); 549 } 550 else if (c == '<') { 551 int idx = typeName.lastIndexOf("/"); 552 if (idx != -1) typeName.delete(0, idx + 1); 553 typeName.append("<"); 554 for (;;) { 555 String td = getTypeDescription(signature); 556 typeName.append(td); 557 c = signature.read(); 558 if (c == '>') break; 559 signature.unread(c); 560 typeName.append(','); 561 } 562 signature.read(); typeName.append(">"); 564 return typeName.toString(); 565 } 566 typeName.append((char)c); 567 } 568 } 569 } 570 throw new IOException (); 571 } 572 573 private static String brackets (int arrayCount) { 574 StringBuffer sb = new StringBuffer (arrayCount * 2); 575 do { 576 sb.append ("[]"); 577 } while (--arrayCount > 0); 578 return sb.toString (); 579 } 580 581 private void initFields () { 582 refreshFields = false; 583 Value value = getInnerValue(); 584 Type type; 585 if (value != null) { 586 try { 587 type = getInnerValue ().type (); 588 } catch (ObjectCollectedException ocex) { 589 type = null; 590 } 591 } else { 592 type = null; 593 } 594 if ( !(getInnerValue() instanceof ObjectReference) || 595 !(type instanceof ReferenceType) 596 ) { 597 this.fields = new Field [0]; 598 this.staticFields = new Field [0]; 599 this.inheritedFields = new Field [0]; 600 } else { 601 try { 602 ObjectReference or = (ObjectReference) this.getInnerValue(); 603 ReferenceType rt = (ReferenceType) type; 604 if (or instanceof ArrayReference) { 605 this.fields = getFieldsOfArray ( 606 (ArrayReference) or, 607 ((ArrayType) rt).componentTypeName (), 608 this.getID (), 609 0, ((ArrayReference) or).length()); 610 this.staticFields = new Field[0]; 611 this.inheritedFields = new Field[0]; 612 } 613 else { 614 initFieldsOfClass(or, rt, this.getID ()); 615 } 616 } catch (ObjectCollectedException ocex) { 617 } 619 } 620 } 621 622 private Field[] getFieldsOfArray ( 623 ArrayReference ar, 624 String componentType, 625 String parentID, 626 int from, 627 int to 628 ) { 629 List l; 630 try { 631 l = ar.getValues(from, to - from); 632 } catch (ObjectCollectedException ocex) { 633 l = java.util.Collections.EMPTY_LIST; 634 } 635 int i, k = l.size (); 636 Field[] ch = new Field [k]; 637 for (i = 0; i < k; i++) { 638 Value v = (Value) l.get (i); 639 ch [i] = (v instanceof ObjectReference) ? 640 new ObjectArrayFieldVariable ( 641 debugger, 642 (ObjectReference) v, 643 componentType, 644 ar, 645 from + i, 646 to - 1, 647 parentID 648 ) : 649 new ArrayFieldVariable ( 650 debugger, 651 v, 652 componentType, 653 ar, 654 from + i, 655 to - 1, 656 parentID 657 ); 658 } 659 return ch; 660 } 661 662 private void initFieldsOfClass ( 663 ObjectReference or, 664 ReferenceType rt, 665 String parentID) 666 { 667 List <Field> fields = new ArrayList <Field>(); 668 List <Field> staticFields = new ArrayList <Field>(); 669 List <Field> allInheretedFields = new ArrayList <Field>(); 670 671 List <com.sun.jdi.Field> l = rt.allFields (); 672 Set <com.sun.jdi.Field> s = new HashSet <com.sun.jdi.Field>(rt.fields ()); 673 674 int i, k = l.size(); 675 for (i = 0; i < k; i++) { 676 com.sun.jdi.Field f = l.get (i); 677 Field field = this.getField (f, or, this.getID()); 678 if (f.isStatic ()) 679 staticFields.add(field); 680 else { 681 if (s.contains (f)) 682 fields.add(field); 683 else 684 allInheretedFields.add(field); 685 } 686 } 687 this.fields = fields.toArray (new Field [fields.size ()]); 688 this.inheritedFields = allInheretedFields.toArray ( 689 new Field [allInheretedFields.size ()] 690 ); 691 this.staticFields = staticFields.toArray 692 (new Field [staticFields.size ()]); 693 } 694 695 FieldVariable getField ( 696 com.sun.jdi.Field f, 697 ObjectReference or, 698 String parentID 699 ) { 700 Value v; 701 try { 702 if (logger.isLoggable(Level.FINE)) { 703 logger.fine("STARTED : "+or+".getValue("+f+")"); 704 } 705 v = or.getValue (f); 706 } catch (ObjectCollectedException ocex) { 707 v = null; 708 } 709 if (logger.isLoggable(Level.FINE)) { 710 logger.fine("FINISHED: "+or+".getValue("+f+") = "+v); 711 } 712 if ( (v == null) || (v instanceof ObjectReference)) 713 return new ObjectFieldVariable ( 714 debugger, 715 (ObjectReference) v, 716 f, 717 parentID, 718 JPDADebuggerImpl.getGenericSignature(f), 719 or 720 ); 721 return new FieldVariable (debugger, v, f, parentID, or); 722 } 723 724 public Variable clone() { 725 AbstractVariable clon = new AbstractVariable(debugger, value, id); 726 clon.genericType = this.genericType; 727 return clon; 728 } 729 730 public void addPropertyChangeListener(PropertyChangeListener l) { 731 listeners.add(l); 732 } 733 734 public void removePropertyChangeListener(PropertyChangeListener l) { 735 listeners.remove(l); 736 } 737 738 public String toString () { 739 return "ObjectVariable "; 740 } 741 742 807 808 private class DebuggetStateListener extends Object implements PropertyChangeListener { 809 810 public void propertyChange(PropertyChangeEvent evt) { 811 if (JPDADebugger.PROP_STATE.equals(evt.getPropertyName())) { 812 Object newValue = evt.getNewValue(); 813 if (newValue instanceof Integer && 814 JPDADebugger.STATE_RUNNING == ((Integer ) newValue).intValue()) { 815 AbstractVariable.this.refreshFields = true; 816 } 817 } 818 } 819 820 } 821 822 } 823 824 | Popular Tags |