? .cvsignore Index: apichanges.xml =================================================================== RCS file: /cvs/java/source/apichanges.xml,v retrieving revision 1.7 diff -u -r1.7 apichanges.xml --- apichanges.xml 16 Apr 2007 15:54:19 -0000 1.7 +++ apichanges.xml 19 Apr 2007 13:40:52 -0000 @@ -83,6 +83,21 @@ + + + Added a method to run a CancellableTask when the backgound scan is finished. + + + + + + The JavaSource.runWhenScanFinished performs the given task either synchronously when no background scan is running. When the background + scan is running the task is performed asynchronously when the scan completes. + + + + + Added a method which returns all the project source roots depending on a given source root. Index: nbproject/project.properties =================================================================== RCS file: /cvs/java/source/nbproject/project.properties,v retrieving revision 1.17 diff -u -r1.17 project.properties --- nbproject/project.properties 17 Apr 2007 14:31:14 -0000 1.17 +++ nbproject/project.properties 19 Apr 2007 13:40:52 -0000 @@ -23,5 +23,5 @@ javadoc.title=Java Source javadoc.arch=${basedir}/arch.xml javadoc.apichanges=${basedir}/apichanges.xml -spec.version.base=0.11.0 +spec.version.base=0.12.0 test.unit.run.cp.extra=${core.dir}/core/core.jar:${core.dir}/lib/boot.jar:../../junit/external/insanelib.jar Index: src/org/netbeans/api/java/source/JavaSource.java =================================================================== RCS file: /cvs/java/source/src/org/netbeans/api/java/source/JavaSource.java,v retrieving revision 1.42 diff -u -r1.42 JavaSource.java --- src/org/netbeans/api/java/source/JavaSource.java 18 Apr 2007 19:11:25 -0000 1.42 +++ src/org/netbeans/api/java/source/JavaSource.java 19 Apr 2007 13:40:52 -0000 @@ -111,7 +111,6 @@ import org.openide.filesystems.FileEvent; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileRenameEvent; -import org.openide.filesystems.FileStateInvalidException; import org.openide.filesystems.FileUtil; import org.openide.filesystems.FileUtil; import org.openide.loaders.DataObject; @@ -230,6 +229,7 @@ private final static SingleThreadFactory factory = new SingleThreadFactory (); private final static CurrentRequestReference currentRequest = new CurrentRequestReference (); private final static EditorRegistryListener editorRegistryListener = new EditorRegistryListener (); + private final static List todo = Collections.synchronizedList(new LinkedList()); //Only single thread can operate on the single javac private final static ReentrantLock javacLock = new ReentrantLock (true); @@ -540,6 +540,66 @@ } } } + + + /** + * Performs the given task when the scan finished. When no background scan is running + * it performs the given task synchronously. When the background scan is active it queues + * the given task and returns, the task is performed when the background scan completes by + * the thread doing the background scan. + * @param task to be performed + * @param shared if true the java compiler may be reused by other {@link org.netbeans.api.java.source.CancellableTasks}, + * the value false may have negative impact on the IDE performance. + * @since 0.12 + */ + public void runWhenScanFinished (final CancellableTask task, final boolean shared) throws IOException { + assert task != null; + final Request r = new Request (task,this,null,null,shared); + //0) Add speculatively task to be performed at the end of background scan + todo.add (r); + //1) Try to aquire javac lock, if successfull no task is running + // perform the given taks synchronously if it wasn't already performed + // by background scan. + final boolean locked = javacLock.tryLock(); + if (locked) { + try { + if (todo.remove(r)) { + runUserActionTask(task, shared); + } + } finally { + javacLock.unlock(); + } + } + else { + //Otherwise interrupt currently running task and try to aquire lock + do { + final JavaSource.Request[] request = new JavaSource.Request[1]; + boolean isScanner = false; + if (request[0] == null) { + isScanner = currentRequest.getUserTaskToCancel(request); + } + try { + if (isScanner) { + return; + } + if (request[0] != null) { + request[0].task.cancel(); + } + if (javacLock.tryLock()) { + try { + if (todo.remove(r)) { + runUserActionTask(task, shared); + } + } finally { + javacLock.unlock(); + } + } + } finally { + currentRequest.cancelCompleted(request[0]); + } + } while (true); + } + } /** Runs a task which permits for modifying the sources. * Call to this method will cancel processig of all the phase completion tasks until @@ -1126,7 +1186,7 @@ Request otherRequest = (Request) other; return priority == otherRequest.priority && reschedule == otherRequest.reschedule - && phase.equals (otherRequest.phase) + && phase == null ? otherRequest.phase == null : phase.equals (otherRequest.phase) && task.equals(otherRequest.task); } else { @@ -1176,7 +1236,21 @@ assert r.reschedule == false; javacLock.lock (); try { - r.task.run (null); + try { + r.task.run (null); + } finally { + boolean cancelled = requests.contains(r); + if (!cancelled) { + Request[] _todo; + synchronized (todo) { + _todo = todo.toArray(new Request[todo.size()]); + todo.clear(); + } + for (Request rq : _todo) { + rq.javaSource.runUserActionTask((CancellableTask)rq.task, rq.reschedule); + } + } + } } catch (RuntimeException re) { Exceptions.printStackTrace(re); } @@ -1660,6 +1734,40 @@ } } return request; + } + + /** + * Called by {@link JavaSource#runWhenScanFinished} to find out which + * task is currently running. Returns true when the running task in backgroud + * scan otherwise returns false. The caller is expected not to call cancel on + * the background scanner, so this method do not reset reference and do not set + * cancelled flag when running task is background scan. But it sets the canceledReference + * to prevent java source thread to dispatch next queued task. + * @param request is filled by currently running task or null when there is no running task. + * @return true when running task is background scan + */ + public boolean getUserTaskToCancel (JavaSource.Request[] request) { + assert request != null; + assert request.length == 1; + boolean result = false; + if (!factory.isDispatchThread(Thread.currentThread())) { + synchronized (this) { + request[0] = this.reference; + if (request[0] != null) { + result = request[0].phase == null; + assert this.canceledReference == null || result; + this.canceledReference = request[0]; + if (!result) { + this.reference = null; + } + this.canceled = result; + if (reportSlowTasks) { + cancelTime = System.currentTimeMillis(); + } + } + } + } + return result; } public synchronized boolean isCanceled () {