1.1 --- a/openide.util/apichanges.xml Wed Jun 17 03:52:56 2009 +0400
1.2 +++ b/openide.util/apichanges.xml Fri Jun 19 03:44:33 2009 +0400
1.3 @@ -49,6 +49,21 @@
1.4 <apidef name="actions">Actions API</apidef>
1.5 </apidefs>
1.6 <changes>
1.7 + <change id="enableStackTraces">
1.8 + <api name="util"/>
1.9 + <summary>Added constructor <code>RequestProcessor(String name, int throughput, boolean interruptThread, boolean enableStackTraces)</code></summary>
1.10 + <version major="7" minor="24"/>
1.11 + <date day="8" month="6" year="2009"/>
1.12 + <author login="rmichalsky"/>
1.13 + <compatibility addition="yes"/>
1.14 + <description>
1.15 + <p>
1.16 + Newly added constructor allows to disable (slow) filling stack traces before posting each task.
1.17 + </p>
1.18 + </description>
1.19 + <class package="org.openide.util" name="RequestProcessor"/>
1.20 + <issue number="165862"/>
1.21 + </change>
1.22 <change id="ImageUtilities.loadImageIcon">
1.23 <api name="util"/>
1.24 <summary>Added <code>loadImageIcon(String resource, boolean localized)</code></summary>
2.1 --- a/openide.util/nbproject/project.properties Wed Jun 17 03:52:56 2009 +0400
2.2 +++ b/openide.util/nbproject/project.properties Fri Jun 19 03:44:33 2009 +0400
2.3 @@ -42,7 +42,7 @@
2.4 module.jar.dir=lib
2.5 cp.extra=${nb_all}/apisupport.harness/external/openjdk-javac-6-b12.jar
2.6
2.7 -spec.version.base=7.23.0
2.8 +spec.version.base=7.24.0
2.9
2.10 # For XMLSerializer, needed for XMLUtil.write to work w/ namespaces under JDK 1.4:
2.11
3.1 --- a/openide.util/src/org/openide/util/RequestProcessor.java Wed Jun 17 03:52:56 2009 +0400
3.2 +++ b/openide.util/src/org/openide/util/RequestProcessor.java Fri Jun 19 03:44:33 2009 +0400
3.3 @@ -173,6 +173,8 @@
3.4
3.5 /** support for interrupts or not? */
3.6 private boolean interruptThread;
3.7 + /** fill stacktraces when task is posted? */
3.8 + private boolean enableStackTraces;
3.9
3.10 /** Creates new RequestProcessor with automatically assigned unique name. */
3.11 public RequestProcessor() {
3.12 @@ -221,11 +223,34 @@
3.13 * @since 6.3
3.14 */
3.15 public RequestProcessor(String name, int throughput, boolean interruptThread) {
3.16 + this(name, throughput, interruptThread, SLOW);
3.17 + }
3.18 +
3.19 + /** Creates a new named <code>RequestProcessor</code> that allows to disable stack trace filling.
3.20 + * By default, when assertions are on, each task posted on <code>RequestProcessor</code> stores
3.21 + * the stack trace at the time of posting. When an exception is later thrown from the task,
3.22 + * it allows to print not only stack trace of the task but also stack trace of the code that posted it.
3.23 + * However this may be a performance bottleneck in cases when hundreds of short task are scheduled.
3.24 + * This constructor then allows to create <code>RequestProcessor</code> which never stores stack traces
3.25 + * at the time of posting.
3.26 + * <p>
3.27 + * See constructor {@link #RequestProcessor(String, int, boolean)} for details of <code>interruptThread</code>
3.28 + * parameter.
3.29 + * </p>
3.30 + * @param name the name to use for the request processor thread
3.31 + * @param throughput the maximal count of requests allowed to run in parallel
3.32 + * @param interruptThread true if {@link RequestProcessor.Task#cancel} shall interrupt the thread
3.33 + * @param enableStackTraces <code>false</code> when request processor should not fill stack traces when task is posted.
3.34 + * Default is <code>true</code> when assertions are enabled, <code>false</code> otherwise.
3.35 + * @since 7.24
3.36 + */
3.37 + public RequestProcessor(String name, int throughput, boolean interruptThread, boolean enableStackTraces) {
3.38 this.throughput = throughput;
3.39 this.name = (name != null) ? name : ("OpenIDE-request-processor-" + (counter++));
3.40 this.interruptThread = interruptThread;
3.41 + this.enableStackTraces = enableStackTraces;
3.42 }
3.43 -
3.44 +
3.45
3.46 /** The getter for the shared instance of the <CODE>RequestProcessor</CODE>.
3.47 * This instance is shared by anybody who
3.48 @@ -627,7 +652,9 @@
3.49 item.clear(null);
3.50 }
3.51
3.52 - item = new Item(this, RequestProcessor.this);
3.53 + item = enableStackTraces ?
3.54 + new SlowItem(this, RequestProcessor.this) :
3.55 + new FastItem(this, RequestProcessor.this);
3.56 localItem = item;
3.57 }
3.58
3.59 @@ -813,8 +840,8 @@
3.60 /* One item representing the task pending in the pending queue */
3.61 private static class Item extends Exception {
3.62 private final RequestProcessor owner;
3.63 - private Object action;
3.64 - private boolean enqueued;
3.65 + Object action;
3.66 + boolean enqueued;
3.67 String message;
3.68
3.69 Item(Task task, RequestProcessor rp) {
3.70 @@ -849,33 +876,46 @@
3.71 return getTask().getPriority();
3.72 }
3.73
3.74 - @Override
3.75 - public Throwable fillInStackTrace() {
3.76 - if (SLOW) {
3.77 - Throwable ret = super.fillInStackTrace();
3.78 - StackTraceElement[] arr = ret.getStackTrace();
3.79 - for (int i = 1; i < arr.length; i++) {
3.80 - if (arr[i].getClassName().startsWith("java.lang")) {
3.81 - continue;
3.82 - }
3.83 - if (arr[i].getClassName().startsWith(RequestProcessor.class.getName())) {
3.84 - continue;
3.85 - }
3.86 - ret.setStackTrace(Arrays.asList(arr).subList(i - 1, arr.length).toArray(new StackTraceElement[0]));
3.87 - break;
3.88 - }
3.89 - return ret;
3.90 - } else {
3.91 - return this;
3.92 - }
3.93 - }
3.94 -
3.95 public @Override String getMessage() {
3.96 return message;
3.97 }
3.98
3.99 }
3.100
3.101 + private static class FastItem extends Item {
3.102 + FastItem(Task task, RequestProcessor rp) {
3.103 + super(task, rp);
3.104 + }
3.105 +
3.106 + @Override
3.107 + public Throwable fillInStackTrace() {
3.108 + return this;
3.109 + }
3.110 + }
3.111 + private static class SlowItem extends Item {
3.112 +
3.113 + SlowItem(Task task, RequestProcessor rp) {
3.114 + super(task, rp);
3.115 + }
3.116 +
3.117 + @Override
3.118 + public Throwable fillInStackTrace() {
3.119 + Throwable ret = super.fillInStackTrace();
3.120 + StackTraceElement[] arr = ret.getStackTrace();
3.121 + for (int i = 1; i < arr.length; i++) {
3.122 + if (arr[i].getClassName().startsWith("java.lang")) {
3.123 + continue;
3.124 + }
3.125 + if (arr[i].getClassName().startsWith(RequestProcessor.class.getName())) {
3.126 + continue;
3.127 + }
3.128 + ret.setStackTrace(Arrays.asList(arr).subList(i - 1, arr.length).toArray(new StackTraceElement[0]));
3.129 + break;
3.130 + }
3.131 + return ret;
3.132 + }
3.133 + }
3.134 +
3.135 //------------------------------------------------------------------------------
3.136 // The Processor management implementation
3.137 //------------------------------------------------------------------------------
4.1 --- a/openide.util/test/unit/src/org/openide/util/RequestProcessorTest.java Wed Jun 17 03:52:56 2009 +0400
4.2 +++ b/openide.util/test/unit/src/org/openide/util/RequestProcessorTest.java Fri Jun 19 03:44:33 2009 +0400
4.3 @@ -45,6 +45,7 @@
4.4 import java.util.logging.Handler;
4.5 import java.util.logging.LogRecord;
4.6 import java.util.logging.Level;
4.7 +import java.util.logging.Logger;
4.8 import junit.framework.Test;
4.9 import org.openide.ErrorManager;
4.10 import org.netbeans.junit.*;
4.11 @@ -1346,7 +1347,80 @@
4.12 x.notifyAll();
4.13 }
4.14 }
4.15 -
4.16 +
4.17 + private static class TestHandler extends Handler {
4.18 + boolean stFilled = false;
4.19 + boolean exceptionCaught = false;
4.20 +
4.21 + @Override
4.22 + public void publish(LogRecord rec) {
4.23 + if (rec.getThrown() != null) {
4.24 + for (StackTraceElement elem : rec.getThrown().getStackTrace()) {
4.25 + if (elem.getMethodName().contains("testStackTraceFillingDisabled")) {
4.26 + stFilled = true;
4.27 + break;
4.28 + }
4.29 + }
4.30 + exceptionCaught = true;
4.31 + }
4.32 + }
4.33 +
4.34 + public void clear() {
4.35 + stFilled = false;
4.36 + exceptionCaught = false;
4.37 + }
4.38 +
4.39 + @Override
4.40 + public void flush() {
4.41 + }
4.42 +
4.43 + @Override
4.44 + public void close() throws SecurityException {
4.45 + }
4.46 + }
4.47 +
4.48 + public void testStackTraceFillingDisabled() throws InterruptedException {
4.49 + boolean ea = false;
4.50 + assert (ea = true);
4.51 + assertTrue("Test must be run with enabled assertions", ea);
4.52 + Logger l = RequestProcessor.logger();
4.53 + TestHandler handler = new TestHandler();
4.54 + l.addHandler(handler);
4.55 + try {
4.56 + RequestProcessor rp = new RequestProcessor("test rp #1", 1);
4.57 + Task t = rp.post(new Runnable() {
4.58 +
4.59 + public void run() {
4.60 + throw new RuntimeException("Testing filled stacktrace");
4.61 + }
4.62 + });
4.63 +// t.waitFinished(); // does not work, thread gets notified before the exception is logged
4.64 + int timeout = 0;
4.65 + while (! handler.exceptionCaught && timeout++ < 100) {
4.66 + Thread.sleep(50);
4.67 + }
4.68 + assertTrue("Waiting for task timed out", timeout < 100);
4.69 + assertTrue("Our testing method not found in stack trace", handler.stFilled);
4.70 +
4.71 + handler.clear();
4.72 + timeout = 0;
4.73 + rp = new RequestProcessor("test rp #2", 1, false, false);
4.74 + t = rp.post(new Runnable() {
4.75 +
4.76 + public void run() {
4.77 + throw new RuntimeException("Testing 'short' stacktrace");
4.78 + }
4.79 + });
4.80 + while (! handler.exceptionCaught && timeout++ < 100) {
4.81 + Thread.sleep(50);
4.82 + }
4.83 + assertTrue("Waiting for task timed out", timeout < 100);
4.84 + assertFalse("Our testing method found in stack trace", handler.stFilled);
4.85 + } finally {
4.86 + l.removeHandler(handler);
4.87 + }
4.88 + }
4.89 +
4.90 private static void doGc (int count, Reference toClear) {
4.91 java.util.ArrayList<byte[]> l = new java.util.ArrayList<byte[]> (count);
4.92 while (count-- > 0) {