From b6f0120647f125e17ea8b2181d95d39ad3df2f42 Mon Sep 17 00:00:00 2001 From: MishaDemianenko Date: Tue, 11 Jul 2017 17:27:28 +0200 Subject: [PATCH] Improve exceptions message for lifecycle graceful stop/shutdown attempts Improve exception message to be less confusing and highlight miss leading suppressed exception nature and origin. --- .../neo4j/kernel/lifecycle/LifeSupport.java | 10 ++++++-- .../kernel/lifecycle/LifecycleException.java | 19 ++++++++------ .../kernel/lifecycle/LifeSupportTest.java | 25 ++++++++++++++++--- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/community/common/src/main/java/org/neo4j/kernel/lifecycle/LifeSupport.java b/community/common/src/main/java/org/neo4j/kernel/lifecycle/LifeSupport.java index 04b4d5185091..8613972154c8 100644 --- a/community/common/src/main/java/org/neo4j/kernel/lifecycle/LifeSupport.java +++ b/community/common/src/main/java/org/neo4j/kernel/lifecycle/LifeSupport.java @@ -415,7 +415,10 @@ public void init() } catch ( Throwable se ) { - e.addSuppressed( se ); + LifecycleException lifecycleException = new LifecycleException( "Exception during graceful " + + "attempt to shutdown partially initialized component. Please use non suppressed" + + " exception to see original component failure.", se ); + e.addSuppressed( lifecycleException ); } if ( e instanceof LifecycleException ) { @@ -451,7 +454,10 @@ public void start() } catch ( Throwable se ) { - e.addSuppressed( se ); + LifecycleException lifecycleException = new LifecycleException( "Exception during graceful " + + "attempt to stop partially started component. Please use non suppressed" + + " exception to see original component failure.", se ); + e.addSuppressed( lifecycleException ); } if ( e instanceof LifecycleException ) { diff --git a/community/common/src/main/java/org/neo4j/kernel/lifecycle/LifecycleException.java b/community/common/src/main/java/org/neo4j/kernel/lifecycle/LifecycleException.java index beea6023a57f..7f1ff5d27752 100644 --- a/community/common/src/main/java/org/neo4j/kernel/lifecycle/LifecycleException.java +++ b/community/common/src/main/java/org/neo4j/kernel/lifecycle/LifecycleException.java @@ -27,8 +27,18 @@ public class LifecycleException extends RuntimeException { - private static String humanReadableMessage( - Object instance, LifecycleStatus from, LifecycleStatus to, Throwable cause ) + public LifecycleException( Object instance, LifecycleStatus from, LifecycleStatus to, Throwable cause ) + { + super( humanReadableMessage( instance, from, to, cause ), cause ); + } + + public LifecycleException( String message, Throwable cause ) + { + super( message, cause ); + } + + private static String humanReadableMessage( Object instance, LifecycleStatus from, + LifecycleStatus to, Throwable cause ) { String instanceStr = String.valueOf( instance ); StringBuilder message = new StringBuilder(); @@ -86,9 +96,4 @@ private static Throwable rootCause( Throwable cause ) } return cause; } - - public LifecycleException( Object instance, LifecycleStatus from, LifecycleStatus to, Throwable cause ) - { - super( humanReadableMessage( instance, from, to, cause ), cause ); - } } diff --git a/community/common/src/test/java/org/neo4j/kernel/lifecycle/LifeSupportTest.java b/community/common/src/test/java/org/neo4j/kernel/lifecycle/LifeSupportTest.java index 963cae52a527..69826cb3176c 100644 --- a/community/common/src/test/java/org/neo4j/kernel/lifecycle/LifeSupportTest.java +++ b/community/common/src/test/java/org/neo4j/kernel/lifecycle/LifeSupportTest.java @@ -21,9 +21,12 @@ import org.junit.Test; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.LinkedList; import java.util.List; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.instanceOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -464,6 +467,7 @@ public void tryToStopComponentOnStartFailure() throws Throwable LifeSupport lifeSupport = newLifeSupport(); Lifecycle component = mock( Lifecycle.class ); doThrow( new RuntimeException( "Start exceptions" ) ).when( component ).start(); + doThrow( new RuntimeException( "Stop exceptions" ) ).when( component ).stop(); lifeSupport.add( component ); try @@ -472,7 +476,10 @@ public void tryToStopComponentOnStartFailure() throws Throwable } catch ( Exception e ) { - // expected start failure + String message = getExceptionStackTrace( e ); + assertThat( message, containsString( + "Exception during graceful attempt to stop partially started component. " + + "Please use non suppressed exception to see original component failure." ) ); } assertEquals( LifecycleStatus.STOPPED, lifeSupport.getStatus() ); @@ -480,11 +487,12 @@ public void tryToStopComponentOnStartFailure() throws Throwable } @Test - public void tryToShutdownComponentOnStartFailure() throws Throwable + public void tryToShutdownComponentOnInitFailure() throws Throwable { LifeSupport lifeSupport = newLifeSupport(); Lifecycle component = mock( Lifecycle.class ); doThrow( new RuntimeException( "Init exceptions" ) ).when( component ).init(); + doThrow( new RuntimeException( "Shutdown exceptions" ) ).when( component ).shutdown(); lifeSupport.add( component ); try @@ -493,7 +501,10 @@ public void tryToShutdownComponentOnStartFailure() throws Throwable } catch ( Exception e ) { - // expected start failure + String message = getExceptionStackTrace( e ); + assertThat( message, containsString( + "Exception during graceful attempt to shutdown partially initialized component. " + + "Please use non suppressed exception to see original component failure." ) ); } assertEquals( LifecycleStatus.SHUTDOWN, lifeSupport.getStatus() ); @@ -502,6 +513,7 @@ public void tryToShutdownComponentOnStartFailure() throws Throwable public class LifecycleMock implements Lifecycle { + Throwable initThrowable; Throwable startThrowable; Throwable stopThrowable; @@ -575,4 +587,11 @@ private LifeSupport newLifeSupport() { return new LifeSupport(); } + + private String getExceptionStackTrace( Exception e ) + { + StringWriter stringWriter = new StringWriter(); + e.printStackTrace( new PrintWriter( stringWriter ) ); + return stringWriter.toString(); + } }