1 19 20 package org.netbeans.modules.java.tools; 21 22 import java.beans.PropertyChangeListener ; 23 import java.beans.PropertyChangeSupport ; 24 import java.lang.reflect.Modifier ; 25 import java.util.*; 26 import javax.jmi.reflect.InvalidObjectException; 27 import org.netbeans.api.mdr.MDRepository; 28 import org.netbeans.jmi.javamodel.Resource; 29 import org.netbeans.jmi.javamodel.ClassDefinition; 30 import org.netbeans.jmi.javamodel.JavaClass; 31 import org.netbeans.jmi.javamodel.JavaModelPackage; 32 import org.netbeans.jmi.javamodel.Method; 33 import org.netbeans.jmi.javamodel.NamedElement; 34 import org.netbeans.jmi.javamodel.Parameter; 35 import org.netbeans.jmi.javamodel.ParameterizedType; 36 import org.netbeans.jmi.javamodel.PrimitiveType; 37 import org.netbeans.jmi.javamodel.PrimitiveTypeKindEnum; 38 import org.netbeans.jmi.javamodel.Type; 39 import org.netbeans.modules.java.settings.JavaSynchronizationSettings; 40 import org.netbeans.modules.javacore.internalapi.JavaMetamodel; 41 import org.netbeans.modules.javacore.internalapi.JavaModelUtil; 42 import org.netbeans.modules.javacore.jmiimpl.javamodel.MethodImpl; 43 import org.netbeans.modules.javacore.jmiimpl.javamodel.ParameterizedTypeImpl; 44 import org.openide.ErrorManager; 45 import org.openide.util.NbBundle; 46 import org.openide.util.RequestProcessor; 47 import org.openide.util.SharedClassObject; 48 import org.openide.util.Task; 49 import org.openide.util.TaskListener; 50 import org.openide.loaders.DataObject; 51 52 public class JMIInheritanceSupport implements Runnable , TaskListener { 53 54 public static final String PROP_FINISHED = "JMIInheritanceSupport.finished"; 56 private static String getString(String key) { 57 return NbBundle.getMessage(JMIInheritanceSupport.class, key); 58 } 59 60 private ClassDefinition root; 61 62 private JavaModelPackage modelPackage; 63 64 private Resource resource; 65 66 private Set classes; 67 68 private Map methods; 70 71 private Map tree; 73 74 private List classesList; 75 76 private Set finalMethodsKeys; 77 78 private int ordNumCounter; 79 80 private PropertyChangeSupport pcs = new PropertyChangeSupport (this); 81 private RequestProcessor.Task task = RequestProcessor.getDefault().create(this); 82 83 84 private int nextPosition = -1; 85 86 87 public JMIInheritanceSupport(ClassDefinition root) { 88 DataObject dobj = (DataObject) JavaMetamodel.getManager().getDataObject(root.getResource()); 89 assert dobj != null; 90 this.root = root; 91 this.resource = root.getResource(); 92 this.modelPackage = (JavaModelPackage)root.refOutermostPackage(); 93 this.task.addTaskListener(this); 94 } 95 96 public ClassDefinition getRootClass() { 97 return root; 98 } 99 100 public void setRootClass(ClassDefinition root) { 101 this.root = root; 102 } 103 104 public Collection getClasses(Collection result, boolean cls, boolean ifc) { 105 if (!task.isFinished()) { 106 task.waitFinished(); 107 } 108 109 for (Iterator i = classesList.iterator(); i.hasNext(); ) { 110 JavaClass jc = (JavaClass) i.next(); 111 boolean isInterface = jc.isInterface(); 112 if ((!isInterface && cls) || (isInterface && ifc)) { 113 result.add(jc); 114 } 115 } 116 117 return result; 118 } 119 120 public Collection getAllMethods(Collection result, boolean abstractOnly) { 121 if (!task.isFinished()) { 122 task.waitFinished(); 123 } 124 125 for (Iterator i = methods.values().iterator(); i.hasNext(); ) { 126 Method mte = (Method) i.next(); 127 if (!abstractOnly || (isAbstract(mte) && !isImplemented(mte))) { 128 result.add(mte); 129 } 130 } 131 132 return result; 133 } 134 135 public Collection getMethods(Collection result, ClassDefinition cd, boolean abstractOnly) { 136 if (!task.isFinished()) { 137 task.waitFinished(); 138 } 139 140 Set meths = (Set) tree.get(cd); 141 for (Iterator i = meths.iterator(); i.hasNext(); ) { 142 MethodKey key = (MethodKey) i.next(); 143 Method m = (Method) methods.get(key); 144 if (!abstractOnly || (isAbstract(m) && !isImplemented(m))) { 145 result.add(m); 146 } 147 } 148 149 return result; 150 } 151 152 public Collection sortMethods(Map selection) { 153 int size = selection.size(); 154 List list = new ArrayList(size); 155 Map map = new HashMap(); 156 for (Iterator iter = methods.keySet().iterator(); iter.hasNext();) { 157 Object val = iter.next(); 158 map.put(val, val); 159 } 160 for (Iterator iter = selection.entrySet().iterator(); iter.hasNext();) { 161 Map.Entry entry = (Map.Entry)iter.next(); 162 int ord = ((MethodKey)map.get(entry.getKey())).getOrdNumber(); 163 list.add(new MethodRecord((Method)entry.getValue(), ord)); 164 } 165 Collections.sort(list, new MethodComparator()); 166 List result = new ArrayList(size); 167 for (Iterator iter = list.iterator(); iter.hasNext();) { 168 result.add(((MethodRecord)iter.next()).method); 169 } 170 return result; 171 } 172 173 181 public Method overrideMethod(Method m, boolean superCall, boolean javadoc) { 182 try { 183 String bodyText = ""; 184 185 int mods = m.getModifiers() & ~(Modifier.NATIVE | Modifier.ABSTRACT | Modifier.SYNCHRONIZED); 189 if (superCall) { 191 bodyText = createSuperCall(m, isImplementedInSuper(root, m, false)); 192 } 193 MethodImpl miOrig; 194 195 if (m instanceof MethodImpl) 196 miOrig = (MethodImpl) m; 197 else 198 miOrig = ((MethodImpl) ((ParameterizedTypeImpl.Wrapper) m).getWrappedObject()); 199 200 MethodImpl newMethod = (MethodImpl) miOrig.duplicate((JavaModelPackage) root.refImmediatePackage()); 201 newMethod.setJavadocText(javadoc?miOrig.getJavadocText():null); 202 newMethod.setModifiers(mods); 203 newMethod.setBody(null); 204 newMethod.fixImports(root, m); 205 newMethod.setBodyText(bodyText); 206 addMethod(newMethod); 207 return newMethod; 208 } catch (InvalidObjectException e) { 209 ErrorManager.getDefault().notify(e); 210 return null; 211 } 212 } 213 214 private void addMethod(Method m) { 215 List contents = root.getContents(); 216 if (nextPosition != -1) { 217 contents.add(nextPosition, m); 218 nextPosition++; 219 return; 220 } 221 int index = -1; 222 ListIterator iter = contents.listIterator(); 223 for (int x = 0; iter.hasNext(); x++) { 224 Object obj = iter.next(); 225 if (!(obj instanceof JavaClass)) { 226 index = x; 227 } 228 } 229 if (index == -1) { 230 contents.add(m); 231 nextPosition = 1; 232 return; 233 } 234 235 JavaMetamodel manager = JavaMetamodel.getManager(); 236 iter = contents.listIterator(index + 1); 237 while (iter.hasPrevious()) { 238 NamedElement elem = (NamedElement) iter.previous(); 239 if (!manager.isElementGuarded(elem)) { 240 iter.next(); 241 iter.add(m); 242 nextPosition = contents.indexOf(m) + 1; 243 return; 244 } 245 } 246 247 contents.add(0, m); 248 nextPosition = 1; 249 } 250 251 public void addPropertyChangeListener(PropertyChangeListener l) { 252 pcs.addPropertyChangeListener(l); 253 } 254 255 public void removePropertyChangeListener(PropertyChangeListener l) { 256 pcs.removePropertyChangeListener(l); 257 } 258 259 public boolean isFinished() { 260 return task.isFinished(); 261 } 262 263 public void reset() { 264 classes = null; 265 classesList = null; 266 methods = null; 267 tree = null; 268 finalMethodsKeys = null; 269 ordNumCounter = 0; 270 task.schedule(0); 271 } 272 273 275 public void run() { 276 classes = new HashSet(); 277 classesList = new ArrayList(); 278 methods = new HashMap(); 279 tree = new HashMap(); 280 finalMethodsKeys = new HashSet(); 281 ordNumCounter = 0; 282 283 MDRepository repository = JavaMetamodel.getDefaultRepository(); 284 repository.beginTrans(false); 285 try { 286 JavaMetamodel model = JavaMetamodel.getManager(); 287 model.setClassPath(model.getFileObject(root.getResource()), true); 288 289 JavaClass superClass = root.getSuperClass(); 291 while (superClass != null && classes.add(superClass)) { 292 classesList.add(superClass); 293 HashSet meths = new HashSet(); 294 collectMethods(meths, superClass); 295 tree.put(superClass, meths); 296 superClass = superClass.getSuperClass(); 297 } 298 299 traverseInterfaces(classes, classesList, tree, root); 301 } finally { 302 repository.endTrans(); 303 } 304 } 305 306 private void traverseInterfaces(Set classes, List classesList, Map tree, ClassDefinition root) { 307 List interfaces = root.getInterfaces(); 308 for (Iterator iter = interfaces.iterator(); iter.hasNext(); ) { 309 JavaClass jc = (JavaClass) iter.next(); 310 if (classes.add(jc)) { 311 classesList.add(jc); 312 HashSet meths = new HashSet(); 313 collectMethods(meths, jc); 314 tree.put(jc, meths); 315 traverseInterfaces(classes, classesList, tree, jc); 316 } 317 } 318 } 319 320 322 public void taskFinished(Task task) { 323 pcs.firePropertyChange(PROP_FINISHED, Boolean.FALSE, Boolean.TRUE); 324 } 325 326 328 private boolean isAbstract(Method mte) { 329 ClassDefinition cd = mte.getDeclaringClass(); 330 return Modifier.isAbstract(mte.getModifiers()) || (cd instanceof JavaClass && ((JavaClass)cd).isInterface()); 331 } 332 333 334 private boolean isAccessibleMethod(Method m) { 335 ClassDefinition cls = m.getDeclaringClass(); 336 int modifs = cls instanceof JavaClass ? ((JavaClass)cls).getModifiers() : 0; 337 338 if ((modifs & Modifier.PRIVATE) != 0 || 339 ((modifs & (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE)) == 0 && 340 !isSamePackage(cls))) { 341 return false; 342 } 343 if ((cls instanceof JavaClass) && ((JavaClass)cls).isInterface()) 344 return true; 345 modifs = m.getModifiers(); 346 if ((modifs & Modifier.PRIVATE) != 0) { 347 return false; 348 } 349 if ((modifs & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) 350 return true; 351 return isSamePackage(cls); 352 } 353 354 357 private boolean isImplementedInSuper(ClassDefinition rootCl, Method m, boolean includeClass) { 358 String name = m.getName(); 359 List params = m.getParameters(); 360 List paramTypes = new ArrayList(params.size()); 361 for (Iterator iter = params.iterator(); iter.hasNext(); ) { 362 paramTypes.add(((Parameter)iter.next()).getType()); 363 } 364 365 ClassDefinition jc = includeClass ? rootCl : rootCl.getSuperClass(); 367 HashSet visited = new HashSet(); 368 while (jc != null && visited.add(jc)) { 369 Method mte = jc.getMethod(name, paramTypes, false); 370 if (mte != null && !Modifier.isAbstract(mte.getModifiers())) { 371 return true; 372 } 373 jc = jc.getSuperClass(); 374 } 375 return false; 376 } 377 378 private boolean isImplemented(Method m) { 379 String name = m.getName(); 380 List params = m.getParameters(); 381 List paramTypes = new ArrayList(params.size()); 382 for (Iterator iter = params.iterator(); iter.hasNext(); ) { 383 paramTypes.add(((Parameter)iter.next()).getType()); 384 } 385 386 ClassDefinition jc = root; 388 ClassDefinition realJc = jc instanceof ParameterizedType ? ((ParameterizedType) jc).getDefinition() : jc; 389 HashSet visited = new HashSet(); 390 visited.add(m.getDeclaringClass()); 391 while (jc != null && visited.add(realJc)) { 393 Method mte = jc.getMethod(name, paramTypes, false); 394 if (mte != null && !Modifier.isAbstract(mte.getModifiers())) { 395 return true; 396 } 397 jc = jc.getSuperClass(); 398 realJc = jc instanceof ParameterizedType ? ((ParameterizedType) jc).getDefinition() : jc; 399 } 400 return false; 401 } 402 403 409 private boolean isOverriden(Method m) { 410 List params = m.getParameters(); 411 String name = m.getName(); 412 List paramTypes = new ArrayList(params.size()); 413 for (Iterator iter = params.iterator(); iter.hasNext(); ) { 414 paramTypes.add(((Parameter)iter.next()).getType()); 415 } 416 ClassDefinition cd = root; 417 HashSet visited = new HashSet(); 418 while (cd != null && visited.add(cd)) { 419 Method meth = root.getMethod(name, paramTypes, false); 420 if (meth == m) 421 return false; 422 else if (meth != null) 423 return true; 424 cd = cd.getSuperClass(); 425 } 426 return false; 427 } 428 429 430 private boolean isSamePackage(ClassDefinition cd) { 431 String p1 = root.getResource().getPackageName(); 432 String p2 = cd.getResource().getPackageName(); 433 return p1 == null ? p2 == null : p1.equals(p2); 434 } 435 436 439 private void collectMethods(Set meths, JavaClass jc) { 440 for (Iterator iter = jc.getContents().iterator(); iter.hasNext(); ) { 441 Object obj = iter.next(); 442 if (!(obj instanceof Method)) 443 continue; 444 Method m = (Method)obj; 445 int mods = m.getModifiers(); 446 boolean modFlag = !Modifier.isStatic(mods) && (Modifier.isPublic(mods) || Modifier.isProtected(mods)); 447 boolean isFinal = Modifier.isFinal(mods); 448 if (modFlag && !isFinal && isAccessibleMethod(m) && !isOverriden(m)) { 449 MethodKey key = new MethodKey(m, ordNumCounter++); 450 if (!finalMethodsKeys.contains(key) && methods.get(key) == null) { 451 methods.put(key, m); 452 meths.add(key); 453 } 454 } else { 455 if (isFinal && modFlag) { 456 MethodKey key = new MethodKey(m, ordNumCounter++); 457 finalMethodsKeys.add(key); 458 } 459 } 460 } 461 462 for (Iterator iter = jc.getInterfaces().iterator(); iter.hasNext(); ) { 463 collectMethods(meths, (JavaClass) iter.next()); 464 } 465 } 466 467 private String createSuperCall(Method target, boolean hasSuper) { 468 JavaSynchronizationSettings syncSettings = (JavaSynchronizationSettings)SharedClassObject.findObject(JavaSynchronizationSettings.class, true); 469 470 String body; 471 472 if (hasSuper) { 473 String format; 475 476 StringBuffer str = new StringBuffer (); 477 for (Iterator iter = target.getParameters().iterator(); iter.hasNext(); ) { 478 Parameter par = (Parameter) iter.next(); 479 if (str.length() > 0) 480 str.append(", "); str.append(par.getName()); 482 } 483 Type t = target.getType(); 484 if (t instanceof PrimitiveType && PrimitiveTypeKindEnum.VOID.equals(((PrimitiveType)t).getKind())) { 485 format = NbBundle.getMessage(JMIInheritanceSupport.class, "FMT_CallSuper"); } else { 487 format = NbBundle.getMessage(JMIInheritanceSupport.class, "FMT_ReturnCallSuper"); } 489 body = java.text.MessageFormat.format(format, 490 new Object [] { 491 JavaModelUtil.resolveImportsForType(root, target.getType()).getName(), 492 target.getName(), 493 str 494 }); 495 } else { 496 body = syncSettings.getGenerateReturnAsString(target.getType()); 498 } 499 return body; 500 } 501 502 504 public static class MethodKey extends Object { 505 506 private String name; 507 private String [] paramTypes; 508 private int ordNumber; 509 510 public MethodKey (Method m) { 511 this(m, 0); 512 } 513 514 public MethodKey (Method m, int ordNumber) { 515 this.ordNumber = ordNumber; 516 name = m.getName(); 517 List params = m.getParameters(); 518 paramTypes = new String [params.size()]; 519 Iterator iter = params.iterator(); 520 for (int x = 0; iter.hasNext(); x++) { 521 paramTypes[x] = ((Parameter)iter.next()).getType().getName(); 522 } 523 } 524 525 public int getOrdNumber() { 526 return ordNumber; 527 } 528 529 530 public boolean equals (Object obj) { 531 if (!(obj instanceof MethodKey)) return false; 532 return name.equals(((MethodKey)obj).name) && Arrays.equals(paramTypes, ((MethodKey)obj).paramTypes); 533 } 534 535 539 public int hashCode () { 540 int length = paramTypes.length; 541 if (length == 0) return 0; 542 if (length == 1) return paramTypes[0].hashCode(); 543 return paramTypes[0].hashCode() ^ 544 paramTypes[length - 1].hashCode(); 545 } 546 547 } 548 549 private static class MethodRecord { 550 551 public Method method; 552 public int orderNumber; 553 554 MethodRecord(Method method, int orderNumber) { 555 this.method = method; 556 this.orderNumber = orderNumber; 557 } 558 559 } 560 561 private static class MethodComparator implements Comparator { 562 563 public int compare(Object o1, Object o2) { 564 if (o1 instanceof MethodRecord) { 565 if (o2 instanceof MethodRecord) { 566 return ((MethodRecord)o1).orderNumber - ((MethodRecord)o2).orderNumber; 567 } else { 568 return 1; 569 } 570 } else { 571 if (o2 instanceof MethodRecord) { 572 return -1; 573 } else { 574 return 0; 575 } 576 } 577 } 578 579 } 580 581 } 582 | Popular Tags |