RequestProcessor(String name, int throughput, boolean interruptThread, boolean enableStackTraces)
+ Newly added constructor allows to disable (slow) filling stack traces before posting each task. +
+loadImageIcon(String resource, boolean localized)
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.
+ *
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