You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2021/04/22 07:00:55 UTC

[camel] 01/04: CAMEL-16494: After VetoCamelContextStartException CamelContext instance broken forever

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit ac64622f8d934648379543e6c773cebcafd76b6a
Author: Акинцев Валерий Андреевич <ak...@gazprom-neft.ru>
AuthorDate: Wed Apr 21 22:28:03 2021 +0300

    CAMEL-16494: After VetoCamelContextStartException CamelContext instance broken forever
---
 .../apache/camel/support/service/BaseService.java  |   4 +
 .../camel/impl/engine/AbstractCamelContext.java    |  50 +++++---
 .../engine/VetoCamelContextStartExceptionTest.java | 139 +++++++++++++++++++++
 3 files changed, 176 insertions(+), 17 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/support/service/BaseService.java b/core/camel-api/src/main/java/org/apache/camel/support/service/BaseService.java
index 8cfc17d..6ee434c 100644
--- a/core/camel-api/src/main/java/org/apache/camel/support/service/BaseService.java
+++ b/core/camel-api/src/main/java/org/apache/camel/support/service/BaseService.java
@@ -109,6 +109,10 @@ public abstract class BaseService {
                 return;
             }
             init();
+            if (status == FAILED) {
+                LOG.trace("Init failed");
+                return;
+            }
             try (AutoCloseable ignored = doLifecycleChange()) {
                 status = STARTING;
                 LOG.trace("Starting service: {}", this);
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index b73bb94..6f35049 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -2476,18 +2476,21 @@ public abstract class AbstractCamelContext extends BaseService
 
     @Override
     public void init() {
-        super.init();
+        try {
+            super.init();
+        } catch (RuntimeCamelException e) {
+            if (e.getCause() != null && e.getCause() instanceof VetoCamelContextStartException) {
+                vetoed = (VetoCamelContextStartException) e.getCause();
+            } else {
+                throw e;
+            }
+        }
 
         // was the initialization vetoed?
         if (vetoed != null) {
-            if (vetoed.isRethrowException()) {
-                throw RuntimeCamelException.wrapRuntimeException(vetoed);
-            } else {
-                LOG.info("CamelContext ({}) vetoed to not initialize due to {}", getName(), vetoed.getMessage());
-                // swallow exception and change state of this camel context to stopped
-                fail(vetoed);
-                return;
-            }
+            LOG.info("CamelContext ({}) vetoed to not initialize due to {}", getName(), vetoed.getMessage());
+            failOnStartup(vetoed);
+            return;
         }
     }
 
@@ -2502,14 +2505,10 @@ public abstract class AbstractCamelContext extends BaseService
 
         // did the start veto?
         if (vetoed != null) {
-            if (vetoed.isRethrowException()) {
-                throw RuntimeCamelException.wrapRuntimeException(vetoed);
-            } else {
-                LOG.info("CamelContext ({}) vetoed to not start due to {}", getName(), vetoed.getMessage());
-                // swallow exception and change state of this camel context to stopped
-                stop();
-                return;
-            }
+            LOG.info("CamelContext ({}) vetoed to not start due to {}", getName(), vetoed.getMessage());
+            failOnStartup(vetoed);
+            stop();
+            return;
         }
 
         for (LifecycleStrategy strategy : lifecycleStrategies) {
@@ -2624,6 +2623,8 @@ public abstract class AbstractCamelContext extends BaseService
     public void doInit() throws Exception {
         StopWatch watch = new StopWatch();
 
+        vetoed = null;
+
         StartupStep step = startupStepRecorder.beginStep(CamelContext.class, null, "Init CamelContext");
 
         // init the route controller
@@ -4847,6 +4848,21 @@ public abstract class AbstractCamelContext extends BaseService
         return "CamelContext(" + getName() + ")";
     }
 
+
+    protected void failOnStartup(Exception e) {
+        if (e instanceof VetoCamelContextStartException) {
+            VetoCamelContextStartException vetoException = (VetoCamelContextStartException) e;
+            if (vetoException.isRethrowException()) {
+                fail(e);
+            } else {
+                // swallow exception and change state of this camel context to stopped
+                status = FAILED;
+            }
+        } else {
+            fail(e);
+        }
+    }
+
     protected abstract ExchangeFactory createExchangeFactory();
 
     protected abstract ExchangeFactoryManager createExchangeFactoryManager();
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/engine/VetoCamelContextStartExceptionTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/VetoCamelContextStartExceptionTest.java
new file mode 100644
index 0000000..9b27033
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/VetoCamelContextStartExceptionTest.java
@@ -0,0 +1,139 @@
+package org.apache.camel.impl.engine;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ServiceStatus;
+import org.apache.camel.VetoCamelContextStartException;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.support.LifecycleStrategySupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class VetoCamelContextStartExceptionTest {
+
+    @Test
+    public void testVetoOnStarting() {
+        CamelContext context = new DefaultCamelContext();
+        context.addLifecycleStrategy(
+                new LifecycleStrategySupport() {
+                    @Override
+                    public void onContextStarting(CamelContext context) throws VetoCamelContextStartException {
+                        throw new VetoCamelContextStartException("Veto on starting", context, true);
+                    }
+                });
+
+        Throwable throwable = assertThrows(Throwable.class, context::start);
+
+        assertTrue(context.isVetoStarted());
+        assertEquals(ServiceStatus.Stopped, context.getStatus());
+        assertEquals("org.apache.camel.VetoCamelContextStartException: Veto on starting", throwable.getMessage());
+    }
+
+    @Test
+    public void testVetoOnStartingWithoutRethrow() {
+        CamelContext context = new DefaultCamelContext();
+        context.addLifecycleStrategy(
+                new LifecycleStrategySupport() {
+                    @Override
+                    public void onContextStarting(CamelContext context) throws VetoCamelContextStartException {
+                        throw new VetoCamelContextStartException("Veto on starting", context, false);
+                    }
+                });
+        context.start();
+        assertTrue(context.isVetoStarted());
+        assertEquals(ServiceStatus.Stopped, context.getStatus());
+    }
+
+    @Test
+    public void testVetoOnInitializing() {
+        CamelContext context = new DefaultCamelContext();
+        context.addLifecycleStrategy(
+                new LifecycleStrategySupport() {
+                    @Override
+                    public void onContextInitializing(CamelContext context) throws VetoCamelContextStartException {
+                        throw new VetoCamelContextStartException("Veto on initializing", context, true);
+                    }
+                });
+
+        Throwable throwable = assertThrows(Throwable.class, context::start);
+        assertTrue(context.isVetoStarted());
+        assertEquals(ServiceStatus.Stopped, context.getStatus());
+        assertEquals("org.apache.camel.VetoCamelContextStartException: Veto on initializing", throwable.getMessage());
+    }
+
+    @Test
+    public void testVetoOnInitializingWithoutRethrow() {
+        CamelContext context = new DefaultCamelContext();
+        context.addLifecycleStrategy(
+                new LifecycleStrategySupport() {
+                    @Override
+                    public void onContextInitializing(CamelContext context) throws VetoCamelContextStartException {
+                        throw new VetoCamelContextStartException("Veto on initializing", context, false);
+                    }
+                });
+        context.start();
+        assertTrue(context.isVetoStarted());
+        assertEquals(ServiceStatus.Stopped, context.getStatus());
+    }
+
+    @Test
+    public void testVetoOnInitialized() {
+        CamelContext context = new DefaultCamelContext();
+        context.addLifecycleStrategy(
+                new LifecycleStrategySupport() {
+                    @Override
+                    public void onContextInitialized(CamelContext context) throws VetoCamelContextStartException {
+                        throw new VetoCamelContextStartException("Veto on initialized", context, true);
+                    }
+                });
+
+        Throwable throwable = assertThrows(Throwable.class, context::start);
+        assertTrue(context.isVetoStarted());
+        assertEquals(ServiceStatus.Stopped, context.getStatus());
+        assertEquals("org.apache.camel.VetoCamelContextStartException: Veto on initialized", throwable.getMessage());
+    }
+
+    @Test
+    public void testVetoOnInitializedWithoutRethrow() {
+        CamelContext context = new DefaultCamelContext();
+        context.addLifecycleStrategy(
+                new LifecycleStrategySupport() {
+                    @Override
+                    public void onContextInitialized(CamelContext context) throws VetoCamelContextStartException {
+                        throw new VetoCamelContextStartException("Veto on initialized", context, false);
+                    }
+                });
+        context.start();
+        assertTrue(context.isVetoStarted());
+        assertEquals(ServiceStatus.Stopped, context.getStatus());
+    }
+
+    @Test
+    public void testVetoReset() throws Exception {
+        try (CamelContext context = new DefaultCamelContext()) {
+            boolean[] needThrowVeto = new boolean[] { true };
+            context.addLifecycleStrategy(
+                    new LifecycleStrategySupport() {
+                        @Override
+                        public void onContextInitialized(CamelContext context) throws VetoCamelContextStartException {
+                            if (needThrowVeto[0]) {
+                                needThrowVeto[0] = false;
+                                throw new VetoCamelContextStartException("Veto on initialized", context, false);
+                            }
+                        }
+                    });
+
+            context.start();
+            assertTrue(context.isVetoStarted());
+            assertEquals(ServiceStatus.Stopped, context.getStatus());
+
+            context.start();
+            assertFalse(context.isVetoStarted());
+            assertEquals(ServiceStatus.Started, context.getStatus());
+        }
+
+    }
+}