1 19 20 package org.netbeans.modules.javacore; 21 import java.util.ArrayList ; 22 import java.util.HashMap ; 23 import org.netbeans.jmi.javamodel.Element; 24 import org.netbeans.jmi.javamodel.JavaModelPackage; 25 import org.netbeans.jmi.javamodel.Resource; 26 import org.netbeans.mdr.util.TransactionMutex; 27 import org.netbeans.modules.javacore.api.JavaModel; 28 import org.netbeans.modules.javacore.jmiimpl.javamodel.ResourceClassImpl; 29 import org.netbeans.modules.javacore.jmiimpl.javamodel.ResourceImpl; 30 import org.netbeans.modules.javacore.jmiimpl.javamodel.SemiPersistentElement; 31 import org.openide.ErrorManager; 32 import java.util.HashSet ; 33 import java.util.Iterator ; 34 import java.util.List ; 35 import java.util.Map ; 36 import java.util.Set ; 37 import org.netbeans.mdr.NBMDRepositoryImpl; 38 import org.netbeans.mdr.persistence.MOFID; 39 import org.netbeans.modules.javacore.jmiimpl.javamodel.BehavioralFeatureImpl; 40 import org.netbeans.modules.javacore.jmiimpl.javamodel.EnumConstantImpl; 41 import org.netbeans.modules.javacore.jmiimpl.javamodel.FieldImpl; 42 import org.netbeans.modules.javacore.internalapi.ExternalChange; 43 import org.netbeans.modules.javacore.internalapi.JavaMetamodel; 44 import org.netbeans.modules.javacore.classpath.FilterClassPathImplementation; 45 import org.netbeans.api.java.classpath.ClassPath; 46 import org.openide.filesystems.FileObject; 47 import javax.swing.SwingUtilities ; 48 import org.netbeans.modules.javacore.jmiimpl.javamodel.AttributeImpl; 49 import org.netbeans.modules.javacore.jmiimpl.javamodel.AttributeValueImpl; 50 51 55 public class ExclusiveMutex extends TransactionMutex { 56 private static final boolean DEBUG = false; 57 58 private boolean changes = false; 59 private boolean fail = false; 60 private Thread thread = null; 61 private int counter = 0; 62 private int modCount = 1; 63 private boolean isSafeTrans = false; 64 65 private Set newObjects = new HashSet (); 66 67 private Set changedRscSet = new HashSet (); 69 private Set changedExternalSet = new HashSet (); 70 private Set undoElementsSet = new HashSet (); 71 72 private Set upToDateElements = new HashSet (); 73 private Set invalidClasses = new HashSet (); 74 75 private List initBodyQueue; 77 78 private Map parserCache; 80 81 private Set needParsing = new HashSet (); 82 private Set needDelete = new HashSet (); 83 private Set needParsingRW = new HashSet (); 84 private Set needTSUpdate = new HashSet (); 85 private Set priorityThreads = null; 86 87 private ClassPath classPath = null; 88 private List searchScope = null; 89 private volatile boolean isSwingWaiting = false; 90 private JMManager manager = (JMManager) JMManager.getManager(); 91 92 private boolean modificationsDisabled = false; 93 94 95 public ExclusiveMutex(Object p1, Object p2, Object p3) { 96 super(p1, p2, p3); 97 } 98 99 public boolean isSwingWaiting() { 101 return isSwingWaiting; 102 } 103 104 public int getModCount() { 105 return modCount; 106 } 107 108 public boolean isSafeTrans() { 109 return isSafeTrans; 110 } 111 112 void setSafeTrans(boolean safeTrans) { 113 this.isSafeTrans = safeTrans; 114 } 115 116 public synchronized void addPriorityThread() { 117 if (priorityThreads == null) { 118 priorityThreads = new HashSet (); 119 } 120 priorityThreads.add(Thread.currentThread()); 121 } 122 123 public synchronized void enter(boolean writeAccess) { 124 Thread thread = Thread.currentThread(); 125 126 assert (counter > 0 && this.thread == thread) || JMManager.getDocumentLocksCounter() == null || JMManager.getDocumentLocksCounter().get() == null : "Document was locked before starting the MDR transaction."; 129 if (this.thread != thread) { 130 if (SwingUtilities.isEventDispatchThread()) addPriorityThread(); 131 boolean isPriorityThread = priorityThreads != null && priorityThreads.remove(thread); 132 while (!(counter == 0 && (!isSwingWaiting || isPriorityThread))) { 133 try { 134 isSwingWaiting |= isPriorityThread; 135 this.wait(); 140 } catch (InterruptedException e) { 141 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 142 } 143 } 144 this.thread = thread; 148 149 if (isPriorityThread) { 150 if (priorityThreads != null && priorityThreads.isEmpty()) { 152 priorityThreads = null; 153 } 154 isSwingWaiting = priorityThreads != null; 155 } 156 157 modCount++; 158 if (modCount == 0) modCount = 1; 159 160 if (JMManager.TRANS_DEBUG) { 161 Thread.dumpStack(); 162 } 163 } 164 165 counter++; 166 167 if (writeAccess) { 168 if (!changes) { 169 changes = true; 170 start(); 171 } 172 } 173 174 if (counter == 1) { 175 boolean success = false; 176 try { 177 parseIfNeeded(writeAccess); 178 success = true; 179 } finally { 180 if (!success) { 181 try { 182 if (changes && counter == 1) { 183 end(true); 184 notifyElements(); 185 ClassIndex.rollback(); 186 } 187 } catch (RuntimeException x) { 188 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, x); 190 } finally { 191 finalizeTrans(); 192 } 193 } 194 } 195 clearClassPath(); 196 clearParserCache(); 197 } 198 } 199 200 private void clearClassPath() { 201 classPath = null; 202 searchScope = null; 203 } 204 205 private void clearParserCache() { 206 parserCache=null; 207 } 208 209 private void parseIfNeeded(boolean writeAccess) { 210 boolean isEmpty; 211 FileObject[] fos; 212 213 synchronized (needDelete) { 214 isEmpty = needDelete.isEmpty(); 215 } 216 217 if (!isEmpty) { 218 synchronized (needDelete) { 219 fos = (FileObject[]) needDelete.toArray(new FileObject[needDelete.size()]); 220 if (DEBUG) { 221 System.err.println("cleaning needDelete"); Thread.dumpStack(); 223 } 224 needDelete.clear(); 225 } 226 for (int i = 0; i < fos.length; i++) { 227 FileObject fo = fos[i]; 228 ResourceImpl res; 229 230 FileObject cpRoot = Util.getCPRoot(fo); 231 if (cpRoot == null) return; 233 JavaModelPackage modelPckg = manager.resolveJavaExtent(cpRoot); 234 if (modelPckg==null) return; 235 Resource resource = (ResourceImpl) ((ResourceClassImpl) modelPckg.getResource()).resolveResource( 236 manager.getResourceName(fo), false, false); 237 238 if (resource!=null) { 239 resource.refDelete(); 240 } 241 } 242 } 243 244 synchronized (needParsingRW) { 245 isEmpty = needParsingRW.isEmpty(); 246 } 247 if (!isEmpty) { 248 synchronized (needParsingRW) { 249 fos = (FileObject[]) needParsingRW.toArray(new FileObject[needParsingRW.size()]); 250 needParsingRW.clear(); 251 } 252 253 for (int i = 0; i < fos.length; i++) { 254 FileObject fobj=fos[i]; 255 256 if (!fobj.isValid()) continue; 257 JavaModel.setClassPath(fobj); 258 RepositoryUpdater.getDefault().createOrUpdateResource(fobj); 259 needParsing.remove(fobj); 260 } 261 } 262 263 if (writeAccess) { 264 synchronized (needParsing) { 265 isEmpty = needParsing.isEmpty(); 266 } 267 268 if (!isEmpty) { 269 synchronized (needParsing) { 270 fos = (FileObject[]) needParsing.toArray(new FileObject[needParsing.size()]); 271 if (DEBUG) { 272 System.err.println("cleaning needParsing"); Thread.dumpStack(); 274 } 275 needParsing.clear(); 276 } 277 for (int i = 0; i < fos.length; i++) { 278 FileObject fobj=fos[i]; 279 ResourceImpl res; 280 281 if (!fobj.isValid()) continue; 282 JavaModel.setClassPath(fobj); 283 res = (ResourceImpl) ((JMManager) JavaMetamodel.getManager()).getResource(fobj, false); 284 if (res != null) { 285 res.updateFromFileObject(fobj,true); 286 } 287 } 288 } 289 } 290 291 synchronized (needTSUpdate) { 292 isEmpty = needTSUpdate.isEmpty(); 293 } 294 if (!isEmpty) { 295 synchronized (needTSUpdate) { 296 fos = (FileObject[]) needTSUpdate.toArray(new FileObject[needTSUpdate.size()]); 297 needTSUpdate.clear(); 298 } 299 300 for (int i = 0; i < fos.length; i++) { 301 FileObject fo = fos[i]; 302 if (!fo.isValid()) continue; 303 RepositoryUpdater.updateTimeStamp(fo); 304 } 305 } 306 } 307 308 public Thread getThread() { 309 return thread; 310 } 311 312 public void addModified(FileObject fo) { 313 if (DEBUG) { 314 System.out.println("adding " + fo + " to needParsing"); Thread.dumpStack(); 316 } 317 synchronized (needParsing) { 318 needParsing.add(fo); 319 } 320 } 321 322 void addDeleted(FileObject fo) { 323 synchronized (needDelete) { 324 needDelete.add(fo); 325 } 326 } 327 328 void addModifiedRW(FileObject fo) { 329 synchronized (needParsingRW) { 330 synchronized (needParsing) { 331 needParsingRW.add(fo); 332 needParsing.remove(fo); 333 } 334 } 335 } 336 337 void addUpdateTS(FileObject fo) { 338 synchronized (needTSUpdate) { 339 needTSUpdate.add(fo); 340 } 341 } 342 343 public synchronized boolean leave(boolean fail) { 344 assert thread == Thread.currentThread() : "Cannot end transaction from a different thread!"; if (fail) { 346 JMManager.getLog().notify(ErrorManager.INFORMATIONAL,new Exception ("rollback!!!")); } 348 boolean result = false; 349 try { 350 if (changes) { 351 this.fail |= fail; 352 } else { 353 if (fail) throw new RuntimeException ("Cannot fail in read mode."); } 355 356 if (counter == 1) { 357 result = true; 358 if (changes) { 359 if (this.fail) { 361 end(true); 362 notifyElements(); 363 ClassIndex.rollback(); 364 } else { 365 notifyElements(); 366 end(false); 367 ClassIndex.commit(); 368 } 369 } 370 } 371 } catch (RuntimeException x) { 372 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, x); 373 this.fail = true; 374 try { 375 end(true); 376 } catch (RuntimeException e) { 377 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 378 } 379 try { 380 notifyElements(); 381 } catch (RuntimeException e) { 382 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 383 } 384 try { 385 ClassIndex.rollback(); 386 } catch (RuntimeException e) { 387 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 388 } 389 } finally { 390 finalizeTrans(); 391 } 392 return result; 393 } 394 395 private void finalizeTrans() { 396 if (counter > 0) { 397 counter--; 398 if (counter == 0) { 399 this.modificationsDisabled = false; 400 this.isSafeTrans = false; 401 this.thread = null; 402 this.fail = false; 403 changes = false; 404 clearClassPath(); 405 clearParserCache(); 406 this.notifyAll(); 407 } 408 } else { 409 throw new RuntimeException ("Error: leave() without enter()."); } 411 } 412 413 void setClassPath(List cp, boolean preferSources) { 414 classPath = FilterClassPathImplementation.createClassPath(cp, preferSources); 415 } 416 417 public void setSearchScope(List cp) { 418 searchScope = cp; 419 } 420 421 List getSearchScope() { 422 return searchScope; 423 } 424 425 public ClassPath getClassPath() { 426 return classPath; 427 } 428 429 public synchronized Map getParserCache() { 430 if (parserCache==null) 431 parserCache=new HashMap (); 432 return parserCache; 433 } 434 435 public void invalidateAtCommit(Element element) { 436 invalidClasses.add(element); 437 } 438 439 public boolean pendingChanges() { 440 return changes; 441 } 442 443 public boolean willFail() { 444 return fail; 445 } 446 447 public void registerChange(ResourceImpl resource) { 448 changedRscSet.add(resource); 449 } 450 451 public void registerPersisted(SemiPersistentElement element) { 452 upToDateElements.add(element._getMofId()); 453 } 454 455 public void unregisterChange(ResourceImpl resource) { 456 changedRscSet.remove(resource); 457 } 458 459 public void registerExtChange(ExternalChange change) { 460 changedExternalSet.add(change); 461 } 462 463 public void registerUndoElement(ExternalChange change) { 464 undoElementsSet.add(change); 465 } 466 467 public void addNew(Element h) { 468 newObjects.add(h); 469 } 470 471 public void removeNew(Element h) { 472 newObjects.remove(h); 473 } 474 475 public void addBFeatureToInitQueue(Object bf) { 476 initBodyQueue.add(bf); 477 } 478 479 private void notifyElements() { 480 if (!upToDateElements.isEmpty()) { 481 for (Iterator it = upToDateElements.iterator(); it.hasNext();) { 482 Object element = ((NBMDRepositoryImpl) JavaMetamodel.getDefaultRepository()).getByMofId((MOFID) it.next()); 483 if (element != null) { 484 ((SemiPersistentElement) element).clearPersist(this.fail); 485 } 486 } 487 if (!this.fail) { 488 upToDateElements.clear(); 489 } 490 } 491 if (!modificationsDisabled && (!changedRscSet.isEmpty() || !changedExternalSet.isEmpty() || !undoElementsSet.isEmpty())) { 492 JavaMetamodel.getUndoManager().transactionStarted(); 493 } 494 495 try { 496 if (!modificationsDisabled && !this.fail) { 497 for (Iterator it = undoElementsSet.iterator(); it.hasNext();) { 498 JavaMetamodel.getUndoManager().addItem((ExternalChange) it.next()); 499 } 500 } 501 initBodyQueue = new ArrayList (); 502 if (this.fail || !modificationsDisabled) { 503 if (!changedRscSet.isEmpty()) { 504 JMManager.initIndentation(); 505 for (Iterator resIt = changedRscSet.iterator(); resIt.hasNext(); ) { 506 ResourceImpl resource = (ResourceImpl) resIt.next(); 507 if (this.fail) { 508 resource.rollbackChanges(); 509 } else { 510 resource.commitChanges(); 511 if (!newObjects.isEmpty()) { 512 throw new RuntimeException ("Some objects were not added to a resource or deleted before commit."); } 514 } 515 } 516 } 517 } 518 519 if (!this.fail) { 520 for (Iterator it = invalidClasses.iterator(); it.hasNext();) { 521 Element el = (Element) it.next(); 522 if (el.isValid()) { 523 el.refDelete(); 524 } 525 it.remove(); 526 } 527 ResourceImpl resource; 528 Iterator resIt; 529 for (resIt = changedRscSet.iterator(); resIt.hasNext(); ) { 530 resource = (ResourceImpl) resIt.next(); 531 resource.parseResource(); 532 } 533 for (resIt = changedRscSet.iterator(); resIt.hasNext(); ) { 534 resource = (ResourceImpl) resIt.next(); 535 resource.commitConfirmed(); 536 FileObject fo = ((JMManager) JavaMetamodel.getManager()).getFileObject(resource); 537 if (DEBUG) System.out.println("removing " + fo + " from needParsing"); synchronized (needParsing) { 539 needParsing.remove(fo); 540 } 541 synchronized (needParsing) { 542 needParsingRW.remove(fo); 543 } 544 } 545 } 546 while (!initBodyQueue.isEmpty()) { 547 Object bf = initBodyQueue.remove(0); 548 if (bf instanceof BehavioralFeatureImpl) { 549 ((BehavioralFeatureImpl)bf).initBody(); 550 } else if (bf instanceof FieldImpl) { 551 ((FieldImpl)bf).initInitValue(); 552 } else if (bf instanceof EnumConstantImpl) { 553 ((EnumConstantImpl) bf).initInitValue(); 554 } else if (bf instanceof AttributeImpl) { 555 ((AttributeImpl) bf).initDefaultValue(); 556 } else { 557 ((AttributeValueImpl) bf).initInitValue(); 558 } 559 } 560 561 initBodyQueue=null; 562 563 if (!this.fail && !modificationsDisabled) { 564 for (Iterator it = changedExternalSet.iterator(); it.hasNext(); ) { 565 ExternalChange change = (ExternalChange) it.next(); 566 JavaMetamodel.getUndoManager().addItem(change); 567 change.performExternalChange(); 568 } 569 } 570 } finally { 571 if (!modificationsDisabled && (!changedRscSet.isEmpty() || !changedExternalSet.isEmpty() || !undoElementsSet.isEmpty())) { 572 JavaMetamodel.getUndoManager().transactionEnded(this.fail); 573 } 574 changedExternalSet.clear(); 575 undoElementsSet.clear(); 576 changedRscSet.clear(); 577 newObjects.clear(); 578 } 579 } 580 581 public void disableModifications() { 582 modificationsDisabled = true; 583 } 584 585 boolean isModified(FileObject fileObject) { 586 synchronized(needParsing) { 587 return needParsing.contains(fileObject); 588 } 589 } 590 } 591 | Popular Tags |