1 19 20 package org.netbeans.modules.java.parser; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.beans.PropertyChangeSupport ; 25 import java.lang.ref.Reference ; 26 import java.lang.ref.ReferenceQueue ; 27 import java.lang.ref.WeakReference ; 28 import java.util.*; 29 import java.io.InputStream ; 30 import java.io.IOException ; 31 32 import javax.swing.event.ChangeListener ; 33 import javax.swing.event.ChangeEvent ; 34 35 import org.netbeans.api.java.classpath.ClassPath; 36 37 import org.openide.nodes.Node; 38 import org.openide.src.*; 39 import org.openide.text.CloneableEditorSupport; 40 import org.openide.util.RequestProcessor; 41 import org.openide.util.Task; 42 import org.openide.util.Utilities; 43 44 import org.netbeans.modules.java.bridge.LangModel; 45 import org.netbeans.modules.java.bridge.CommitListener; 46 import org.netbeans.modules.java.bridge.SrcElementImpl; 47 48 import org.netbeans.modules.java.codegen.DocumentBinding; 49 import org.netbeans.modules.java.ParserEngine; 50 import org.netbeans.modules.java.ElementFactory; 51 import org.netbeans.modules.java.JavaDataObject; 52 53 64 public class ParsingSupport implements JavaParser { 65 66 private PropertyChangeSupport propSupport; 67 68 public static final String PROP_STATUS = "status"; 70 private static final boolean DEBUG = false; 71 72 74 private boolean valid; 75 76 80 private boolean updating; 81 82 private boolean clean; 83 84 private Env parsingEnv; 85 86 89 private ParserEngine engine; 90 91 95 private SourceException savedException; 96 97 102 private SourceElement src; 103 104 108 private Processor currentRequest; 109 110 113 private Processor runningRequest; 114 115 118 LangModel model; 119 120 123 LangModel.Updater updater; 124 125 128 private Reference refImplementation; 129 130 134 private int status; 135 136 139 Collection changeList; 140 141 DocumentBinding docBinding; 142 143 JavaDataObject jdo; 144 145 149 public ParsingSupport(Env parsingEnv, JavaDataObject jdo, DocumentBinding docBinding, 150 LangModel.Updater updater, LangModel model) { 151 this.parsingEnv = parsingEnv; 152 this.jdo = jdo; 153 this.docBinding = docBinding; 154 this.updater = updater; 155 this.model = model; 156 this.valid = true; 157 } 158 159 public void addChangeListener(ChangeListener l) { 160 if (changeList == null) { 161 synchronized (this) { 162 if (changeList == null) 163 changeList = new LinkedList(); 164 } 165 } 166 synchronized (changeList) { 167 changeList.add(l); 168 } 169 } 170 171 public void removeChangeListener(ChangeListener l) { 172 if (changeList == null) 173 return; 174 synchronized (changeList) { 175 changeList.remove(l); 176 } 177 } 178 179 182 public void addPropertyChangeListener(PropertyChangeListener l) { 183 if (propSupport == null) { 184 synchronized (this) { 185 if (propSupport == null) 186 propSupport = new PropertyChangeSupport (this); 187 } 188 } 189 propSupport.addPropertyChangeListener(l); 190 } 191 192 195 public void removePropertyChangeListener(PropertyChangeListener l) { 196 if (propSupport == null) 197 return; 198 propSupport.removePropertyChangeListener(l); 199 } 200 201 209 public Task parse(int priority, boolean ignoreClean, boolean acceptErrors) { 210 Thread.dumpStack(); 211 return Task.EMPTY; 215 } 216 217 public Task parse(int priority, boolean ignoreClean, boolean acceptErrors, ParsableObjectRequest req) { 218 219 if (req.getParserType () == JavaParser.MDR_PARSER) { 220 return new FinishedTask(null); 223 } 224 225 Processor immediate; 226 SourceElement.Impl i = null; 227 CloneableEditorSupport editSupport = docBinding.getEditorSupport(); 231 synchronized (this) { 232 if (DEBUG) { 233 System.err.println("Got parse request, prio = " + priority + " ignoreClean = " + ignoreClean + " acceptErrs = " + acceptErrors); i = getSourceImpl(); 235 System.err.println("Data = " + i + " clean = " + this.clean); System.err.println("Parsing task = " + currentRequest + "/" + runningRequest); } 238 if (currentRequest != null) { 239 if (PARSING_RP.isRequestProcessorThread()) { 242 if (DEBUG) 243 System.err.println("Running in parsing thread!"); immediate = currentRequest; 245 } else { 246 currentRequest.enableErrors(acceptErrors); 247 currentRequest.setPriority(priority); 248 if (DEBUG) 249 System.err.println("Returning task from current request " + currentRequest); return currentRequest.getClientTask(); 251 } 252 } else { 253 i = getSourceImpl(); 254 if (i != null && this.clean && !ignoreClean) { 255 if (DEBUG) 256 System.err.println("Returning finished task"); return new FinishedTask(i); 258 } 259 Processor proc = new Processor(priority, parsingEnv, editSupport,req); 260 proc.enableErrors(acceptErrors); 261 if (PARSING_RP != null && PARSING_RP.isRequestProcessorThread()) { 262 immediate = proc; 263 } else { 264 addRequest(proc, priority); 265 return proc.getClientTask(); 266 } 267 } 268 } 269 immediate.run(); 270 i = getSourceImpl(); 271 return new FinishedTask(i); 272 } 273 public synchronized Task getCurrentTask() { 274 if (currentRequest!=null) 275 return currentRequest.getClientTask(); 276 return new FinishedTask(null); 277 } 278 279 private static class FinishedTask extends Task { 280 private Object hook; 281 282 public FinishedTask(Object o) { 283 super(null); 284 hook = o; 285 } 286 } 287 288 public void fireElementPropertyChange(Element source, PropertyChangeEvent evt) { 289 if (source == getSource()) { 290 ((SrcElementImpl) getSourceImpl ()).propertyChange(evt); 291 } else { 292 updater.firePropertyChange(source, evt); 293 } 294 } 295 296 299 public ParserEngine getParserEngine() { 300 return this.engine; 301 } 302 303 306 public void setParserEngine(ParserEngine eng) { 307 this.engine = eng; 308 } 309 310 316 public Task prepare() { 317 return Task.EMPTY; } 319 320 public SourceElement getSource() { 321 if (src == null) 322 src = jdo.getSource (); 323 return src; 324 332 } 333 334 339 public void invalidate() { 340 SourceElement.Impl impl; 341 synchronized (this) { 342 if (!valid) 343 return; 344 impl = getSourceImpl(); 345 if (impl == null) 346 return; 347 valid = false; 348 } 349 updater.invalidateModel(getSource()); 350 synchronized (this) { 351 if (!updating) 352 refImplementation = null; 353 } 354 changeStatus(SourceElement.STATUS_NOT); 355 } 356 357 358 protected void changeStatus(int newStatus) { 359 int oldStatus = status; 360 status = newStatus; 361 if (propSupport != null && propSupport.hasListeners(null)) 362 propSupport.firePropertyChange(PROP_STATUS, oldStatus, newStatus); 363 fireStateChange(); 364 } 365 366 protected void fireStateChange() { 367 if (changeList == null) 368 return; 369 Collection copy; 370 371 synchronized (changeList) { 372 if (changeList.isEmpty()) 373 return; 374 copy = new ArrayList(changeList); 375 } 376 ChangeEvent e = new ChangeEvent (this); 377 378 for (Iterator it = copy.iterator(); it.hasNext(); ) { 379 try { 380 ((ChangeListener )it.next()).stateChanged(e); 381 } catch (RuntimeException x) { 382 org.openide.ErrorManager.getDefault().notify(org.openide.ErrorManager.WARNING, x); 383 } 384 } 385 } 386 387 public SourceElement.Impl getSourceImpl() { 388 SourceElement sourceElem = getSource (); 389 if (sourceElem == null) 390 return null; 391 return (SourceElement.Impl) sourceElem.getCookie (SourceElement.Impl.class); 392 } 393 394 public LangModel getModel() { 395 return this.model; 396 } 397 398 public SourceElement.Impl findSourceImpl() throws SourceException { 399 synchronized (this) { 400 SourceElement.Impl impl = getSourceImpl(); 401 if (impl != null) 402 return impl; 403 Util.log("impl = null"); if (savedException != null) 405 throw savedException; 406 } 407 throw new SourceException("Cannot acquire source"); } 409 410 414 public void sourceChanged(int from, int to) { 415 Processor req = currentRequest; 416 417 clean = false; 418 if (req != null) 419 req.sourceChanged(); 420 } 421 422 427 public SourceException getErrorCause() { 428 return savedException; 429 } 430 431 432 433 Node.Cookie findCookieForSource(Class type) { 434 if (src == null) 435 return null; 436 return parsingEnv.findCookie(getSource(), type); 437 } 438 439 443 public int getStatus() { 444 int s = status; 445 if (s != SourceElement.STATUS_OK) 446 return s; 447 SourceElement.Impl impl = getSourceImpl(); 448 if (impl == null) 449 changeStatus(SourceElement.STATUS_NOT); 450 return status; 451 } 452 453 public Task addParsingRunnable(Runnable r, int priority) { 454 return PARSING_RP.post(r, 0, priority); 455 } 456 457 458 static final Runnable EMPTY_RUNNABLE = new Runnable () { 459 public void run() {} 460 }; 461 462 466 class Processor extends Object implements 467 Runnable , CommitListener, ParseObjectRequest { 468 Processor chained; 469 int priority; 470 RequestProcessor.Task ownTask; 471 boolean errorsOK; 472 int stage; 474 int resultStatus; 475 ParsableObjectRequest request; 476 T task; 477 478 Processor(int priority, Env env, CloneableEditorSupport supp,ParsableObjectRequest req) { 479 request=req; 480 task = new T(); 481 request.setEnvironment(env); 482 request.setEditorSupport(supp); 483 } 484 485 490 protected void directRun() { 491 do { 492 run(); 493 } while (stage >= 0); 494 } 495 496 public void setPriority(int prior) { 497 if (this.priority > prior) 498 return; 499 priority = prior; 500 if (ownTask.cancel()) { 503 addRequest(this, prior); 504 } 505 } 506 507 public void enableErrors(boolean enable) { 508 errorsOK |= enable; 509 } 510 511 public void chainRequest(Processor other) { 512 chained = other; 513 } 514 515 public void setProcessorTask(RequestProcessor.Task t) { 516 ownTask = t; 517 } 518 519 public void run() { 520 Util.log("processing request " + this + " stage " + stage); try { 522 switch (stage++) { 523 case 0: 524 if (DEBUG) { 525 System.err.println("Starting request " + this); } 527 parseLockModel(); 528 break; 529 case 1: 530 break; 531 } 532 } catch (SourceException.IO e) { 533 resultStatus = SourceElement.STATUS_ERROR; 535 } catch (Throwable e) { 536 savedException = new SourceException(e.getLocalizedMessage()); 537 parsingEnv.annotateThrowable(savedException, e); 538 parsingEnv.annotateThrowable(savedException, "Parser error", false); org.openide.ErrorManager.getDefault().notify(e); 540 resultStatus = SourceElement.STATUS_ERROR; 541 } finally { 542 stage--; 543 } 544 Util.log("request " + this + " stage " + (stage + 1) + " end"); if (stage > 0) 546 return; 547 548 if (resultStatus != -1) { 549 complete(); 550 } else { 551 request.notifyReschedule(); 553 Util.log("Rescheduling request"); stage = 0; 555 addRequest(this, priority); 556 } 557 } 558 559 private void parseLockModel() throws SourceException { 560 model.addPreCommitListener(this); 561 resultStatus = -1; 562 synchronized (ParsingSupport.this) { 563 runningRequest = this; 564 Util.log("Running request = " + this); } 566 savedException = null; 567 try { 568 runningRequest = this; 569 process(getParserEngine()); 570 if (isValid()) { 571 Util.log("Request " + this + " processed. Still valid"); stage = 1; 573 Util.log("trying to run update"); resultStatus = SourceElement.STATUS_OK; 576 } 577 } catch (IOException ex) { 578 savedException = new SourceException.IO(ex); 579 parsingEnv.annotateThrowable(savedException, ex); 580 resultStatus = SourceElement.STATUS_ERROR; 582 } catch (InternalError er) { 583 savedException = new SourceException(er.getMessage()); 585 parsingEnv.annotateThrowable(savedException, er); 586 resultStatus = SourceElement.STATUS_ERROR; 587 } finally { 588 model.removePreCommitListener(this); 589 } 590 runningRequest = null; 591 } 592 593 public void complete() { 594 synchronized (ParsingSupport.this) { 595 if (currentRequest == this) 596 currentRequest = null; 597 } 598 changeStatus(resultStatus); 599 task.complete(); 600 if (chained != null) 601 chained.complete(); 602 stage = -1; 604 } 605 606 public void changesCommited(Set created, Set removed, Map changed) { 607 request.modelChanged(); 608 } 609 610 614 public void process(ParserEngine eng) throws IOException { 615 eng.process(this); 616 } 617 618 623 public Task getClientTask() { 624 return task; 625 } 626 627 631 public void sourceChanged() { 632 request.sourceChanged(); 633 } 634 635 636 public void setSyntaxErrors(int errors) { 637 request.setSyntaxErrors(errors); 638 } 639 640 public void setSemanticErrors(int errors) { 641 request.setSemanticErrors(errors); 642 } 643 644 public void notifyStart() { 645 request.notifyStart(); 646 } 647 648 public void notifyComplete() { 649 request.notifyComplete(); 650 } 651 652 public boolean isValid() { 653 return request.isValid(); 654 } 655 656 public boolean needsProcessing() { 657 return request.needsProcessing(); 658 } 659 660 public int getSyntaxErrors() { 661 return request.getSyntaxErrors(); 662 } 663 664 public Collection getMessages() { 665 return request.getMessages(); 666 } 667 668 public ElementFactory getFactory() { 669 return request.getFactory(); 670 } 671 672 public char[] getSource() throws java.io.IOException { 673 clean = true; 674 return request.getSource(); 675 } 676 677 public InputStream findCompiledClass(String className) { 678 return request.findCompiledClass(className); 679 } 680 681 public Object getParserType() { 682 return request.getParserType(); 683 } 684 685 public String getSourceName() { 686 return request.getSourceName(); 687 } 688 689 public ClassPath getSourcePath() { 690 return request.getSourcePath(); 691 } 692 693 public ClassPath getLibraryPath() { 694 return request.getLibraryPath(); 695 } 696 697 public ClassPath getBootClassPath() { 698 return request.getBootClassPath(); 699 } 700 701 702 703 706 private class T extends org.openide.util.Task { 707 T() { 708 super(EMPTY_RUNNABLE); 709 } 710 711 public void run() { 712 Processor.this.directRun(); 713 } 714 715 protected void complete() { 716 super.notifyFinished(); 717 } 718 } 719 } 720 721 722 static RequestProcessor PARSING_RP; 723 724 private void addRequest(Processor proc, int priority) { 725 synchronized (this) { 726 if (PARSING_RP == null) { 727 PARSING_RP = new RequestProcessor("Java source parsing"); } 729 if (currentRequest != proc) { 730 if (currentRequest != null) 731 proc.chainRequest(currentRequest); 732 currentRequest = proc; 733 } 734 proc.setProcessorTask(PARSING_RP.post(proc, 0, priority)); 735 } 736 } 737 738 protected void registerData(SourceElement.Impl data) { 739 Reference newRef; 740 741 synchronized (ParsingSupport.class) { 742 newRef = new DataFinalizer(this, data, Utilities.activeReferenceQueue()); 743 } 744 synchronized (this) { 745 refImplementation = newRef; 746 } 747 } 748 749 protected void notifyFinalized(Reference refImpl) { 750 751 synchronized (this) { 752 if (refImplementation != refImpl) 753 return; 754 refImplementation = null; 755 } 756 changeStatus(SourceElement.STATUS_NOT); 757 } 758 759 private static class DataFinalizer extends WeakReference implements Runnable { 760 Reference refSupp; 761 762 DataFinalizer(ParsingSupport supp, Object data, ReferenceQueue rqueue) { 763 super(data, rqueue); 764 refSupp = new WeakReference (supp); 765 } 766 767 public void run() { 768 ParsingSupport supp = (ParsingSupport)refSupp.get(); 769 if (supp != null) 770 supp.notifyFinalized(this); 771 } 772 } 773 } 774 | Popular Tags |