diff --git a/openide.filesystems/src/org/openide/filesystems/JarFileSystem.java b/openide.filesystems/src/org/openide/filesystems/JarFileSystem.java --- a/openide.filesystems/src/org/openide/filesystems/JarFileSystem.java +++ b/openide.filesystems/src/org/openide/filesystems/JarFileSystem.java @@ -89,7 +89,7 @@ static final long serialVersionUID = -98124752801761145L; /** One request proccesor shared for all instances of JarFileSystem*/ - private static RequestProcessor req = new RequestProcessor("JarFs - modification watcher"); // NOI18N + private static RequestProcessor req = new RequestProcessor("JarFs - modification watcher", 1, false, false); // NOI18N /** Controlls the LocalFileSystem's automatic refresh. * If the refresh time interval is set from the System.property, than this value is used. diff --git a/openide.util/apichanges.xml b/openide.util/apichanges.xml --- a/openide.util/apichanges.xml +++ b/openide.util/apichanges.xml @@ -49,6 +49,21 @@ Actions API + + + Added constructor RequestProcessor(String name, int throughput, boolean interruptThread, boolean enableStackTraces) + + + + + +

+ Newly added constructor allows to disable (slow) filling stack traces before posting each task. +

+
+ + +
Added loadImageIcon(String resource, boolean localized) diff --git a/openide.util/nbproject/project.properties b/openide.util/nbproject/project.properties --- a/openide.util/nbproject/project.properties +++ b/openide.util/nbproject/project.properties @@ -42,7 +42,7 @@ module.jar.dir=lib cp.extra=${nb_all}/apisupport.harness/external/openjdk-javac-6-b12.jar -spec.version.base=7.23.0 +spec.version.base=7.24.0 # For XMLSerializer, needed for XMLUtil.write to work w/ namespaces under JDK 1.4: diff --git a/openide.util/src/org/openide/util/RequestProcessor.java b/openide.util/src/org/openide/util/RequestProcessor.java --- a/openide.util/src/org/openide/util/RequestProcessor.java +++ b/openide.util/src/org/openide/util/RequestProcessor.java @@ -173,6 +173,8 @@ /** support for interrupts or not? */ private boolean interruptThread; + /** fill stacktraces when task is posted? */ + private boolean enableStackTraces; /** Creates new RequestProcessor with automatically assigned unique name. */ public RequestProcessor() { @@ -221,9 +223,32 @@ * @since 6.3 */ public RequestProcessor(String name, int throughput, boolean interruptThread) { + this(name, throughput, interruptThread, SLOW); + } + + /** Creates a new named RequestProcessor that allows to disable stack trace filling. + * By default, when assertions are on, each task posted on RequestProcessor stores + * the stack trace at the time of posting. When an exception is later thrown from the task, + * it allows to print not only stack trace of the task but also stack trace of the code that posted it. + * However this may be a performance bottleneck in cases when hundreds of short task are scheduled. + * This constructor then allows to create RequestProcessor which never stores stack traces + * at the time of posting. + *

