diff --git a/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/concurrent/RequestManagerTest.xtend b/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/concurrent/RequestManagerTest.xtend index e68e88b60..d9b7b0e23 100644 --- a/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/concurrent/RequestManagerTest.xtend +++ b/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/concurrent/RequestManagerTest.xtend @@ -9,16 +9,22 @@ package org.eclipse.xtext.ide.tests.server.concurrent import com.google.inject.Guice import com.google.inject.Inject +import java.util.concurrent.ExecutionException import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger +import org.apache.log4j.Level import org.eclipse.xtext.ide.server.ServerModule import org.eclipse.xtext.ide.server.concurrent.RequestManager +import org.eclipse.xtext.testing.logging.LoggingTester import org.junit.After import org.junit.Before import org.junit.Ignore import org.junit.Test import static org.junit.Assert.* +import org.junit.Assert +import org.eclipse.xtext.ide.server.concurrent.WriteRequest +import org.eclipse.xtext.ide.server.concurrent.ReadRequest /** * @author kosyakov - Initial contribution and API @@ -42,6 +48,80 @@ class RequestManagerTest { sharedState = null } + @Test(timeout = 1000) + def void testRunWriteLogExceptionNonCancellable() { + val logResult = LoggingTester.captureLogging(Level.ALL, WriteRequest, [ + val future = requestManager.runWrite([], [ + throw new RuntimeException(); + ]) + + // join future to assert log later + try { + future.join + } catch (Exception e) {} + ]) + + logResult.assertLogEntry("Error during request:") + } + + @Test(timeout = 1000) + def void testRunWriteLogExceptionCancellable() { + val logResult = LoggingTester.captureLogging(Level.ALL, WriteRequest, [ + val future = requestManager.runWrite([ + throw new RuntimeException(); + ], []) + + // join future to assert log later + try { + future.join + } catch (Exception e) {} + ]) + + logResult.assertLogEntry("Error during request:") + } + + @Test(timeout = 1000, expected = ExecutionException) + def void testRunWriteCatchException() { + LoggingTester.captureLogging(Level.ALL, WriteRequest, [ + val future = requestManager.runWrite([ + throw new RuntimeException() + ], []) + + assertEquals('Foo', future.get) + ]) + + Assert.fail("unreachable") + } + + @Test(timeout = 1000) + def void testRunReadLogException() { + val logResult = LoggingTester.captureLogging(Level.ALL, ReadRequest, [ + val future = requestManager.runRead([ + throw new RuntimeException(); + ]) + + // join future to assert log later + try { + future.join + } catch (Exception e) {} + ]) + + logResult.assertLogEntry("Error during request:") + } + + @Test(timeout = 1000, expected = ExecutionException) + def void testRunReadCatchException() { + LoggingTester.captureLogging(Level.ALL, ReadRequest, [ + val future = requestManager.runRead([ + throw new RuntimeException() + ]) + + assertEquals('Foo', future.get) + ]) + + Assert.fail + } + @Test(timeout = 1000) def void testRunRead() { val future = requestManager.runRead [ @@ -132,5 +212,4 @@ class RequestManagerTest { Thread.sleep(10) } } - } diff --git a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/concurrent/RequestManagerTest.java b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/concurrent/RequestManagerTest.java index 375317879..f661a4b16 100644 --- a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/concurrent/RequestManagerTest.java +++ b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/concurrent/RequestManagerTest.java @@ -10,10 +10,15 @@ package org.eclipse.xtext.ide.tests.server.concurrent; import com.google.inject.Guice; import com.google.inject.Inject; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import org.apache.log4j.Level; import org.eclipse.xtext.ide.server.ServerModule; +import org.eclipse.xtext.ide.server.concurrent.ReadRequest; import org.eclipse.xtext.ide.server.concurrent.RequestManager; +import org.eclipse.xtext.ide.server.concurrent.WriteRequest; +import org.eclipse.xtext.testing.logging.LoggingTester; import org.eclipse.xtext.util.CancelIndicator; import org.eclipse.xtext.xbase.lib.Exceptions; import org.eclipse.xtext.xbase.lib.Functions.Function0; @@ -49,6 +54,109 @@ public class RequestManagerTest { this.sharedState = null; } + @Test(timeout = 1000) + public void testRunWriteLogExceptionNonCancellable() { + final Runnable _function = () -> { + final Function0 _function_1 = () -> { + return null; + }; + final Function2 _function_2 = (CancelIndicator $0, Object $1) -> { + throw new RuntimeException(); + }; + final CompletableFuture future = this.requestManager.runWrite(_function_1, _function_2); + try { + future.join(); + } catch (final Throwable _t) { + if (_t instanceof Exception) { + } else { + throw Exceptions.sneakyThrow(_t); + } + } + }; + final LoggingTester.LogCapture logResult = LoggingTester.captureLogging(Level.ALL, WriteRequest.class, _function); + logResult.assertLogEntry("Error during request:"); + } + + @Test(timeout = 1000) + public void testRunWriteLogExceptionCancellable() { + final Runnable _function = () -> { + final Function0 _function_1 = () -> { + throw new RuntimeException(); + }; + final Function2 _function_2 = (CancelIndicator $0, Object $1) -> { + return null; + }; + final CompletableFuture future = this.requestManager.runWrite(_function_1, _function_2); + try { + future.join(); + } catch (final Throwable _t) { + if (_t instanceof Exception) { + } else { + throw Exceptions.sneakyThrow(_t); + } + } + }; + final LoggingTester.LogCapture logResult = LoggingTester.captureLogging(Level.ALL, WriteRequest.class, _function); + logResult.assertLogEntry("Error during request:"); + } + + @Test(timeout = 1000, expected = ExecutionException.class) + public void testRunWriteCatchException() { + final Runnable _function = () -> { + try { + final Function0 _function_1 = () -> { + throw new RuntimeException(); + }; + final Function2 _function_2 = (CancelIndicator $0, Object $1) -> { + return null; + }; + final CompletableFuture future = this.requestManager.runWrite(_function_1, _function_2); + Assert.assertEquals("Foo", future.get()); + } catch (Throwable _e) { + throw Exceptions.sneakyThrow(_e); + } + }; + LoggingTester.captureLogging(Level.ALL, WriteRequest.class, _function); + Assert.fail("unreachable"); + } + + @Test(timeout = 1000) + public void testRunReadLogException() { + final Runnable _function = () -> { + final Function1 _function_1 = (CancelIndicator it) -> { + throw new RuntimeException(); + }; + final CompletableFuture future = this.requestManager.runRead(_function_1); + try { + future.join(); + } catch (final Throwable _t) { + if (_t instanceof Exception) { + } else { + throw Exceptions.sneakyThrow(_t); + } + } + }; + final LoggingTester.LogCapture logResult = LoggingTester.captureLogging(Level.ALL, ReadRequest.class, _function); + logResult.assertLogEntry("Error during request:"); + } + + @Test(timeout = 1000, expected = ExecutionException.class) + public void testRunReadCatchException() { + final Runnable _function = () -> { + try { + final Function1 _function_1 = (CancelIndicator it) -> { + throw new RuntimeException(); + }; + final CompletableFuture future = this.requestManager.runRead(_function_1); + Assert.assertEquals("Foo", future.get()); + } catch (Throwable _e) { + throw Exceptions.sneakyThrow(_e); + } + }; + LoggingTester.captureLogging(Level.ALL, ReadRequest.class, _function); + Assert.fail(); + } + @Test(timeout = 1000) public void testRunRead() { try { diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/concurrent/RequestManager.xtend b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/concurrent/RequestManager.xtend index 2332d31d8..57fe2a407 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/concurrent/RequestManager.xtend +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/concurrent/RequestManager.xtend @@ -13,6 +13,7 @@ import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletionException import java.util.concurrent.ExecutorService import java.util.concurrent.Executors +import org.apache.log4j.Logger import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor import org.eclipse.xtext.service.OperationCanceledManager import org.eclipse.xtext.util.CancelIndicator @@ -42,14 +43,14 @@ class RequestManager { def CompletableFuture runRead((CancelIndicator)=>V cancellable) { return submit( - new ReadRequest(cancellable, parallel) + new ReadRequest(this, cancellable, parallel) ) } def CompletableFuture runWrite(()=>U nonCancellable, (CancelIndicator, U)=>V cancellable) { val cancelFuture = cancel() return submit( - new WriteRequest(nonCancellable, cancellable, cancelFuture) + new WriteRequest(this, nonCancellable, cancellable, cancelFuture) ) } @@ -81,6 +82,7 @@ class RequestManager { @FinalFieldsConstructor class ReadRequest extends AbstractRequest { + static final Logger LOG = Logger.getLogger(ReadRequest); val (CancelIndicator)=>V cancellable val ExecutorService executor @@ -92,6 +94,9 @@ class ReadRequest extends AbstractRequest { cancelIndicator.checkCanceled result.complete(cancellable.apply(cancelIndicator)) } catch(Throwable e) { + if (e !== null && !requestManager.isCancelException(e)) { + LOG.error("Error during request: ", e); + } result.completeExceptionally(e) } ] @@ -101,6 +106,7 @@ class ReadRequest extends AbstractRequest { @FinalFieldsConstructor class WriteRequest extends AbstractRequest { + static final Logger LOG = Logger.getLogger(WriteRequest); val ()=>U nonCancellable val (CancelIndicator, U)=>V cancellable @@ -118,6 +124,9 @@ class WriteRequest extends AbstractRequest { cancelIndicator.checkCanceled result.complete(cancellable.apply(cancelIndicator, intermediateResult)) } catch(Throwable e) { + if (e !== null && !requestManager.isCancelException(e)) { + LOG.error("Error during request: ", e); + } result.completeExceptionally(e) } } @@ -128,6 +137,11 @@ abstract class AbstractRequest implements Runnable, Cancellable { protected val result = new CompletableFuture() protected val cancelIndicator = new RequestCancelIndicator(result) + protected val RequestManager requestManager; + + new (RequestManager requestManager) { + this.requestManager = requestManager; + } override cancel() { cancelIndicator.cancel diff --git a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/AbstractRequest.java b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/AbstractRequest.java index b82882ec3..1cc6a086f 100644 --- a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/AbstractRequest.java +++ b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/AbstractRequest.java @@ -10,6 +10,7 @@ package org.eclipse.xtext.ide.server.concurrent; import java.util.concurrent.CompletableFuture; import org.eclipse.xtext.ide.server.concurrent.Cancellable; import org.eclipse.xtext.ide.server.concurrent.RequestCancelIndicator; +import org.eclipse.xtext.ide.server.concurrent.RequestManager; @SuppressWarnings("all") public abstract class AbstractRequest implements Runnable, Cancellable { @@ -17,6 +18,12 @@ public abstract class AbstractRequest implements Runnable, Can protected final RequestCancelIndicator cancelIndicator = new RequestCancelIndicator(this.result); + protected final RequestManager requestManager; + + public AbstractRequest(final RequestManager requestManager) { + this.requestManager = requestManager; + } + @Override public void cancel() { this.cancelIndicator.cancel(); diff --git a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/ReadRequest.java b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/ReadRequest.java index 31d46812d..0044b1d08 100644 --- a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/ReadRequest.java +++ b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/ReadRequest.java @@ -9,8 +9,10 @@ package org.eclipse.xtext.ide.server.concurrent; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; +import org.apache.log4j.Logger; import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor; import org.eclipse.xtext.ide.server.concurrent.AbstractRequest; +import org.eclipse.xtext.ide.server.concurrent.RequestManager; import org.eclipse.xtext.util.CancelIndicator; import org.eclipse.xtext.xbase.lib.Exceptions; import org.eclipse.xtext.xbase.lib.Functions.Function1; @@ -18,6 +20,8 @@ import org.eclipse.xtext.xbase.lib.Functions.Function1; @FinalFieldsConstructor @SuppressWarnings("all") public class ReadRequest extends AbstractRequest { + private static final Logger LOG = Logger.getLogger(ReadRequest.class); + private final Function1 cancellable; private final ExecutorService executor; @@ -40,7 +44,14 @@ public class ReadRequest extends AbstractRequest { } catch (final Throwable _t) { if (_t instanceof Throwable) { final Throwable e = (Throwable)_t; - _xtrycatchfinallyexpression = this.result.completeExceptionally(e); + boolean _xblockexpression_1 = false; + { + if (((e != null) && (!this.requestManager.isCancelException(e)))) { + ReadRequest.LOG.error("Error during request: ", e); + } + _xblockexpression_1 = this.result.completeExceptionally(e); + } + _xtrycatchfinallyexpression = _xblockexpression_1; } else { throw Exceptions.sneakyThrow(_t); } @@ -50,8 +61,8 @@ public class ReadRequest extends AbstractRequest { this.executor.submit(_function); } - public ReadRequest(final Function1 cancellable, final ExecutorService executor) { - super(); + public ReadRequest(final RequestManager requestManager, final Function1 cancellable, final ExecutorService executor) { + super(requestManager); this.cancellable = cancellable; this.executor = executor; } diff --git a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/RequestManager.java b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/RequestManager.java index 1e8ccc057..279c04726 100644 --- a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/RequestManager.java +++ b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/RequestManager.java @@ -49,13 +49,13 @@ public class RequestManager { } public CompletableFuture runRead(final Function1 cancellable) { - ReadRequest _readRequest = new ReadRequest(cancellable, this.parallel); + ReadRequest _readRequest = new ReadRequest(this, cancellable, this.parallel); return this.submit(_readRequest); } public CompletableFuture runWrite(final Function0 nonCancellable, final Function2 cancellable) { final CompletableFuture cancelFuture = this.cancel(); - WriteRequest _writeRequest = new WriteRequest(nonCancellable, cancellable, cancelFuture); + WriteRequest _writeRequest = new WriteRequest(this, nonCancellable, cancellable, cancelFuture); return this.submit(_writeRequest); } diff --git a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/WriteRequest.java b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/WriteRequest.java index 1803899d2..621dc5fa5 100644 --- a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/WriteRequest.java +++ b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/concurrent/WriteRequest.java @@ -8,8 +8,10 @@ package org.eclipse.xtext.ide.server.concurrent; import java.util.concurrent.CompletableFuture; +import org.apache.log4j.Logger; import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor; import org.eclipse.xtext.ide.server.concurrent.AbstractRequest; +import org.eclipse.xtext.ide.server.concurrent.RequestManager; import org.eclipse.xtext.util.CancelIndicator; import org.eclipse.xtext.xbase.lib.Exceptions; import org.eclipse.xtext.xbase.lib.Functions.Function0; @@ -18,6 +20,8 @@ import org.eclipse.xtext.xbase.lib.Functions.Function2; @FinalFieldsConstructor @SuppressWarnings("all") public class WriteRequest extends AbstractRequest { + private static final Logger LOG = Logger.getLogger(WriteRequest.class); + private final Function0 nonCancellable; private final Function2 cancellable; @@ -41,6 +45,9 @@ public class WriteRequest extends AbstractRe } catch (final Throwable _t) { if (_t instanceof Throwable) { final Throwable e = (Throwable)_t; + if (((e != null) && (!this.requestManager.isCancelException(e)))) { + WriteRequest.LOG.error("Error during request: ", e); + } this.result.completeExceptionally(e); } else { throw Exceptions.sneakyThrow(_t); @@ -48,8 +55,8 @@ public class WriteRequest extends AbstractRe } } - public WriteRequest(final Function0 nonCancellable, final Function2 cancellable, final CompletableFuture previous) { - super(); + public WriteRequest(final RequestManager requestManager, final Function0 nonCancellable, final Function2 cancellable, final CompletableFuture previous) { + super(requestManager); this.nonCancellable = nonCancellable; this.cancellable = cancellable; this.previous = previous; diff --git a/org.eclipse.xtext/src/org/eclipse/xtext/service/OperationCanceledManager.java b/org.eclipse.xtext/src/org/eclipse/xtext/service/OperationCanceledManager.java index 2c47de6b7..c80823e26 100644 --- a/org.eclipse.xtext/src/org/eclipse/xtext/service/OperationCanceledManager.java +++ b/org.eclipse.xtext/src/org/eclipse/xtext/service/OperationCanceledManager.java @@ -7,6 +7,8 @@ */ package org.eclipse.xtext.service; +import java.util.concurrent.CancellationException; + import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.xtext.util.CancelIndicator; @@ -19,6 +21,9 @@ import org.eclipse.xtext.util.CancelIndicator; */ public class OperationCanceledManager { protected RuntimeException getPlatformOperationCanceledException(Throwable t) { + if (t instanceof CancellationException) { + return (RuntimeException) t; + } if (t instanceof OperationCanceledException) { return (RuntimeException) t; }