+ * See constructor {@link #RequestProcessor(String, int, boolean)} for details of interruptThread + * parameter. + *

+ * @param name the name to use for the request processor thread + * @param throughput the maximal count of requests allowed to run in parallel + * @param interruptThread true if {@link RequestProcessor.Task#cancel} shall interrupt the thread + * @param enableStackTraces false when request processor should not fill stack traces when task is posted. + * Default is true when assertions are enabled, false otherwise. + * @since 7.24 + */ + public RequestProcessor(String name, int throughput, boolean interruptThread, boolean enableStackTraces) { this.throughput = throughput; this.name = (name != null) ? name : ("OpenIDE-request-processor-" + (counter++)); this.interruptThread = interruptThread; + this.enableStackTraces = enableStackTraces; } @@ -627,7 +652,9 @@ item.clear(null); } - item = new Item(this, RequestProcessor.this); + item = enableStackTraces ? + new SlowItem(this, RequestProcessor.this) : + new FastItem(this, RequestProcessor.this); localItem = item; } @@ -813,8 +840,8 @@ /* One item representing the task pending in the pending queue */ private static class Item extends Exception { private final RequestProcessor owner; - private Object action; - private boolean enqueued; + Object action; + boolean enqueued; String message; Item(Task task, RequestProcessor rp) { @@ -849,31 +876,44 @@ return getTask().getPriority(); } - @Override - public Throwable fillInStackTrace() { - if (SLOW) { - Throwable ret = super.fillInStackTrace(); - StackTraceElement[] arr = ret.getStackTrace(); - for (int i = 1; i < arr.length; i++) { - if (arr[i].getClassName().startsWith("java.lang")) { - continue; - } - if (arr[i].getClassName().startsWith(RequestProcessor.class.getName())) { - continue; - } - ret.setStackTrace(Arrays.asList(arr).subList(i - 1, arr.length).toArray(new StackTraceElement[0])); - break; - } - return ret; - } else { - return this; - } - } - public @Override String getMessage() { return message; } + } + + private static class FastItem extends Item { + FastItem(Task task, RequestProcessor rp) { + super(task, rp); + } + + @Override + public Throwable fillInStackTrace() { + return this; + } + } + private static class SlowItem extends Item { + + SlowItem(Task task, RequestProcessor rp) { + super(task, rp); + } + + @Override + public Throwable fillInStackTrace() { + Throwable ret = super.fillInStackTrace(); + StackTraceElement[] arr = ret.getStackTrace(); + for (int i = 1; i < arr.length; i++) { + if (arr[i].getClassName().startsWith("java.lang")) { + continue; + } + if (arr[i].getClassName().startsWith(RequestProcessor.class.getName())) { + continue; + } + ret.setStackTrace(Arrays.asList(arr).subList(i - 1, arr.length).toArray(new StackTraceElement[0])); + break; + } + return ret; + } } //------------------------------------------------------------------------------ diff --git a/openide.util/test/unit/src/org/openide/util/RequestProcessorTest.java b/openide.util/test/unit/src/org/openide/util/RequestProcessorTest.java --- a/openide.util/test/unit/src/org/openide/util/RequestProcessorTest.java +++ b/openide.util/test/unit/src/org/openide/util/RequestProcessorTest.java @@ -45,6 +45,7 @@ import java.util.logging.Handler; import java.util.logging.LogRecord; import java.util.logging.Level; +import java.util.logging.Logger; import junit.framework.Test; import org.openide.ErrorManager; import org.netbeans.junit.*; @@ -1346,7 +1347,80 @@ x.notifyAll(); } } - + + private static class TestHandler extends Handler { + boolean stFilled = false; + boolean exceptionCaught = false; + + @Override + public void publish(LogRecord rec) { + if (rec.getThrown() != null) { + for (StackTraceElement elem : rec.getThrown().getStackTrace()) { + if (elem.getMethodName().contains("testStackTraceFillingDisabled")) { + stFilled = true; + break; + } + } + exceptionCaught = true; + } + } + + public void clear() { + stFilled = false; + exceptionCaught = false; + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + } + + public void testStackTraceFillingDisabled() throws InterruptedException { + boolean ea = false; + assert (ea = true); + assertTrue("Test must be run with enabled assertions", ea); + Logger l = RequestProcessor.logger(); + TestHandler handler = new TestHandler(); + l.addHandler(handler); + try { + RequestProcessor rp = new RequestProcessor("test rp #1", 1); + Task t = rp.post(new Runnable() { + + public void run() { + throw new RuntimeException("Testing filled stacktrace"); + } + }); +// t.waitFinished(); // does not work, thread gets notified before the exception is logged + int timeout = 0; + while (! handler.exceptionCaught && timeout++ < 100) { + Thread.sleep(50); + } + assertTrue("Waiting for task timed out", timeout < 100); + assertTrue("Our testing method not found in stack trace", handler.stFilled); + + handler.clear(); + timeout = 0; + rp = new RequestProcessor("test rp #2", 1, false, false); + t = rp.post(new Runnable() { + + public void run() { + throw new RuntimeException("Testing 'short' stacktrace"); + } + }); + while (! handler.exceptionCaught && timeout++ < 100) { + Thread.sleep(50); + } + assertTrue("Waiting for task timed out", timeout < 100); + assertFalse("Our testing method found in stack trace", handler.stFilled); + } finally { + l.removeHandler(handler); + } + } + private static void doGc (int count, Reference toClear) { java.util.ArrayList l = new java.util.ArrayList (count); while (count-- > 0) {