You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by gn...@apache.org on 2020/03/13 14:40:05 UTC

[camel] 04/09: Introduce an immutable CamelContext with limited features

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

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

commit c9a2acad290e134e291f0badf8f3ae5fb91c7e65
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Fri Mar 13 15:06:26 2020 +0100

    Introduce an immutable CamelContext with limited features
---
 .../main/java/org/apache/camel/CamelContext.java   |   19 +-
 .../org/apache/camel/ExtendedCamelContext.java     |    7 +
 .../{ServiceSupport.java => BaseService.java}      |   85 +-
 .../camel/support/service/ServiceSupport.java      |  379 +---
 .../impl/converter/BaseTypeConverterRegistry.java  |  631 +------
 ...egistry.java => CoreTypeConverterRegistry.java} |  352 +---
 .../camel/impl/converter/DefaultTypeConverter.java |    5 -
 .../camel/impl/engine/AbstractCamelContext.java    |  512 +++---
 .../camel/impl/engine/DefaultRouteController.java  |   31 +-
 .../org/apache/camel/impl/engine/EndpointKey.java  |    3 +-
 .../org/apache/camel/impl/engine/RouteService.java |   11 +-
 .../camel/impl/engine/SimpleCamelContext.java      |   45 +-
 .../org/apache/camel/impl/DefaultCamelContext.java |   31 +-
 .../java/org/apache/camel/impl/DefaultModel.java   |   57 +-
 .../camel/impl/lw/ImmutableCamelContext.java       | 1657 ++++++++++++++++++
 .../impl/lw/RuntimeImmutableCamelContext.java      | 1820 ++++++++++++++++++++
 .../main/java/org/apache/camel/model/Model.java    |    5 -
 .../org/apache/camel/model/ModelCamelContext.java  |    9 +
 .../java/org/apache/camel/ContextTestSupport.java  |   34 +-
 .../org/apache/camel/main/BaseMainSupport.java     |    4 +-
 .../org/apache/camel/support/EndpointHelper.java   |   23 +-
 21 files changed, 4026 insertions(+), 1694 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index cc63828..96471ca 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel;
 
+import java.io.IOException;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
@@ -79,7 +80,20 @@ import org.apache.camel.support.jsse.SSLContextParameters;
  * <p/>
  * For more advanced APIs with {@link CamelContext} see {@link ExtendedCamelContext}, which you can obtain via the adapt method.
  */
-public interface CamelContext extends StatefulService, RuntimeConfiguration {
+public interface CamelContext extends RuntimeConfiguration, AutoCloseable {
+
+    boolean isStarted();
+    boolean isStarting();
+    boolean isStopped();
+    boolean isStopping();
+    boolean isSuspended();
+    boolean isSuspending();
+    boolean isRunAllowed();
+    void init();
+    void suspend();
+    void resume();
+    void shutdown();
+    void close() throws IOException;
 
     /**
      * Adapts this {@link org.apache.camel.CamelContext} to the specialized type.
@@ -121,7 +135,6 @@ public interface CamelContext extends StatefulService, RuntimeConfiguration {
      *
      * @throws RuntimeCamelException is thrown if starting failed
      */
-    @Override
     void start();
 
     /**
@@ -131,7 +144,6 @@ public interface CamelContext extends StatefulService, RuntimeConfiguration {
      *
      * @throws RuntimeCamelException is thrown if stopping failed
      */
-    @Override
     void stop();
 
     /**
@@ -197,7 +209,6 @@ public interface CamelContext extends StatefulService, RuntimeConfiguration {
      *
      * @return the status
      */
-    @Override
     ServiceStatus getStatus();
 
     /**
diff --git a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
index d1c96b7..55f92bb 100644
--- a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java
@@ -52,6 +52,7 @@ import org.apache.camel.spi.PackageScanResourceResolver;
 import org.apache.camel.spi.ProcessorFactory;
 import org.apache.camel.spi.ReactiveExecutor;
 import org.apache.camel.spi.Registry;
+import org.apache.camel.spi.RouteController;
 import org.apache.camel.spi.RouteStartupOrder;
 import org.apache.camel.spi.UnitOfWorkFactory;
 import org.apache.camel.spi.XMLRoutesDefinitionLoader;
@@ -566,4 +567,10 @@ public interface ExtendedCamelContext extends CamelContext {
      * If references to the model are removed when Camel is started or not.
      */
     boolean isClearModelReferences();
+
+    RouteController getInternalRouteController();
+
+    void addRoute(Route route);
+
+    void removeRoute(Route route);
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/support/service/ServiceSupport.java b/core/camel-api/src/main/java/org/apache/camel/support/service/BaseService.java
similarity index 90%
copy from core/camel-api/src/main/java/org/apache/camel/support/service/ServiceSupport.java
copy to core/camel-api/src/main/java/org/apache/camel/support/service/BaseService.java
index 8c9fc4e..d408b10 100644
--- a/core/camel-api/src/main/java/org/apache/camel/support/service/ServiceSupport.java
+++ b/core/camel-api/src/main/java/org/apache/camel/support/service/BaseService.java
@@ -18,7 +18,6 @@ package org.apache.camel.support.service;
 
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.ServiceStatus;
-import org.apache.camel.StatefulService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,7 +33,7 @@ import org.slf4j.LoggerFactory;
  * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
  * invoke the operation in a safe manner.
  */
-public abstract class ServiceSupport implements StatefulService {
+public abstract class BaseService {
 
     protected static final byte NEW = 0;
     protected static final byte BUILDED = 1;
@@ -49,21 +48,20 @@ public abstract class ServiceSupport implements StatefulService {
     protected static final byte SHUTDOWN = 10;
     protected static final byte FAILED = 11;
 
-    private static final Logger LOG = LoggerFactory.getLogger(ServiceSupport.class);
+    private static final Logger LOG = LoggerFactory.getLogger(BaseService.class);
 
     protected final Object lock = new Object();
     protected volatile byte status = NEW;
 
-    @Override
     public void build() {
         if (status == NEW) {
             synchronized (lock) {
                 if (status == NEW) {
                     LOG.trace("Building service: {}", this);
-                    try {
+                    try (AutoCloseable ignored = doLifecycleChange()) {
                         doBuild();
                     } catch (Exception e) {
-                        throw RuntimeCamelException.wrapRuntimeException(e);
+                        doFail(e);
                     }
                     status = BUILDED;
                     LOG.trace("Built service: {}", this);
@@ -72,17 +70,17 @@ public abstract class ServiceSupport implements StatefulService {
         }
     }
 
-    @Override
     public void init() {
         // allow to initialize again if stopped or failed
         if (status <= BUILDED || status >= STOPPED) {
             synchronized (lock) {
                 if (status <= BUILDED || status >= STOPPED) {
                     LOG.trace("Initializing service: {}", this);
-                    try {
+                    try (AutoCloseable ignored = doLifecycleChange()) {
                         doInit();
                     } catch (Exception e) {
-                        throw RuntimeCamelException.wrapRuntimeException(e);
+                        LOG.trace("Error while initializing service: " + this, e);
+                        fail(e);
                     }
                     status = INITIALIZED;
                     LOG.trace("Initialized service: {}", this);
@@ -97,7 +95,6 @@ public abstract class ServiceSupport implements StatefulService {
      * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
      * invoke the operation in a safe manner.
      */
-    @Override
     public void start() {
         synchronized (lock) {
             if (status == STARTED) {
@@ -108,14 +105,8 @@ public abstract class ServiceSupport implements StatefulService {
                 LOG.trace("Service: {} already starting", this);
                 return;
             }
-            try {
-                init();
-            } catch (Exception e) {
-                status = FAILED;
-                LOG.trace("Error while initializing service: " + this, e);
-                throw e;
-            }
-            try {
+            init();
+            try (AutoCloseable ignored = doLifecycleChange()) {
                 status = STARTING;
                 LOG.trace("Starting service: {}", this);
                 doStart();
@@ -129,9 +120,8 @@ public abstract class ServiceSupport implements StatefulService {
                     // ignore
                     LOG.trace("Error while stopping service after it failed to start: " + this + ". This exception is ignored", e);
                 }
-                status = FAILED;
                 LOG.trace("Error while starting service: " + this, e);
-                throw RuntimeCamelException.wrapRuntimeException(e);
+                fail(e);
             }
         }
     }
@@ -142,7 +132,6 @@ public abstract class ServiceSupport implements StatefulService {
      * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
      * invoke the operation in a safe manner.
      */
-    @Override
     public void stop() {
         synchronized (lock) {
             if (status == FAILED) {
@@ -159,14 +148,13 @@ public abstract class ServiceSupport implements StatefulService {
             }
             status = STOPPING;
             LOG.trace("Stopping service: {}", this);
-            try {
+            try (AutoCloseable ignored = doLifecycleChange()) {
                 doStop();
                 status = STOPPED;
                 LOG.trace("Stopped: {} service", this);
             } catch (Exception e) {
-                status = FAILED;
                 LOG.trace("Error while stopping service: " + this, e);
-                throw RuntimeCamelException.wrapRuntimeException(e);
+                fail(e);
             }
         }
     }
@@ -177,7 +165,6 @@ public abstract class ServiceSupport implements StatefulService {
      * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
      * invoke the operation in a safe manner.
      */
-    @Override
     public void suspend() {
         synchronized (lock) {
             if (status == SUSPENDED) {
@@ -190,14 +177,13 @@ public abstract class ServiceSupport implements StatefulService {
             }
             status = SUSPENDING;
             LOG.trace("Suspending service: {}", this);
-            try {
+            try (AutoCloseable ignored = doLifecycleChange()) {
                 doSuspend();
                 status = SUSPENDED;
                 LOG.trace("Suspended service: {}", this);
             } catch (Exception e) {
-                status = FAILED;
                 LOG.trace("Error while suspending service: " + this, e);
-                throw RuntimeCamelException.wrapRuntimeException(e);
+                fail(e);
             }
         }
     }
@@ -208,7 +194,6 @@ public abstract class ServiceSupport implements StatefulService {
      * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
      * invoke the operation in a safe manner.
      */
-    @Override
     public void resume() {
         synchronized (lock) {
             if (status != SUSPENDED) {
@@ -217,14 +202,13 @@ public abstract class ServiceSupport implements StatefulService {
             }
             status = STARTING;
             LOG.trace("Resuming service: {}", this);
-            try {
+            try (AutoCloseable ignored = doLifecycleChange()) {
                 doResume();
                 status = STARTED;
                 LOG.trace("Resumed service: {}", this);
             } catch (Exception e) {
-                status = FAILED;
                 LOG.trace("Error while resuming service: " + this, e);
-                throw RuntimeCamelException.wrapRuntimeException(e);
+                fail(e);
             }
         }
     }
@@ -235,7 +219,6 @@ public abstract class ServiceSupport implements StatefulService {
      * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
      * invoke the operation in a safe manner.
      */
-    @Override
     public void shutdown() {
         synchronized (lock) {
             if (status == SHUTDOWN) {
@@ -249,19 +232,17 @@ public abstract class ServiceSupport implements StatefulService {
             stop();
             status = SHUTDOWN;
             LOG.trace("Shutting down service: {}", this);
-            try {
+            try (AutoCloseable ignored = doLifecycleChange()) {
                 doShutdown();
                 LOG.trace("Shutdown service: {}", this);
                 status = SHUTDOWN;
             } catch (Exception e) {
-                status = FAILED;
                 LOG.trace("Error shutting down service: " + this, e);
-                throw RuntimeCamelException.wrapRuntimeException(e);
+                fail(e);
             }
         }
     }
 
-    @Override
     public ServiceStatus getStatus() {
         switch (status) {
             case STARTING:
@@ -291,37 +272,30 @@ public abstract class ServiceSupport implements StatefulService {
         return status == INITIALIZED;
     }
 
-    @Override
     public boolean isStarted() {
         return status == STARTED;
     }
 
-    @Override
     public boolean isStarting() {
         return status == STARTING;
     }
 
-    @Override
     public boolean isStopping() {
         return status == STOPPING;
     }
 
-    @Override
     public boolean isStopped() {
         return status < STARTING || status >= STOPPED;
     }
 
-    @Override
     public boolean isSuspending() {
         return status == SUSPENDING;
     }
 
-    @Override
     public boolean isSuspended() {
         return status == SUSPENDED;
     }
 
-    @Override
     public boolean isRunAllowed() {
         return status >= STARTING && status <= SUSPENDED;
     }
@@ -351,6 +325,14 @@ public abstract class ServiceSupport implements StatefulService {
         return status == STARTING || status == STARTED;
     }
 
+    protected void fail(Exception e) {
+        try {
+            doFail(e);
+        } finally {
+            status = FAILED;
+        }
+    }
+
     /**
      * Optional build phase of the service.
      * This method will only be called by frameworks which supports pre-building projects such as camel-quarkus.
@@ -409,4 +391,19 @@ public abstract class ServiceSupport implements StatefulService {
         // noop
     }
 
+    /**
+     * Implementations override this method to perform any action upon failure.
+     */
+    protected void doFail(Exception e) {
+        throw RuntimeCamelException.wrapRuntimeException(e);
+    }
+
+    /**
+     * Implementations may return an object that will be closed
+     * when the lifecycle action is completed.
+     */
+    protected AutoCloseable doLifecycleChange() {
+        return null;
+    }
+
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/support/service/ServiceSupport.java b/core/camel-api/src/main/java/org/apache/camel/support/service/ServiceSupport.java
index 8c9fc4e..06b5b4e 100644
--- a/core/camel-api/src/main/java/org/apache/camel/support/service/ServiceSupport.java
+++ b/core/camel-api/src/main/java/org/apache/camel/support/service/ServiceSupport.java
@@ -16,11 +16,7 @@
  */
 package org.apache.camel.support.service;
 
-import org.apache.camel.RuntimeCamelException;
-import org.apache.camel.ServiceStatus;
 import org.apache.camel.StatefulService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * A useful base class which ensures that a service is only initialized once and
@@ -34,379 +30,6 @@ import org.slf4j.LoggerFactory;
  * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
  * invoke the operation in a safe manner.
  */
-public abstract class ServiceSupport implements StatefulService {
-
-    protected static final byte NEW = 0;
-    protected static final byte BUILDED = 1;
-    protected static final byte INITIALIZED = 2;
-    protected static final byte STARTING = 3;
-    protected static final byte STARTED = 4;
-    protected static final byte SUSPENDING = 5;
-    protected static final byte SUSPENDED = 6;
-    protected static final byte STOPPING = 7;
-    protected static final byte STOPPED = 8;
-    protected static final byte SHUTTINGDOWN = 9;
-    protected static final byte SHUTDOWN = 10;
-    protected static final byte FAILED = 11;
-
-    private static final Logger LOG = LoggerFactory.getLogger(ServiceSupport.class);
-
-    protected final Object lock = new Object();
-    protected volatile byte status = NEW;
-
-    @Override
-    public void build() {
-        if (status == NEW) {
-            synchronized (lock) {
-                if (status == NEW) {
-                    LOG.trace("Building service: {}", this);
-                    try {
-                        doBuild();
-                    } catch (Exception e) {
-                        throw RuntimeCamelException.wrapRuntimeException(e);
-                    }
-                    status = BUILDED;
-                    LOG.trace("Built service: {}", this);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void init() {
-        // allow to initialize again if stopped or failed
-        if (status <= BUILDED || status >= STOPPED) {
-            synchronized (lock) {
-                if (status <= BUILDED || status >= STOPPED) {
-                    LOG.trace("Initializing service: {}", this);
-                    try {
-                        doInit();
-                    } catch (Exception e) {
-                        throw RuntimeCamelException.wrapRuntimeException(e);
-                    }
-                    status = INITIALIZED;
-                    LOG.trace("Initialized service: {}", this);
-                }
-            }
-        }
-    }
-
-    /**
-     * <b>Important: </b> You should override the lifecycle methods that start with <tt>do</tt>, eg {@link #doStart()},
-     * {@link #doStop()}, etc. where you implement your logic. The methods {@link #start()}, {@link #stop()} should
-     * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
-     * invoke the operation in a safe manner.
-     */
-    @Override
-    public void start() {
-        synchronized (lock) {
-            if (status == STARTED) {
-                LOG.trace("Service: {} already started", this);
-                return;
-            }
-            if (status == STARTING) {
-                LOG.trace("Service: {} already starting", this);
-                return;
-            }
-            try {
-                init();
-            } catch (Exception e) {
-                status = FAILED;
-                LOG.trace("Error while initializing service: " + this, e);
-                throw e;
-            }
-            try {
-                status = STARTING;
-                LOG.trace("Starting service: {}", this);
-                doStart();
-                status = STARTED;
-                LOG.trace("Started service: {}", this);
-            } catch (Exception e) {
-                // need to stop as some resources may have been started during startup
-                try {
-                    stop();
-                } catch (Exception e2) {
-                    // ignore
-                    LOG.trace("Error while stopping service after it failed to start: " + this + ". This exception is ignored", e);
-                }
-                status = FAILED;
-                LOG.trace("Error while starting service: " + this, e);
-                throw RuntimeCamelException.wrapRuntimeException(e);
-            }
-        }
-    }
-
-    /**
-     * <b>Important: </b> You should override the lifecycle methods that start with <tt>do</tt>, eg {@link #doStart()},
-     * {@link #doStop()}, etc. where you implement your logic. The methods {@link #start()}, {@link #stop()} should
-     * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
-     * invoke the operation in a safe manner.
-     */
-    @Override
-    public void stop() {
-        synchronized (lock) {
-            if (status == FAILED) {
-                LOG.trace("Service: {} failed and regarded as already stopped", this);
-                return;
-            }
-            if (status == STOPPED || status == SHUTTINGDOWN || status == SHUTDOWN) {
-                LOG.trace("Service: {} already stopped", this);
-                return;
-            }
-            if (status == STOPPING) {
-                LOG.trace("Service: {} already stopping", this);
-                return;
-            }
-            status = STOPPING;
-            LOG.trace("Stopping service: {}", this);
-            try {
-                doStop();
-                status = STOPPED;
-                LOG.trace("Stopped: {} service", this);
-            } catch (Exception e) {
-                status = FAILED;
-                LOG.trace("Error while stopping service: " + this, e);
-                throw RuntimeCamelException.wrapRuntimeException(e);
-            }
-        }
-    }
-
-    /**
-     * <b>Important: </b> You should override the lifecycle methods that start with <tt>do</tt>, eg {@link #doStart()},
-     * {@link #doStop()}, etc. where you implement your logic. The methods {@link #start()}, {@link #stop()} should
-     * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
-     * invoke the operation in a safe manner.
-     */
-    @Override
-    public void suspend() {
-        synchronized (lock) {
-            if (status == SUSPENDED) {
-                LOG.trace("Service: {} already suspended", this);
-                return;
-            }
-            if (status == SUSPENDING) {
-                LOG.trace("Service: {} already suspending", this);
-                return;
-            }
-            status = SUSPENDING;
-            LOG.trace("Suspending service: {}", this);
-            try {
-                doSuspend();
-                status = SUSPENDED;
-                LOG.trace("Suspended service: {}", this);
-            } catch (Exception e) {
-                status = FAILED;
-                LOG.trace("Error while suspending service: " + this, e);
-                throw RuntimeCamelException.wrapRuntimeException(e);
-            }
-        }
-    }
-
-    /**
-     * <b>Important: </b> You should override the lifecycle methods that start with <tt>do</tt>, eg {@link #doStart()},
-     * {@link #doStop()}, etc. where you implement your logic. The methods {@link #start()}, {@link #stop()} should
-     * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
-     * invoke the operation in a safe manner.
-     */
-    @Override
-    public void resume() {
-        synchronized (lock) {
-            if (status != SUSPENDED) {
-                LOG.trace("Service is not suspended: {}", this);
-                return;
-            }
-            status = STARTING;
-            LOG.trace("Resuming service: {}", this);
-            try {
-                doResume();
-                status = STARTED;
-                LOG.trace("Resumed service: {}", this);
-            } catch (Exception e) {
-                status = FAILED;
-                LOG.trace("Error while resuming service: " + this, e);
-                throw RuntimeCamelException.wrapRuntimeException(e);
-            }
-        }
-    }
-
-    /**
-     * <b>Important: </b> You should override the lifecycle methods that start with <tt>do</tt>, eg {@link #doStart()},
-     * {@link #doStop()}, etc. where you implement your logic. The methods {@link #start()}, {@link #stop()} should
-     * <b>NOT</b> be overridden as they are used internally to keep track of the state of this service and properly
-     * invoke the operation in a safe manner.
-     */
-    @Override
-    public void shutdown() {
-        synchronized (lock) {
-            if (status == SHUTDOWN) {
-                LOG.trace("Service: {} already shutdown", this);
-                return;
-            }
-            if (status == SHUTTINGDOWN) {
-                LOG.trace("Service: {} already shutting down", this);
-                return;
-            }
-            stop();
-            status = SHUTDOWN;
-            LOG.trace("Shutting down service: {}", this);
-            try {
-                doShutdown();
-                LOG.trace("Shutdown service: {}", this);
-                status = SHUTDOWN;
-            } catch (Exception e) {
-                status = FAILED;
-                LOG.trace("Error shutting down service: " + this, e);
-                throw RuntimeCamelException.wrapRuntimeException(e);
-            }
-        }
-    }
-
-    @Override
-    public ServiceStatus getStatus() {
-        switch (status) {
-            case STARTING:
-                return ServiceStatus.Starting;
-            case STARTED:
-                return ServiceStatus.Started;
-            case SUSPENDING:
-                return ServiceStatus.Suspending;
-            case SUSPENDED:
-                return ServiceStatus.Suspended;
-            case STOPPING:
-                return ServiceStatus.Stopping;
-            default:
-                return ServiceStatus.Stopped;
-        }
-    }
-
-    public boolean isNew() {
-        return status == NEW;
-    }
-
-    public boolean isBuild() {
-        return status == BUILDED;
-    }
-
-    public boolean isInit() {
-        return status == INITIALIZED;
-    }
-
-    @Override
-    public boolean isStarted() {
-        return status == STARTED;
-    }
-
-    @Override
-    public boolean isStarting() {
-        return status == STARTING;
-    }
-
-    @Override
-    public boolean isStopping() {
-        return status == STOPPING;
-    }
-
-    @Override
-    public boolean isStopped() {
-        return status < STARTING || status >= STOPPED;
-    }
-
-    @Override
-    public boolean isSuspending() {
-        return status == SUSPENDING;
-    }
-
-    @Override
-    public boolean isSuspended() {
-        return status == SUSPENDED;
-    }
-
-    @Override
-    public boolean isRunAllowed() {
-        return status >= STARTING && status <= SUSPENDED;
-    }
-
-    public boolean isShutdown() {
-        return status == SHUTDOWN;
-    }
-
-    /**
-     * Is the service in progress of being stopped or already stopped
-     */
-    public boolean isStoppingOrStopped() {
-        return status < STARTING || status > SUSPENDED;
-    }
-
-    /**
-     * Is the service in progress of being suspended or already suspended
-     */
-    public boolean isSuspendingOrSuspended() {
-        return status == SUSPENDING || status == SUSPENDED;
-    }
-
-    /**
-     * Is the service in progress of being suspended or already suspended
-     */
-    public boolean isStartingOrStarted() {
-        return status == STARTING || status == STARTED;
-    }
-
-    /**
-     * Optional build phase of the service.
-     * This method will only be called by frameworks which supports pre-building projects such as camel-quarkus.
-     */
-    protected void doBuild() throws Exception {
-    }
-
-    /**
-     * Initialize the service.
-     * This method will only be called once before starting.
-     */
-    protected void doInit() throws Exception {
-    }
-
-    /**
-     * Implementations override this method to support customized start/stop.
-     * <p/>
-     * <b>Important: </b> See {@link #doStop()} for more details.
-     *
-     * @see #doStop()
-     */
-    protected abstract void doStart() throws Exception;
-
-    /**
-     * Implementations override this method to support customized start/stop.
-     * <p/>
-     * <b>Important:</b> Camel will invoke this {@link #doStop()} method when
-     * the service is being stopped. This method will <b>also</b> be invoked
-     * if the service is still in <i>uninitialized</i> state (eg has not
-     * been started). The method is <b>always</b> called to allow the service
-     * to do custom logic when the service is being stopped, such as when
-     * {@link org.apache.camel.CamelContext} is shutting down.
-     *
-     * @see #doStart()
-     */
-    protected abstract void doStop() throws Exception;
-
-    /**
-     * Implementations override this method to support customized suspend/resume.
-     */
-    protected void doSuspend() throws Exception {
-        // noop
-    }
-
-    /**
-     * Implementations override this method to support customized suspend/resume.
-     */
-    protected void doResume() throws Exception {
-        // noop
-    }
-
-    /**
-     * Implementations override this method to perform customized shutdown.
-     */
-    protected void doShutdown() throws Exception {
-        // noop
-    }
+public abstract class ServiceSupport extends BaseService implements StatefulService {
 
 }
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java b/core/camel-base/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
index 62be24d..ee08b33 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
@@ -28,37 +28,20 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.LongAdder;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
-import org.apache.camel.CamelExecutionException;
-import org.apache.camel.Exchange;
 import org.apache.camel.ExtendedCamelContext;
-import org.apache.camel.LoggingLevel;
 import org.apache.camel.NoFactoryAvailableException;
-import org.apache.camel.NoTypeConversionAvailableException;
 import org.apache.camel.RuntimeCamelException;
-import org.apache.camel.TypeConversionException;
 import org.apache.camel.TypeConverter;
-import org.apache.camel.TypeConverterExists;
-import org.apache.camel.TypeConverterExistsException;
 import org.apache.camel.TypeConverterLoaderException;
 import org.apache.camel.TypeConverters;
-import org.apache.camel.converter.ObjectConverter;
-import org.apache.camel.spi.CamelLogger;
+import org.apache.camel.impl.converter.CoreTypeConverterRegistry.FallbackTypeConverter;
 import org.apache.camel.spi.FactoryFinder;
 import org.apache.camel.spi.Injector;
 import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.TypeConverterLoader;
-import org.apache.camel.spi.TypeConverterRegistry;
-import org.apache.camel.support.MessageHelper;
-import org.apache.camel.support.TypeConverterSupport;
-import org.apache.camel.support.service.ServiceSupport;
-import org.apache.camel.util.DoubleMap;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
@@ -68,35 +51,18 @@ import org.slf4j.LoggerFactory;
  * Base implementation of a type converter registry used for
  * <a href="http://camel.apache.org/type-converter.html">type converters</a> in Camel.
  */
-public abstract class BaseTypeConverterRegistry extends ServiceSupport implements TypeConverter, TypeConverterRegistry {
+public abstract class BaseTypeConverterRegistry extends CoreTypeConverterRegistry {
 
     public static final String META_INF_SERVICES_TYPE_CONVERTER_LOADER = "META-INF/services/org/apache/camel/TypeConverterLoader";
     public static final String META_INF_SERVICES_FALLBACK_TYPE_CONVERTER = "META-INF/services/org/apache/camel/FallbackTypeConverter";
 
-    protected static final TypeConverter MISS_CONVERTER = new TypeConverterSupport() {
-        @Override
-        public <T> T convertTo(Class<T> type, Exchange exchange, Object value) throws TypeConversionException {
-            return (T) MISS_VALUE;
-        }
-    };
-
     private static final Logger LOG = LoggerFactory.getLogger(BaseTypeConverterRegistry.class);
 
-    protected final DoubleMap<Class<?>, Class<?>, TypeConverter> typeMappings = new DoubleMap<>(200);
     protected final List<TypeConverterLoader> typeConverterLoaders = new ArrayList<>();
-    protected final List<FallbackTypeConverter> fallbackConverters = new CopyOnWriteArrayList<>();
     protected CamelContext camelContext;
     protected PackageScanClassResolver resolver;
     protected Injector injector;
     protected final FactoryFinder factoryFinder;
-    protected TypeConverterExists typeConverterExists = TypeConverterExists.Override;
-    protected LoggingLevel typeConverterExistsLoggingLevel = LoggingLevel.WARN;
-    protected final Statistics statistics = new UtilizationStatistics();
-    protected final LongAdder noopCounter = new LongAdder();
-    protected final LongAdder attemptCounter = new LongAdder();
-    protected final LongAdder missCounter = new LongAdder();
-    protected final LongAdder hitCounter = new LongAdder();
-    protected final LongAdder failedCounter = new LongAdder();
 
     public BaseTypeConverterRegistry(CamelContext camelContext, PackageScanClassResolver resolver, Injector injector, FactoryFinder factoryFinder) {
         this.camelContext = camelContext;
@@ -120,347 +86,6 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
     }
 
     @Override
-    public <T> T convertTo(Class<T> type, Object value) {
-        return convertTo(type, null, value);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
-        // optimize for a few common conversions
-        if (value != null) {
-            if (type.isInstance(value)) {
-                // same instance
-                return (T) value;
-            }
-            if (type == boolean.class) {
-                // primitive boolean which must return a value so throw exception if not possible
-                Object answer = ObjectConverter.toBoolean(value);
-                if (answer == null) {
-                    throw new TypeConversionException(value, type, new IllegalArgumentException("Cannot convert type: " + value.getClass().getName() + " to boolean"));
-                }
-                return (T) answer;
-            } else if (type == Boolean.class && (value instanceof String)) {
-                // String -> Boolean
-                String str = (String) value;
-                if ("true".equalsIgnoreCase(str)) {
-                    return (T) Boolean.TRUE;
-                } else if ("false".equalsIgnoreCase(str)) {
-                    return (T) Boolean.FALSE;
-                }
-            } else if (type.isPrimitive()) {
-                // okay its a wrapper -> primitive then return as-is for some common types
-                Class cls = value.getClass();
-                if (cls == Integer.class || cls == Long.class) {
-                    return (T) value;
-                }
-            } else if (type == String.class) {
-                // okay its a primitive -> string then return as-is for some common types
-                Class cls = value.getClass();
-                if (cls.isPrimitive()
-                        || cls == Boolean.class || cls == boolean.class
-                        || cls == Integer.class || cls == int.class
-                        || cls == Long.class || cls == long.class) {
-                    return (T) value.toString();
-                }
-            }
-            // NOTE: we cannot optimize any more if value is String as it may be time pattern and other patterns
-        }
-
-        return (T) doConvertTo(type, exchange, value, false, false);
-    }
-
-    @Override
-    public <T> T mandatoryConvertTo(Class<T> type, Object value) throws NoTypeConversionAvailableException {
-        return mandatoryConvertTo(type, null, value);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <T> T mandatoryConvertTo(Class<T> type, Exchange exchange, Object value) throws NoTypeConversionAvailableException {
-        // optimize for a few common conversions
-        if (value != null) {
-            if (type.isInstance(value)) {
-                // same instance
-                return (T) value;
-            }
-            if (type == boolean.class) {
-                // primitive boolean which must return a value so throw exception if not possible
-                Object answer = ObjectConverter.toBoolean(value);
-                if (answer == null) {
-                    throw new TypeConversionException(value, type, new IllegalArgumentException("Cannot convert type: " + value.getClass().getName() + " to boolean"));
-                }
-                return (T) answer;
-            } else if (type == Boolean.class && (value instanceof String)) {
-                // String -> Boolean
-                String str = (String) value;
-                if ("true".equalsIgnoreCase(str)) {
-                    return (T) Boolean.TRUE;
-                } else if ("false".equalsIgnoreCase(str)) {
-                    return (T) Boolean.FALSE;
-                }
-            } else if (type.isPrimitive()) {
-                // okay its a wrapper -> primitive then return as-is for some common types
-                Class cls = value.getClass();
-                if (cls == Integer.class || cls == Long.class) {
-                    return (T) value;
-                }
-            } else if (type == String.class) {
-                // okay its a primitive -> string then return as-is for some common types
-                Class cls = value.getClass();
-                if (cls.isPrimitive()
-                        || cls == Boolean.class || cls == boolean.class
-                        || cls == Integer.class || cls == int.class
-                        || cls == Long.class || cls == long.class) {
-                    return (T) value.toString();
-                }
-            }
-            // NOTE: we cannot optimize any more if value is String as it may be time pattern and other patterns
-        }
-
-        Object answer = doConvertTo(type, exchange, value, true, false);
-        if (answer == null) {
-            // Could not find suitable conversion
-            throw new NoTypeConversionAvailableException(value, type);
-        }
-        return (T) answer;
-    }
-
-    @Override
-    public <T> T tryConvertTo(Class<T> type, Object value) {
-        return tryConvertTo(type, null, value);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <T> T tryConvertTo(Class<T> type, Exchange exchange, Object value) {
-        return (T) doConvertTo(type, exchange, value, false, true);
-    }
-
-    protected Object doConvertTo(final Class<?> type, final Exchange exchange, final Object value,
-                                 final boolean mandatory, final boolean tryConvert) {
-        Object answer;
-        try {
-            answer = doConvertTo(type, exchange, value, tryConvert);
-        } catch (Exception e) {
-            if (statistics.isStatisticsEnabled()) {
-                failedCounter.increment();
-            }
-            if (tryConvert) {
-                return null;
-            }
-
-            // if its a ExecutionException then we have rethrow it as its not due to failed conversion
-            // this is special for FutureTypeConverter
-            boolean execution = ObjectHelper.getException(ExecutionException.class, e) != null
-                    || ObjectHelper.getException(CamelExecutionException.class, e) != null;
-            if (execution) {
-                throw CamelExecutionException.wrapCamelExecutionException(exchange, e);
-            }
-            // error occurred during type conversion
-            throw createTypeConversionException(exchange, type, value, e);
-        }
-        if (answer == MISS_VALUE) {
-            // Could not find suitable conversion
-            if (statistics.isStatisticsEnabled()) {
-                missCounter.increment();
-            }
-            return null;
-        } else {
-            if (statistics.isStatisticsEnabled()) {
-                hitCounter.increment();
-            }
-            return answer;
-        }
-    }
-
-    protected Object doConvertTo(final Class<?> type, final Exchange exchange, final Object value,
-                                 final boolean tryConvert) throws Exception {
-        boolean trace = LOG.isTraceEnabled();
-        boolean statisticsEnabled = statistics.isStatisticsEnabled();
-
-        if (trace) {
-            LOG.trace("Finding type converter to convert {} -> {} with value: {}",
-                    value == null ? "null" : value.getClass().getCanonicalName(),
-                    type.getCanonicalName(), value);
-        }
-
-
-        if (value == null) {
-            // no type conversion was needed
-            if (statisticsEnabled) {
-                noopCounter.increment();
-            }
-            // lets avoid NullPointerException when converting to primitives for null values
-            if (type.isPrimitive()) {
-                if (boolean.class == type) {
-                    return Boolean.FALSE;
-                }
-                if (int.class == type) {
-                    return 0;
-                }
-                if (long.class == type) {
-                    return 0L;
-                }
-                if (byte.class == type) {
-                    return (byte) 0;
-                }
-                if (short.class == type) {
-                    return (short) 0;
-                }
-                if (double.class == type) {
-                    return 0.0;
-                }
-                if (float.class == type) {
-                    return 0.0f;
-                }
-                if (char.class == type) {
-                    return '\0';
-                }
-            }
-            return null;
-        }
-
-        // same instance type
-        if (type.isInstance(value)) {
-            // no type conversion was needed
-            if (statisticsEnabled) {
-                noopCounter.increment();
-            }
-            return value;
-        }
-
-        // okay we need to attempt to convert
-        if (statisticsEnabled) {
-            attemptCounter.increment();
-        }
-
-        // try to find a suitable type converter
-        TypeConverter converter = getOrFindTypeConverter(type, value.getClass());
-        if (converter != null) {
-            if (trace) {
-                LOG.trace("Using converter: {} to convert [{}=>{}]", converter, value.getClass(), type);
-            }
-            Object rc;
-            if (tryConvert) {
-                rc = converter.tryConvertTo(type, exchange, value);
-            } else {
-                rc = converter.convertTo(type, exchange, value);
-            }
-            if (rc != null) {
-                return rc;
-            } else if (converter.allowNull()) {
-                return null;
-            }
-        }
-
-        // not found with that type then if it was a primitive type then try again with the wrapper type
-        if (type.isPrimitive()) {
-            Class<?> primitiveType = ObjectHelper.convertPrimitiveTypeToWrapperType(type);
-            if (primitiveType != type) {
-                Class<?> fromType = value.getClass();
-                TypeConverter tc = getOrFindTypeConverter(primitiveType, fromType);
-                if (tc != null) {
-                    // add the type as a known type converter as we can convert from primitive to object converter
-                    addTypeConverter(type, fromType, tc);
-                    Object rc;
-                    if (tryConvert) {
-                        rc = tc.tryConvertTo(primitiveType, exchange, value);
-                    } else {
-                        rc = tc.convertTo(primitiveType, exchange, value);
-                    }
-                    if (rc == null && tc.allowNull()) {
-                        return null;
-                    } else if (rc != null) {
-                        return rc;
-                    }
-                }
-            }
-        }
-
-        // fallback converters
-        for (FallbackTypeConverter fallback : fallbackConverters) {
-            TypeConverter tc = fallback.getFallbackTypeConverter();
-            Object rc;
-            if (tryConvert) {
-                rc = tc.tryConvertTo(type, exchange, value);
-            } else {
-                rc = tc.convertTo(type, exchange, value);
-            }
-            if (rc == null && tc.allowNull()) {
-                return null;
-            }
-
-            if (rc == MISS_VALUE) {
-                // it cannot be converted so give up
-                return MISS_VALUE;
-            }
-
-            if (rc != null) {
-                // if fallback can promote then let it be promoted to a first class type converter
-                if (fallback.isCanPromote()) {
-                    // add it as a known type converter since we found a fallback that could do it
-                    if (LOG.isDebugEnabled()) {
-                        LOG.debug("Promoting fallback type converter as a known type converter to convert from: {} to: {} for the fallback converter: {}",
-                                type.getCanonicalName(), value.getClass().getCanonicalName(), fallback.getFallbackTypeConverter());
-                    }
-                    addTypeConverter(type, value.getClass(), fallback.getFallbackTypeConverter());
-                }
-
-                if (LOG.isTraceEnabled()) {
-                    LOG.trace("Fallback type converter {} converted type from: {} to: {}",
-                            fallback.getFallbackTypeConverter(), type.getCanonicalName(), value.getClass().getCanonicalName());
-                }
-
-                // return converted value
-                return rc;
-            }
-        }
-
-        if (!tryConvert) {
-            // Could not find suitable conversion, so remember it
-            // do not register misses for try conversions
-            typeMappings.put(type, value.getClass(), MISS_CONVERTER);
-        }
-
-        // Could not find suitable conversion, so return Void to indicate not found
-        return MISS_VALUE;
-    }
-
-    @Override
-    public void addTypeConverter(Class<?> toType, Class<?> fromType, TypeConverter typeConverter) {
-        LOG.trace("Adding type converter: {}", typeConverter);
-        TypeConverter converter = typeMappings.get(toType, fromType);
-        // only override it if its different
-        // as race conditions can lead to many threads trying to promote the same fallback converter
-
-        if (typeConverter != converter) {
-
-            // add the converter unless we should ignore
-            boolean add = true;
-
-            // if converter is not null then a duplicate exists
-            if (converter != null) {
-                if (typeConverterExists == TypeConverterExists.Override) {
-                    CamelLogger logger = new CamelLogger(LOG, typeConverterExistsLoggingLevel);
-                    logger.log("Overriding type converter from: " + converter + " to: " + typeConverter);
-                } else if (typeConverterExists == TypeConverterExists.Ignore) {
-                    CamelLogger logger = new CamelLogger(LOG, typeConverterExistsLoggingLevel);
-                    logger.log("Ignoring duplicate type converter from: " + converter + " to: " + typeConverter);
-                    add = false;
-                } else {
-                    // we should fail
-                    throw new TypeConverterExistsException(toType, fromType);
-                }
-            }
-
-            if (add) {
-                typeMappings.put(toType, fromType, typeConverter);
-            }
-        }
-    }
-
-    @Override
     public void addTypeConverters(TypeConverters typeConverters) {
         LOG.trace("Adding type converters: {}", typeConverters);
         try {
@@ -473,19 +98,8 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
     }
 
     @Override
-    public boolean removeTypeConverter(Class<?> toType, Class<?> fromType) {
-        LOG.trace("Removing type converter from: {} to: {}", fromType, toType);
-        return typeMappings.remove(toType, fromType);
-    }
-
-    @Override
     public void addFallbackTypeConverter(TypeConverter typeConverter, boolean canPromote) {
-        LOG.trace("Adding fallback type converter: {} which can promote: {}", typeConverter, canPromote);
-
-        // add in top of fallback as the toString() fallback will nearly always be able to convert
-        // the last one which is add to the FallbackTypeConverter will be called at the first place
-        fallbackConverters.add(0, new FallbackTypeConverter(typeConverter, canPromote));
-
+        super.addFallbackTypeConverter(typeConverter, canPromote);
         if (typeConverter instanceof CamelContextAware) {
             CamelContextAware camelContextAware = (CamelContextAware) typeConverter;
             if (camelContext != null) {
@@ -494,8 +108,8 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         }
     }
 
-    private void addCoreFallbackTypeConverterToList(TypeConverter typeConverter, boolean canPromote, List<
-            FallbackTypeConverter> converters) {
+    private void addCoreFallbackTypeConverterToList(TypeConverter typeConverter, boolean canPromote,
+                                                    List<FallbackTypeConverter> converters) {
         LOG.trace("Adding core fallback type converter: {} which can promote: {}", typeConverter, canPromote);
 
         // add in top of fallback as the toString() fallback will nearly always be able to convert
@@ -510,10 +124,6 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         }
     }
 
-    public TypeConverter getTypeConverter(Class<?> toType, Class<?> fromType) {
-        return typeMappings.get(toType, fromType);
-    }
-
     @Override
     public Injector getInjector() {
         return injector;
@@ -528,82 +138,6 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         return resolver;
     }
 
-    protected <T> TypeConverter getOrFindTypeConverter(Class<?> toType, Class<?> fromType) {
-        TypeConverter converter = typeMappings.get(toType, fromType);
-        if (converter == null) {
-            // converter not found, try to lookup then
-            converter = lookup(toType, fromType);
-            if (converter != null) {
-                typeMappings.put(toType, fromType, converter);
-            }
-        }
-        return converter;
-    }
-
-    @Override
-    public TypeConverter lookup(Class<?> toType, Class<?> fromType) {
-        return doLookup(toType, fromType, false);
-    }
-
-    protected TypeConverter doLookup(Class<?> toType, Class<?> fromType, boolean isSuper) {
-
-        if (fromType != null) {
-            // lets try if there is a direct match
-            TypeConverter converter = getTypeConverter(toType, fromType);
-            if (converter != null) {
-                return converter;
-            }
-
-            // try the interfaces
-            for (Class<?> type : fromType.getInterfaces()) {
-                converter = getTypeConverter(toType, type);
-                if (converter != null) {
-                    return converter;
-                }
-            }
-
-            // try super then
-            Class<?> fromSuperClass = fromType.getSuperclass();
-            if (fromSuperClass != null && !fromSuperClass.equals(Object.class)) {
-                converter = doLookup(toType, fromSuperClass, true);
-                if (converter != null) {
-                    return converter;
-                }
-            }
-        }
-
-        // only do these tests as fallback and only on the target type (eg not on its super)
-        if (!isSuper) {
-            if (fromType != null && !fromType.equals(Object.class)) {
-
-                // lets try classes derived from this toType
-                TypeConverter converter = typeMappings.getFirst(
-                    toType::isAssignableFrom,
-                    // skip Object based we do them last
-                    from -> !from.equals(Object.class) && from.isAssignableFrom(fromType));
-                if (converter != null) {
-                    return converter;
-                }
-
-                // lets test for Object based converters as last resort
-                converter = getTypeConverter(toType, Object.class);
-                if (converter != null) {
-                    return converter;
-                }
-            }
-        }
-
-        // none found
-        return null;
-    }
-
-    @Override
-    public List<Class<?>[]> listAllTypeConvertersFromTo() {
-        List<Class<?>[]> answer = new ArrayList<>();
-        typeMappings.forEach((k1, k2, v) -> answer.add(new Class<?>[]{k2, k1}));
-        return answer;
-    }
-
     /**
      * Loads the core type converters which is mandatory to use Camel,
      * and also loads the fast type converters (generated via @Converter(loader = true).
@@ -612,7 +146,7 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         Collection<String> names = findTypeConverterLoaderClasses();
         for (String name : names) {
             LOG.debug("Resolving TypeConverterLoader: {}", name);
-            Class clazz = null;
+            Class<?> clazz = null;
             for (ClassLoader loader : getResolver().getClassLoaders()) {
                 try {
                     clazz = loader.loadClass(name);
@@ -724,7 +258,7 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         Collection<String> names = findFallbackTypeConverterClasses();
         for (String name : names) {
             LOG.debug("Resolving FallbackTypeConverter: {}", name);
-            Class clazz = getResolver().getClassLoaders().stream()
+            Class<?> clazz = getResolver().getClassLoaders().stream()
                     .map(cl -> ObjectHelper.loadClass(name, cl))
                     .filter(Objects::nonNull)
                     .findAny().orElseThrow(() -> new ClassNotFoundException(name));
@@ -737,54 +271,6 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         }
     }
 
-    protected TypeConversionException createTypeConversionException(Exchange exchange, Class<?> type, Object
-            value, Throwable cause) {
-        if (cause instanceof TypeConversionException) {
-            if (((TypeConversionException) cause).getToType() == type) {
-                return (TypeConversionException) cause;
-            }
-        }
-        Object body;
-        // extract the body for logging which allows to limit the message body in the exception/stacktrace
-        // and also can be used to turn off logging sensitive message data
-        if (exchange != null) {
-            body = MessageHelper.extractValueForLogging(value, exchange.getIn());
-        } else {
-            body = value;
-        }
-        return new TypeConversionException(body, type, cause);
-    }
-
-    @Override
-    public Statistics getStatistics() {
-        return statistics;
-    }
-
-    @Override
-    public int size() {
-        return typeMappings.size();
-    }
-
-    @Override
-    public LoggingLevel getTypeConverterExistsLoggingLevel() {
-        return typeConverterExistsLoggingLevel;
-    }
-
-    @Override
-    public void setTypeConverterExistsLoggingLevel(LoggingLevel typeConverterExistsLoggingLevel) {
-        this.typeConverterExistsLoggingLevel = typeConverterExistsLoggingLevel;
-    }
-
-    @Override
-    public TypeConverterExists getTypeConverterExists() {
-        return typeConverterExists;
-    }
-
-    @Override
-    public void setTypeConverterExists(TypeConverterExists typeConverterExists) {
-        this.typeConverterExists = typeConverterExists;
-    }
-
     @Override
     protected void doInit() {
         if (injector == null && camelContext != null) {
@@ -812,107 +298,4 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         fallbackConverters.addAll(fallbacks);
     }
 
-    @Override
-    protected void doStart() throws Exception {
-        // noop
-    }
-
-    @Override
-    protected void doStop() throws Exception {
-        // log utilization statistics when stopping, including mappings
-        if (statistics.isStatisticsEnabled()) {
-            String info = statistics.toString();
-            AtomicInteger misses = new AtomicInteger();
-            typeMappings.forEach((k1, k2, v) -> {
-                if (v == MISS_CONVERTER) {
-                    misses.incrementAndGet();
-                }
-            });
-            info += String.format(" mappings[total=%s, misses=%s]", typeMappings.size(), misses);
-            LOG.info(info);
-        }
-
-        typeMappings.clear();
-        statistics.reset();
-    }
-
-    /**
-     * Represents utilization statistics
-     */
-    private final class UtilizationStatistics implements Statistics {
-
-        private boolean statisticsEnabled;
-
-        @Override
-        public long getNoopCounter() {
-            return noopCounter.longValue();
-        }
-
-        @Override
-        public long getAttemptCounter() {
-            return attemptCounter.longValue();
-        }
-
-        @Override
-        public long getHitCounter() {
-            return hitCounter.longValue();
-        }
-
-        @Override
-        public long getMissCounter() {
-            return missCounter.longValue();
-        }
-
-        @Override
-        public long getFailedCounter() {
-            return failedCounter.longValue();
-        }
-
-        @Override
-        public void reset() {
-            noopCounter.reset();
-            attemptCounter.reset();
-            hitCounter.reset();
-            missCounter.reset();
-            failedCounter.reset();
-        }
-
-        @Override
-        public boolean isStatisticsEnabled() {
-            return statisticsEnabled;
-        }
-
-        @Override
-        public void setStatisticsEnabled(boolean statisticsEnabled) {
-            this.statisticsEnabled = statisticsEnabled;
-        }
-
-        @Override
-        public String toString() {
-            return String.format("TypeConverterRegistry utilization[noop=%s, attempts=%s, hits=%s, misses=%s, failures=%s]",
-                    getNoopCounter(), getAttemptCounter(), getHitCounter(), getMissCounter(), getFailedCounter());
-        }
-    }
-
-    /**
-     * Represents a fallback type converter
-     */
-    protected static class FallbackTypeConverter {
-        private final boolean canPromote;
-        private final TypeConverter fallbackTypeConverter;
-
-        FallbackTypeConverter(TypeConverter fallbackTypeConverter, boolean canPromote) {
-            this.canPromote = canPromote;
-            this.fallbackTypeConverter = fallbackTypeConverter;
-        }
-
-        public boolean isCanPromote() {
-            return canPromote;
-        }
-
-        public TypeConverter getFallbackTypeConverter() {
-            return fallbackTypeConverter;
-        }
-    }
-
 }
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java b/core/camel-base/src/main/java/org/apache/camel/impl/converter/CoreTypeConverterRegistry.java
similarity index 67%
copy from core/camel-base/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
copy to core/camel-base/src/main/java/org/apache/camel/impl/converter/CoreTypeConverterRegistry.java
index 62be24d..c5fcef4 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/converter/CoreTypeConverterRegistry.java
@@ -16,62 +16,36 @@
  */
 package org.apache.camel.impl.converter;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Objects;
-import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.LongAdder;
 
 import org.apache.camel.CamelContext;
-import org.apache.camel.CamelContextAware;
 import org.apache.camel.CamelExecutionException;
 import org.apache.camel.Exchange;
-import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.LoggingLevel;
-import org.apache.camel.NoFactoryAvailableException;
 import org.apache.camel.NoTypeConversionAvailableException;
-import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.TypeConversionException;
 import org.apache.camel.TypeConverter;
 import org.apache.camel.TypeConverterExists;
 import org.apache.camel.TypeConverterExistsException;
-import org.apache.camel.TypeConverterLoaderException;
 import org.apache.camel.TypeConverters;
 import org.apache.camel.converter.ObjectConverter;
 import org.apache.camel.spi.CamelLogger;
-import org.apache.camel.spi.FactoryFinder;
 import org.apache.camel.spi.Injector;
-import org.apache.camel.spi.PackageScanClassResolver;
-import org.apache.camel.spi.TypeConverterLoader;
 import org.apache.camel.spi.TypeConverterRegistry;
 import org.apache.camel.support.MessageHelper;
 import org.apache.camel.support.TypeConverterSupport;
 import org.apache.camel.support.service.ServiceSupport;
 import org.apache.camel.util.DoubleMap;
-import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/**
- * Base implementation of a type converter registry used for
- * <a href="http://camel.apache.org/type-converter.html">type converters</a> in Camel.
- */
-public abstract class BaseTypeConverterRegistry extends ServiceSupport implements TypeConverter, TypeConverterRegistry {
-
-    public static final String META_INF_SERVICES_TYPE_CONVERTER_LOADER = "META-INF/services/org/apache/camel/TypeConverterLoader";
-    public static final String META_INF_SERVICES_FALLBACK_TYPE_CONVERTER = "META-INF/services/org/apache/camel/FallbackTypeConverter";
+public class CoreTypeConverterRegistry extends ServiceSupport implements TypeConverter, TypeConverterRegistry {
 
     protected static final TypeConverter MISS_CONVERTER = new TypeConverterSupport() {
         @Override
@@ -80,15 +54,10 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         }
     };
 
-    private static final Logger LOG = LoggerFactory.getLogger(BaseTypeConverterRegistry.class);
+    private static final Logger LOG = LoggerFactory.getLogger(CoreTypeConverterRegistry.class);
 
     protected final DoubleMap<Class<?>, Class<?>, TypeConverter> typeMappings = new DoubleMap<>(200);
-    protected final List<TypeConverterLoader> typeConverterLoaders = new ArrayList<>();
     protected final List<FallbackTypeConverter> fallbackConverters = new CopyOnWriteArrayList<>();
-    protected CamelContext camelContext;
-    protected PackageScanClassResolver resolver;
-    protected Injector injector;
-    protected final FactoryFinder factoryFinder;
     protected TypeConverterExists typeConverterExists = TypeConverterExists.Override;
     protected LoggingLevel typeConverterExistsLoggingLevel = LoggingLevel.WARN;
     protected final Statistics statistics = new UtilizationStatistics();
@@ -98,34 +67,59 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
     protected final LongAdder hitCounter = new LongAdder();
     protected final LongAdder failedCounter = new LongAdder();
 
-    public BaseTypeConverterRegistry(CamelContext camelContext, PackageScanClassResolver resolver, Injector injector, FactoryFinder factoryFinder) {
-        this.camelContext = camelContext;
-        this.injector = injector;
-        this.factoryFinder = factoryFinder;
-        this.resolver = resolver;
+    public CoreTypeConverterRegistry() {
+    }
+
+    public CoreTypeConverterRegistry(TypeConverterRegistry registry) {
+        if (registry instanceof CoreTypeConverterRegistry) {
+            CoreTypeConverterRegistry reg = (CoreTypeConverterRegistry) registry;
+            reg.getTypeMappings().forEach(typeMappings::put);
+            this.fallbackConverters.addAll(reg.getFallbackConverters());
+        } else {
+            throw new UnsupportedOperationException();
+        }
+        this.typeConverterExistsLoggingLevel = registry.getTypeConverterExistsLoggingLevel();
+        this.typeConverterExists = registry.getTypeConverterExists();
     }
 
     @Override
-    public CamelContext getCamelContext() {
-        return camelContext;
+    public boolean allowNull() {
+        return false;
     }
 
     @Override
-    public void setCamelContext(CamelContext camelContext) {
-        this.camelContext = camelContext;
+    public void setInjector(Injector injector) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Injector getInjector() {
+        throw new UnsupportedOperationException();
     }
 
-    public List<TypeConverterLoader> getTypeConverterLoaders() {
-        return typeConverterLoaders;
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        throw new UnsupportedOperationException();
     }
 
     @Override
+    public CamelContext getCamelContext() {
+        throw new UnsupportedOperationException();
+    }
+
+    public DoubleMap<Class<?>, Class<?>, TypeConverter> getTypeMappings() {
+        return typeMappings;
+    }
+
+    public List<FallbackTypeConverter> getFallbackConverters() {
+        return fallbackConverters;
+    }
+
     public <T> T convertTo(Class<T> type, Object value) {
         return convertTo(type, null, value);
     }
 
     @SuppressWarnings("unchecked")
-    @Override
     public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
         // optimize for a few common conversions
         if (value != null) {
@@ -150,13 +144,13 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
                 }
             } else if (type.isPrimitive()) {
                 // okay its a wrapper -> primitive then return as-is for some common types
-                Class cls = value.getClass();
+                Class<?> cls = value.getClass();
                 if (cls == Integer.class || cls == Long.class) {
                     return (T) value;
                 }
             } else if (type == String.class) {
                 // okay its a primitive -> string then return as-is for some common types
-                Class cls = value.getClass();
+                Class<?> cls = value.getClass();
                 if (cls.isPrimitive()
                         || cls == Boolean.class || cls == boolean.class
                         || cls == Integer.class || cls == int.class
@@ -170,13 +164,11 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         return (T) doConvertTo(type, exchange, value, false, false);
     }
 
-    @Override
     public <T> T mandatoryConvertTo(Class<T> type, Object value) throws NoTypeConversionAvailableException {
         return mandatoryConvertTo(type, null, value);
     }
 
     @SuppressWarnings("unchecked")
-    @Override
     public <T> T mandatoryConvertTo(Class<T> type, Exchange exchange, Object value) throws NoTypeConversionAvailableException {
         // optimize for a few common conversions
         if (value != null) {
@@ -201,13 +193,13 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
                 }
             } else if (type.isPrimitive()) {
                 // okay its a wrapper -> primitive then return as-is for some common types
-                Class cls = value.getClass();
+                Class<?> cls = value.getClass();
                 if (cls == Integer.class || cls == Long.class) {
                     return (T) value;
                 }
             } else if (type == String.class) {
                 // okay its a primitive -> string then return as-is for some common types
-                Class cls = value.getClass();
+                Class<?> cls = value.getClass();
                 if (cls.isPrimitive()
                         || cls == Boolean.class || cls == boolean.class
                         || cls == Integer.class || cls == int.class
@@ -226,13 +218,11 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         return (T) answer;
     }
 
-    @Override
     public <T> T tryConvertTo(Class<T> type, Object value) {
         return tryConvertTo(type, null, value);
     }
 
     @SuppressWarnings("unchecked")
-    @Override
     public <T> T tryConvertTo(Class<T> type, Exchange exchange, Object value) {
         return (T) doConvertTo(type, exchange, value, false, true);
     }
@@ -260,7 +250,7 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
             // error occurred during type conversion
             throw createTypeConversionException(exchange, type, value, e);
         }
-        if (answer == MISS_VALUE) {
+        if (answer == TypeConverter.MISS_VALUE) {
             // Could not find suitable conversion
             if (statistics.isStatisticsEnabled()) {
                 missCounter.increment();
@@ -391,9 +381,9 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
                 return null;
             }
 
-            if (rc == MISS_VALUE) {
+            if (rc == TypeConverter.MISS_VALUE) {
                 // it cannot be converted so give up
-                return MISS_VALUE;
+                return TypeConverter.MISS_VALUE;
             }
 
             if (rc != null) {
@@ -424,10 +414,13 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         }
 
         // Could not find suitable conversion, so return Void to indicate not found
-        return MISS_VALUE;
+        return TypeConverter.MISS_VALUE;
+    }
+
+    public TypeConverter getTypeConverter(Class<?> toType, Class<?> fromType) {
+        return typeMappings.get(toType, fromType);
     }
 
-    @Override
     public void addTypeConverter(Class<?> toType, Class<?> fromType, TypeConverter typeConverter) {
         LOG.trace("Adding type converter: {}", typeConverter);
         TypeConverter converter = typeMappings.get(toType, fromType);
@@ -460,75 +453,29 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         }
     }
 
-    @Override
-    public void addTypeConverters(TypeConverters typeConverters) {
-        LOG.trace("Adding type converters: {}", typeConverters);
-        try {
-            // scan the class for @Converter and load them into this registry
-            TypeConvertersLoader loader = new TypeConvertersLoader(typeConverters);
-            loader.load(this);
-        } catch (TypeConverterLoaderException e) {
-            throw RuntimeCamelException.wrapRuntimeCamelException(e);
-        }
-    }
-
-    @Override
     public boolean removeTypeConverter(Class<?> toType, Class<?> fromType) {
         LOG.trace("Removing type converter from: {} to: {}", fromType, toType);
         return typeMappings.remove(toType, fromType);
     }
 
     @Override
+    public void addTypeConverters(TypeConverters typeConverters) {
+        throw new UnsupportedOperationException();
+    }
+
     public void addFallbackTypeConverter(TypeConverter typeConverter, boolean canPromote) {
         LOG.trace("Adding fallback type converter: {} which can promote: {}", typeConverter, canPromote);
 
         // add in top of fallback as the toString() fallback will nearly always be able to convert
         // the last one which is add to the FallbackTypeConverter will be called at the first place
         fallbackConverters.add(0, new FallbackTypeConverter(typeConverter, canPromote));
-
-        if (typeConverter instanceof CamelContextAware) {
-            CamelContextAware camelContextAware = (CamelContextAware) typeConverter;
-            if (camelContext != null) {
-                camelContextAware.setCamelContext(camelContext);
-            }
-        }
-    }
-
-    private void addCoreFallbackTypeConverterToList(TypeConverter typeConverter, boolean canPromote, List<
-            FallbackTypeConverter> converters) {
-        LOG.trace("Adding core fallback type converter: {} which can promote: {}", typeConverter, canPromote);
-
-        // add in top of fallback as the toString() fallback will nearly always be able to convert
-        // the last one which is add to the FallbackTypeConverter will be called at the first place
-        converters.add(0, new FallbackTypeConverter(typeConverter, canPromote));
-
-        if (typeConverter instanceof CamelContextAware) {
-            CamelContextAware camelContextAware = (CamelContextAware) typeConverter;
-            if (camelContext != null) {
-                camelContextAware.setCamelContext(camelContext);
-            }
-        }
-    }
-
-    public TypeConverter getTypeConverter(Class<?> toType, Class<?> fromType) {
-        return typeMappings.get(toType, fromType);
-    }
-
-    @Override
-    public Injector getInjector() {
-        return injector;
-    }
-
-    @Override
-    public void setInjector(Injector injector) {
-        this.injector = injector;
     }
 
-    public PackageScanClassResolver getResolver() {
-        return resolver;
+    public TypeConverter lookup(Class<?> toType, Class<?> fromType) {
+        return doLookup(toType, fromType, false);
     }
 
-    protected <T> TypeConverter getOrFindTypeConverter(Class<?> toType, Class<?> fromType) {
+    protected TypeConverter getOrFindTypeConverter(Class<?> toType, Class<?> fromType) {
         TypeConverter converter = typeMappings.get(toType, fromType);
         if (converter == null) {
             // converter not found, try to lookup then
@@ -540,11 +487,6 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         return converter;
     }
 
-    @Override
-    public TypeConverter lookup(Class<?> toType, Class<?> fromType) {
-        return doLookup(toType, fromType, false);
-    }
-
     protected TypeConverter doLookup(Class<?> toType, Class<?> fromType, boolean isSuper) {
 
         if (fromType != null) {
@@ -578,9 +520,9 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
 
                 // lets try classes derived from this toType
                 TypeConverter converter = typeMappings.getFirst(
-                    toType::isAssignableFrom,
-                    // skip Object based we do them last
-                    from -> !from.equals(Object.class) && from.isAssignableFrom(fromType));
+                        toType::isAssignableFrom,
+                        // skip Object based we do them last
+                        from -> !from.equals(Object.class) && from.isAssignableFrom(fromType));
                 if (converter != null) {
                     return converter;
                 }
@@ -597,146 +539,12 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         return null;
     }
 
-    @Override
     public List<Class<?>[]> listAllTypeConvertersFromTo() {
         List<Class<?>[]> answer = new ArrayList<>();
         typeMappings.forEach((k1, k2, v) -> answer.add(new Class<?>[]{k2, k1}));
         return answer;
     }
 
-    /**
-     * Loads the core type converters which is mandatory to use Camel,
-     * and also loads the fast type converters (generated via @Converter(loader = true).
-     */
-    public void loadCoreAndFastTypeConverters() throws Exception {
-        Collection<String> names = findTypeConverterLoaderClasses();
-        for (String name : names) {
-            LOG.debug("Resolving TypeConverterLoader: {}", name);
-            Class clazz = null;
-            for (ClassLoader loader : getResolver().getClassLoaders()) {
-                try {
-                    clazz = loader.loadClass(name);
-                } catch (Throwable e) {
-                    // ignore
-                }
-                if (clazz != null) {
-                    break;
-                }
-            }
-            if (clazz == null) {
-                throw new ClassNotFoundException(name);
-            }
-            Object obj = getInjector().newInstance(clazz, false);
-            if (obj instanceof TypeConverterLoader) {
-                TypeConverterLoader loader = (TypeConverterLoader) obj;
-                LOG.debug("TypeConverterLoader: {} loading converters", name);
-                loader.load(this);
-            }
-        }
-    }
-
-    /**
-     * Finds the type converter loader classes from the classpath looking
-     * for text files on the classpath at the {@link #META_INF_SERVICES_TYPE_CONVERTER_LOADER} location.
-     */
-    protected Collection<String> findTypeConverterLoaderClasses() throws IOException {
-        Set<String> loaders = new LinkedHashSet<>();
-        Collection<URL> loaderResources = getLoaderUrls();
-        for (URL url : loaderResources) {
-            LOG.debug("Loading file {} to retrieve list of type converters, from url: {}", META_INF_SERVICES_TYPE_CONVERTER_LOADER, url);
-            BufferedReader reader = IOHelper.buffered(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8));
-            String line;
-            do {
-                line = reader.readLine();
-                if (line != null && !line.startsWith("#") && !line.isEmpty()) {
-                    loaders.add(line);
-                }
-            } while (line != null);
-            IOHelper.close(reader);
-        }
-        return loaders;
-    }
-
-    protected Collection<URL> getLoaderUrls() throws IOException {
-        List<URL> loaderResources = new ArrayList<>();
-        for (ClassLoader classLoader : resolver.getClassLoaders()) {
-            Enumeration<URL> resources = classLoader.getResources(META_INF_SERVICES_TYPE_CONVERTER_LOADER);
-            while (resources.hasMoreElements()) {
-                URL url = resources.nextElement();
-                loaderResources.add(url);
-            }
-        }
-        return loaderResources;
-    }
-
-    /**
-     * Checks if the registry is loaded and if not lazily load it
-     */
-    protected void loadTypeConverters() throws Exception {
-        for (TypeConverterLoader typeConverterLoader : getTypeConverterLoaders()) {
-            typeConverterLoader.load(this);
-        }
-
-        // lets try load any other fallback converters
-        try {
-            loadFallbackTypeConverters();
-        } catch (NoFactoryAvailableException e) {
-            // ignore its fine to have none
-        }
-    }
-
-    /**
-     * Finds the fallback type converter classes from the classpath looking
-     * for text files on the classpath at the {@link #META_INF_SERVICES_FALLBACK_TYPE_CONVERTER} location.
-     */
-    protected Collection<String> findFallbackTypeConverterClasses() throws IOException {
-        Set<String> loaders = new LinkedHashSet<>();
-        Collection<URL> loaderResources = getFallbackUrls();
-        for (URL url : loaderResources) {
-            LOG.debug("Loading file {} to retrieve list of fallback type converters, from url: {}", META_INF_SERVICES_FALLBACK_TYPE_CONVERTER, url);
-            BufferedReader reader = IOHelper.buffered(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8));
-            try {
-                reader.lines()
-                        .map(String::trim)
-                        .filter(l -> !l.isEmpty())
-                        .filter(l -> !l.startsWith("#"))
-                        .forEach(loaders::add);
-            } finally {
-                IOHelper.close(reader, url.toString(), LOG);
-            }
-        }
-        return loaders;
-    }
-
-    protected Collection<URL> getFallbackUrls() throws IOException {
-        List<URL> loaderResources = new ArrayList<>();
-        for (ClassLoader classLoader : resolver.getClassLoaders()) {
-            Enumeration<URL> resources = classLoader.getResources(META_INF_SERVICES_FALLBACK_TYPE_CONVERTER);
-            while (resources.hasMoreElements()) {
-                URL url = resources.nextElement();
-                loaderResources.add(url);
-            }
-        }
-        return loaderResources;
-    }
-
-    protected void loadFallbackTypeConverters() throws IOException, ClassNotFoundException {
-        Collection<String> names = findFallbackTypeConverterClasses();
-        for (String name : names) {
-            LOG.debug("Resolving FallbackTypeConverter: {}", name);
-            Class clazz = getResolver().getClassLoaders().stream()
-                    .map(cl -> ObjectHelper.loadClass(name, cl))
-                    .filter(Objects::nonNull)
-                    .findAny().orElseThrow(() -> new ClassNotFoundException(name));
-            Object obj = getInjector().newInstance(clazz, false);
-            if (obj instanceof TypeConverter) {
-                TypeConverter fb = (TypeConverter) obj;
-                LOG.debug("Adding loaded FallbackTypeConverter: {}", name);
-                addFallbackTypeConverter(fb, false);
-            }
-        }
-    }
-
     protected TypeConversionException createTypeConversionException(Exchange exchange, Class<?> type, Object
             value, Throwable cause) {
         if (cause instanceof TypeConversionException) {
@@ -755,69 +563,33 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
         return new TypeConversionException(body, type, cause);
     }
 
-    @Override
     public Statistics getStatistics() {
         return statistics;
     }
 
-    @Override
     public int size() {
         return typeMappings.size();
     }
 
-    @Override
     public LoggingLevel getTypeConverterExistsLoggingLevel() {
         return typeConverterExistsLoggingLevel;
     }
 
-    @Override
     public void setTypeConverterExistsLoggingLevel(LoggingLevel typeConverterExistsLoggingLevel) {
         this.typeConverterExistsLoggingLevel = typeConverterExistsLoggingLevel;
     }
 
-    @Override
     public TypeConverterExists getTypeConverterExists() {
         return typeConverterExists;
     }
 
-    @Override
     public void setTypeConverterExists(TypeConverterExists typeConverterExists) {
         this.typeConverterExists = typeConverterExists;
     }
 
-    @Override
-    protected void doInit() {
-        if (injector == null && camelContext != null) {
-            injector = camelContext.getInjector();
-        }
-        if (resolver == null && camelContext != null) {
-            resolver = camelContext.adapt(ExtendedCamelContext.class).getPackageScanClassResolver();
-        }
-
-        List<FallbackTypeConverter> fallbacks = new ArrayList<>();
-        // add to string first as it will then be last in the last as to string can nearly
-        // always convert something to a string so we want it only as the last resort
-        // ToStringTypeConverter should NOT allow to be promoted
-        addCoreFallbackTypeConverterToList(new ToStringTypeConverter(), false, fallbacks);
-        // enum is okay to be promoted
-        addCoreFallbackTypeConverterToList(new EnumTypeConverter(), true, fallbacks);
-        // arrays is okay to be promoted
-        addCoreFallbackTypeConverterToList(new ArrayTypeConverter(), true, fallbacks);
-        // and future should also not allowed to be promoted
-        addCoreFallbackTypeConverterToList(new FutureTypeConverter(this), false, fallbacks);
-        // add sync processor to async processor converter is to be promoted
-        addCoreFallbackTypeConverterToList(new AsyncProcessorTypeConverter(), true, fallbacks);
-
-        // add all core fallback converters at once which is faster (profiler)
-        fallbackConverters.addAll(fallbacks);
-    }
-
-    @Override
     protected void doStart() throws Exception {
-        // noop
     }
 
-    @Override
     protected void doStop() throws Exception {
         // log utilization statistics when stopping, including mappings
         if (statistics.isStatisticsEnabled()) {
@@ -897,7 +669,7 @@ public abstract class BaseTypeConverterRegistry extends ServiceSupport implement
     /**
      * Represents a fallback type converter
      */
-    protected static class FallbackTypeConverter {
+    public static class FallbackTypeConverter {
         private final boolean canPromote;
         private final TypeConverter fallbackTypeConverter;
 
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/converter/DefaultTypeConverter.java b/core/camel-base/src/main/java/org/apache/camel/impl/converter/DefaultTypeConverter.java
index 086af3c..bc8a6a2 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/converter/DefaultTypeConverter.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/converter/DefaultTypeConverter.java
@@ -51,11 +51,6 @@ public class DefaultTypeConverter extends BaseTypeConverterRegistry implements A
     }
 
     @Override
-    public boolean allowNull() {
-        return false;
-    }
-
-    @Override
     public boolean isRunAllowed() {
         // as type converter is used during initialization then allow it to always run
         return true;
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index 868bf2d..b32bbc6 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -64,6 +64,7 @@ import org.apache.camel.Processor;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.ResolveEndpointFailedException;
 import org.apache.camel.Route;
+import org.apache.camel.RouteAware;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.Service;
@@ -155,15 +156,14 @@ import org.apache.camel.support.NormalizedUri;
 import org.apache.camel.support.OrderedComparator;
 import org.apache.camel.support.ProcessorEndpoint;
 import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.service.BaseService;
 import org.apache.camel.support.service.ServiceHelper;
-import org.apache.camel.support.service.ServiceSupport;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.StopWatch;
 import org.apache.camel.util.StringHelper;
 import org.apache.camel.util.TimeUtils;
 import org.apache.camel.util.URISupport;
-import org.apache.camel.util.function.ThrowingRunnable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
@@ -173,7 +173,7 @@ import static org.apache.camel.spi.UnitOfWork.MDC_CAMEL_CONTEXT_ID;
 /**
  * Represents the context used to configure routes and the policies to use.
  */
-public abstract class AbstractCamelContext extends ServiceSupport
+public abstract class AbstractCamelContext extends BaseService
         implements ExtendedCamelContext, CatalogCamelContext, Suspendable {
 
     private static final Logger LOG = LoggerFactory.getLogger(AbstractCamelContext.class);
@@ -346,6 +346,20 @@ public abstract class AbstractCamelContext extends ServiceSupport
         }
     }
 
+    public void close() throws IOException {
+        try {
+            stop();
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new IOException(e);
+        }
+    }
+
+    public CamelContext getCamelContextReference() {
+        return this;
+    }
+
     /**
      * Whether to eager create {@link TypeConverter} during initialization of CamelContext.
      * This is enabled by default to optimize camel-core.
@@ -355,28 +369,6 @@ public abstract class AbstractCamelContext extends ServiceSupport
     }
 
     @Override
-    public void doInit() throws Exception {
-        // Initialize LRUCacheFactory as eager as possible, 
-        // to let it warm up concurrently while Camel is startup up
-        if (initialization != Initialization.Lazy) {
-            LRUCacheFactory.init();
-        }
-
-        // Setup management first since end users may use it to add event
-        // notifiers using the management strategy before the CamelContext has been started
-        setupManagement(null);
-
-        // Call all registered trackers with this context
-        // Note, this may use a partially constructed object
-        CamelContextTracker.notifyContextCreated(this);
-        
-        // Setup type converter eager as its highly in use and should not be lazy initialized
-        if (eagerCreateTypeConverter()) {
-            getOrCreateTypeConverter();
-        }
-    }
-
-    @Override
     public <T extends CamelContext> T adapt(Class<T> type) {
         return type.cast(this);
     }
@@ -486,7 +478,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
     @Override
     public void addComponent(String componentName, final Component component) {
         ObjectHelper.notNull(component, "component");
-        component.setCamelContext(this);
+        component.setCamelContext(getCamelContextReference());
         ServiceHelper.initService(component);
         Component oldValue = components.putIfAbsent(componentName, component);
         if (oldValue != null) {
@@ -599,9 +591,9 @@ public abstract class AbstractCamelContext extends ServiceSupport
                 // See https://issues.apache.org/jira/browse/CAMEL-11225
                 componentsInCreation.get().add(name);
 
-                component = getComponentResolver().resolveComponent(name, this);
+                component = getComponentResolver().resolveComponent(name, getCamelContextReference());
                 if (component != null) {
-                    component.setCamelContext(this);
+                    component.setCamelContext(getCamelContextReference());
                     ServiceHelper.initService(component);
                     postInitComponent(name, component);
                 }
@@ -758,7 +750,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
     public NormalizedEndpointUri normalizeUri(String uri) {
         try {
             uri = resolvePropertyPlaceholders(uri);
-            uri = normalizeEndpointUri(uri);
+            uri = URISupport.normalizeUri(uri);
             return new NormalizedUri(uri);
         } catch (Exception e) {
             throw new ResolveEndpointFailedException(uri, e);
@@ -808,7 +800,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
         // normalize uri so we can do endpoint hits with minor mistakes and
         // parameters is not in the same order
         if (!normalized) {
-            uri = normalizeEndpointUri(uri);
+            uri = EndpointHelper.normalizeEndpointUri(uri);
         }
 
         LOG.trace("Getting endpoint with raw uri: {}, normalized uri: {}", rawUri, uri);
@@ -921,7 +913,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
         // normalize uri so we can do endpoint hits with minor mistakes and
         // parameters is not in the same order
         if (!normalized) {
-            uri = normalizeEndpointUri(uri);
+            uri = EndpointHelper.normalizeEndpointUri(uri);
         }
 
         LOG.trace("Getting endpoint with raw uri: {}, normalized uri: {}", rawUri, uri);
@@ -1038,23 +1030,6 @@ public abstract class AbstractCamelContext extends ServiceSupport
     }
 
     /**
-     * Normalize uri so we can do endpoint hits with minor mistakes and
-     * parameters is not in the same order.
-     *
-     * @param uri the uri
-     * @return normalized uri
-     * @throws ResolveEndpointFailedException if uri cannot be normalized
-     */
-    protected static String normalizeEndpointUri(String uri) {
-        try {
-            uri = URISupport.normalizeUri(uri);
-        } catch (Exception e) {
-            throw new ResolveEndpointFailedException(uri, e);
-        }
-        return uri;
-    }
-
-    /**
      * Gets the endpoint key to use for lookup or whe adding endpoints to the
      * {@link DefaultEndpointRegistry}
      *
@@ -1103,8 +1078,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
 
     @Override
     public void setRouteController(RouteController routeController) {
-        this.routeController = routeController;
-        doAddService(routeController);
+        this.routeController = doAddService(routeController);
     }
 
     @Override
@@ -1195,10 +1169,11 @@ public abstract class AbstractCamelContext extends ServiceSupport
         if (isStarted() && !isAllowAddingNewRoutes()) {
             throw new IllegalArgumentException("Adding new routes after CamelContext has been started is not allowed");
         }
-
-        init();
-        LOG.debug("Adding routes from builder: {}", builder);
-        doWithDefinedClassLoader(() -> builder.addRoutesToCamelContext(AbstractCamelContext.this));
+        try (LifecycleHelper helper = new LifecycleHelper()) {
+            init();
+            LOG.debug("Adding routes from builder: {}", builder);
+            builder.addRoutesToCamelContext(AbstractCamelContext.this);
+        }
     }
 
     public ServiceStatus getRouteStatus(String key) {
@@ -1460,7 +1435,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
         // inject CamelContext
         if (object instanceof CamelContextAware) {
             CamelContextAware aware = (CamelContextAware)object;
-            aware.setCamelContext(this);
+            aware.setCamelContext(getCamelContextReference());
         }
 
         if (object instanceof Service) {
@@ -1472,7 +1447,12 @@ public abstract class AbstractCamelContext extends ServiceSupport
                         // use specialized endpoint add
                         strategy.onEndpointAdd((Endpoint) service);
                     } else {
-                        Route route = setupRoute.get();
+                        Route route;
+                        if (service instanceof RouteAware) {
+                            route = ((RouteAware)service).getRoute();
+                        } else {
+                            route = setupRoute.get();
+                        }
                         strategy.onServiceAdd(this, service, route);
                     }
                 }
@@ -1590,6 +1570,10 @@ public abstract class AbstractCamelContext extends ServiceSupport
         }
     }
 
+    protected List<StartupListener> getStartupListeners() {
+        return startupListeners;
+    }
+
     @Override
     public void addStartupListener(StartupListener listener) throws Exception {
         // either add to listener so we can invoke then later when CamelContext
@@ -1733,12 +1717,12 @@ public abstract class AbstractCamelContext extends ServiceSupport
             }
 
             // language not known or not singleton, then use resolver
-            answer = getLanguageResolver().resolveLanguage(language, this);
+            answer = getLanguageResolver().resolveLanguage(language, getCamelContextReference());
 
             // inject CamelContext if aware
             if (answer != null) {
                 if (answer instanceof CamelContextAware) {
-                    ((CamelContextAware)answer).setCamelContext(this);
+                    ((CamelContextAware)answer).setCamelContext(getCamelContextReference());
                 }
                 if (answer instanceof Service) {
                     try {
@@ -1979,7 +1963,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
     @Override
     public void setRegistry(Registry registry) {
         if (registry instanceof CamelContextAware) {
-            ((CamelContextAware)registry).setCamelContext(this);
+            ((CamelContextAware)registry).setCamelContext(getCamelContextReference());
         }
         this.registry = registry;
     }
@@ -2175,7 +2159,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
 
     @Override
     public ProducerTemplate createProducerTemplate(int maximumCacheSize) {
-        DefaultProducerTemplate answer = new DefaultProducerTemplate(this);
+        DefaultProducerTemplate answer = new DefaultProducerTemplate(getCamelContextReference());
         answer.setMaximumCacheSize(maximumCacheSize);
         // start it so its ready to use
         try {
@@ -2193,7 +2177,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
 
     @Override
     public FluentProducerTemplate createFluentProducerTemplate(int maximumCacheSize) {
-        DefaultFluentProducerTemplate answer = new DefaultFluentProducerTemplate(this);
+        DefaultFluentProducerTemplate answer = new DefaultFluentProducerTemplate(getCamelContextReference());
         answer.setMaximumCacheSize(maximumCacheSize);
         // start it so its ready to use
         try {
@@ -2211,7 +2195,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
 
     @Override
     public ConsumerTemplate createConsumerTemplate(int maximumCacheSize) {
-        DefaultConsumerTemplate answer = new DefaultConsumerTemplate(this);
+        DefaultConsumerTemplate answer = new DefaultConsumerTemplate(getCamelContextReference());
         answer.setMaximumCacheSize(maximumCacheSize);
         // start it so its ready to use
         try {
@@ -2451,181 +2435,144 @@ public abstract class AbstractCamelContext extends ServiceSupport
         }
     }
 
+    // Implementation methods
+    // -----------------------------------------------------------------------
+
     @Override
-    public void start() {
-        startDate = new Date();
-        try (MDCHelper mdcHelper = new MDCHelper()) {
-            init();
-            vetoStarted.set(false);
-            stopWatch.restart();
-            LOG.info("Apache Camel {} (CamelContext: {}) is starting", getVersion(), getName());
+    protected AutoCloseable doLifecycleChange() {
+        return new LifecycleHelper();
+    }
 
-            // Start the route controller
-            ServiceHelper.startService(this.routeController);
+    @Override
+    public void doInit() throws Exception {
+        // Initialize LRUCacheFactory as eager as possible,
+        // to let it warm up concurrently while Camel is startup up
+        if (initialization != Initialization.Lazy) {
+            LRUCacheFactory.init();
+        }
 
-            doNotStartRoutesOnFirstStart = !firstStartDone && !isAutoStartup();
+        // Setup management first since end users may use it to add event
+        // notifiers using the management strategy before the CamelContext has been started
+        setupManagement(null);
 
-            // optimize - before starting routes lets check if event notifications is possible
-            eventNotificationApplicable = EventHelper.eventsApplicable(this);
+        // Call all registered trackers with this context
+        // Note, this may use a partially constructed object
+        CamelContextTracker.notifyContextCreated(this);
 
-            // if the context was configured with auto startup = false, and we
-            // are already started,
-            // then we may need to start the routes on the 2nd start call
-            if (firstStartDone && !isAutoStartup() && isStarted()) {
-                // invoke this logic to warm up the routes and if possible also
-                // start the routes
-                try {
-                    doStartOrResumeRoutes(routeServices, true, true, false, true);
-                } catch (Exception e) {
-                    throw RuntimeCamelException.wrapRuntimeException(e);
-                }
-            }
+        // Setup type converter eager as its highly in use and should not be lazy initialized
+        if (eagerCreateTypeConverter()) {
+            getOrCreateTypeConverter();
+        }
+    }
 
-            // super will invoke doStart which will prepare internal services
-            // and start routes etc.
-            try {
-                firstStartDone = true;
-                super.start();
-            } catch (Exception e) {
-                VetoCamelContextStartException veto = ObjectHelper.getException(VetoCamelContextStartException.class, e);
-                if (veto != null) {
-                    // mark we veto against starting Camel
-                    vetoStarted.set(true);
-                    if (veto.isRethrowException()) {
-                        throw e;
-                    } else {
-                        LOG.info("CamelContext ({}) vetoed to not start due {}", getName(), e.getMessage());
-                        // swallow exception and change state of this camel context
-                        // to stopped
-                        stop();
-                        return;
-                    }
-                } else {
-                    LOG.error("Error starting CamelContext (" + getName() + ") due to exception thrown: " + e.getMessage(), e);
-                    throw RuntimeCamelException.wrapRuntimeException(e);
-                }
-            }
+    @Override
+    protected synchronized void doStart() throws Exception {
+        try {
+            doStartContext();
+        } catch (Exception e) {
+            // fire event that we failed to start
+            EventHelper.notifyCamelContextStartupFailed(AbstractCamelContext.this, e);
+            // rethrow cause
+            throw e;
+        }
+    }
 
-            if (!isAllowAddingNewRoutes()) {
-                LOG.info("Adding new routes after CamelContext has started is not allowed");
-                disallowAddingNewRoutes();
-            }
+    protected void doStartContext() throws Exception {
+        startDate = new Date();
 
-            if (isClearModelReferences()) {
-                LOG.info("Clearing model references");
-                clearModelReferences();
-            }
+        vetoStarted.set(false);
+        stopWatch.restart();
+        LOG.info("Apache Camel {} (CamelContext: {}) is starting", getVersion(), getName());
 
-            if (LOG.isInfoEnabled()) {
-                // count how many routes are actually started
-                int started = 0;
-                for (Route route : getRoutes()) {
-                    ServiceStatus status = getRouteStatus(route.getId());
-                    if (status != null && status.isStarted()) {
-                        started++;
-                    }
-                }
+        // Start the route controller
+        ServiceHelper.startService(this.routeController);
 
-                final Collection<Route> controlledRoutes = getRouteController().getControlledRoutes();
-                if (controlledRoutes.isEmpty()) {
-                    LOG.info("Total {} routes, of which {} are started", getRoutes().size(), started);
-                } else {
-                    LOG.info("Total {} routes, of which {} are started, and {} are managed by RouteController: {}", getRoutes().size(), started, controlledRoutes.size(),
-                             getRouteController().getClass().getName());
-                }
-                LOG.info("Apache Camel {} (CamelContext: {}) started in {}", getVersion(), getName(), TimeUtils.printDuration(stopWatch.taken()));
-            }
+        doNotStartRoutesOnFirstStart = !firstStartDone && !isAutoStartup();
 
-            // okay the routes has been started so emit event that CamelContext
-            // has started (here at the end)
-            EventHelper.notifyCamelContextStarted(this);
+        // optimize - before starting routes lets check if event notifications is possible
+        eventNotificationApplicable = EventHelper.eventsApplicable(this);
 
-            // now call the startup listeners where the routes has been started
-            for (StartupListener startup : startupListeners) {
-                if (startup instanceof ExtendedStartupListener) {
-                    try {
-                        ((ExtendedStartupListener)startup).onCamelContextFullyStarted(this, isStarted());
-                    } catch (Exception e) {
-                        throw RuntimeCamelException.wrapRuntimeException(e);
-                    }
-                }
+        // if the context was configured with auto startup = false, and we
+        // are already started,
+        // then we may need to start the routes on the 2nd start call
+        if (firstStartDone && !isAutoStartup() && isStarted()) {
+            // invoke this logic to warm up the routes and if possible also
+            // start the routes
+            try {
+                doStartOrResumeRoutes(routeServices, true, true, false, true);
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
             }
         }
-    }
-
-    /**
-     * Strategy invoked when adding new routes after CamelContext has been started is not allowed.
-     * This is used to do some internal optimizations.
-     */
-    protected void disallowAddingNewRoutes() {
-        ReifierStrategy.clearReifiers();
-    }
 
-    protected void clearModelReferences() {
-    }
-
-    @Override
-    public void init() {
-        try (MDCHelper mdcHelper = new MDCHelper()) {
-            super.init();
+        // super will invoke doStart which will prepare internal services
+        // and start routes etc.
+        try {
+            firstStartDone = true;
+            doStartCamel();
+        } catch (Exception e) {
+            VetoCamelContextStartException veto = ObjectHelper.getException(VetoCamelContextStartException.class, e);
+            if (veto != null) {
+                // mark we veto against starting Camel
+                vetoStarted.set(true);
+                if (veto.isRethrowException()) {
+                    throw e;
+                } else {
+                    LOG.info("CamelContext ({}) vetoed to not start due {}", getName(), e.getMessage());
+                    // swallow exception and change state of this camel context
+                    // to stopped
+                    stop();
+                    return;
+                }
+            } else {
+                LOG.error("Error starting CamelContext (" + getName() + ") due to exception thrown: " + e.getMessage(), e);
+                throw RuntimeCamelException.wrapRuntimeException(e);
+            }
         }
-    }
 
-    @Override
-    public void stop() {
-        try (MDCHelper mdcHelper = new MDCHelper()) {
-            super.stop();
+        if (!isAllowAddingNewRoutes()) {
+            LOG.info("Adding new routes after CamelContext has started is not allowed");
+            disallowAddingNewRoutes();
         }
-    }
 
-    @Override
-    public void suspend() {
-        try (MDCHelper mdcHelper = new MDCHelper()) {
-            super.suspend();
+        if (isClearModelReferences()) {
+            LOG.info("Clearing model references");
+            clearModelReferences();
         }
-    }
 
-    @Override
-    public void resume() {
-        try (MDCHelper mdcHelper = new MDCHelper()) {
-            super.resume();
-        }
-    }
+        if (LOG.isInfoEnabled()) {
+            // count how many routes are actually started
+            int started = 0;
+            for (Route route : getRoutes()) {
+                ServiceStatus status = getRouteStatus(route.getId());
+                if (status != null && status.isStarted()) {
+                    started++;
+                }
+            }
 
-    @Override
-    public void shutdown() {
-        try (MDCHelper mdcHelper = new MDCHelper()) {
-            super.shutdown();
+            final Collection<Route> controlledRoutes = getRouteController().getControlledRoutes();
+            if (controlledRoutes.isEmpty()) {
+                LOG.info("Total {} routes, of which {} are started", getRoutes().size(), started);
+            } else {
+                LOG.info("Total {} routes, of which {} are started, and {} are managed by RouteController: {}", getRoutes().size(), started, controlledRoutes.size(),
+                        getRouteController().getClass().getName());
+            }
+            LOG.info("Apache Camel {} (CamelContext: {}) started in {}", getVersion(), getName(), TimeUtils.printDuration(stopWatch.taken()));
         }
-    }
 
-    // Implementation methods
-    // -----------------------------------------------------------------------
+        // okay the routes has been started so emit event that CamelContext
+        // has started (here at the end)
+        EventHelper.notifyCamelContextStarted(this);
 
-    @Override
-    protected synchronized void doStart() throws Exception {
-        doWithDefinedClassLoader(() -> {
-            try {
-                doStartCamel();
-            } catch (Exception e) {
-                // fire event that we failed to start
-                EventHelper.notifyCamelContextStartupFailed(AbstractCamelContext.this, e);
-                // rethrow cause
-                throw e;
-            }
-        });
-    }
-
-    private <T extends Throwable> void doWithDefinedClassLoader(ThrowingRunnable<T> callable) throws T {
-        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
-        try {
-            // Using the ApplicationClassLoader as the default for TCCL
-            if (applicationContextClassLoader != null) {
-                Thread.currentThread().setContextClassLoader(applicationContextClassLoader);
+        // now call the startup listeners where the routes has been started
+        for (StartupListener startup : startupListeners) {
+            if (startup instanceof ExtendedStartupListener) {
+                try {
+                    ((ExtendedStartupListener)startup).onCamelContextFullyStarted(this, isStarted());
+                } catch (Exception e) {
+                    throw RuntimeCamelException.wrapRuntimeException(e);
+                }
             }
-            callable.run();
-        } finally {
-            Thread.currentThread().setContextClassLoader(tccl);
         }
     }
 
@@ -2814,16 +2761,6 @@ public abstract class AbstractCamelContext extends ServiceSupport
         // starting will continue in the start method
     }
 
-    protected void startRouteDefinitions() throws Exception {
-    }
-
-    protected boolean isStreamCachingInUse() throws Exception {
-        return isStreamCaching();
-    }
-
-    protected void bindDataFormats() throws Exception {
-    }
-
     @Override
     protected synchronized void doStop() throws Exception {
         stopWatch.restart();
@@ -2956,6 +2893,27 @@ public abstract class AbstractCamelContext extends ServiceSupport
     }
 
     /**
+     * Strategy invoked when adding new routes after CamelContext has been started is not allowed.
+     * This is used to do some internal optimizations.
+     */
+    protected void disallowAddingNewRoutes() {
+        ReifierStrategy.clearReifiers();
+    }
+
+    protected void clearModelReferences() {
+    }
+
+    public void startRouteDefinitions() throws Exception {
+    }
+
+    protected boolean isStreamCachingInUse() throws Exception {
+        return isStreamCaching();
+    }
+
+    protected void bindDataFormats() throws Exception {
+    }
+
+    /**
      * Starts or resumes the routes
      *
      * @param routeServices the routes to start (will only start a route if its
@@ -3059,7 +3017,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
 
         if (service instanceof CamelContextAware) {
             CamelContextAware aware = (CamelContextAware)service;
-            aware.setCamelContext(this);
+            aware.setCamelContext(getCamelContextReference());
         }
 
         service.start();
@@ -3079,7 +3037,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
             ServiceHelper.stopService(service);
         } catch (Exception e) {
             // fire event
-            EventHelper.notifyServiceStopFailure(this, service, e);
+            EventHelper.notifyServiceStopFailure(getCamelContextReference(), service, e);
             // rethrow to signal error with stopping
             throw e;
         }
@@ -3219,7 +3177,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
         // now call the startup listeners where the routes has been warmed up
         // (only the actual route consumer has not yet been started)
         for (StartupListener startup : startupListeners) {
-            startup.onCamelContextStarted(this, isStarted());
+            startup.onCamelContextStarted(getCamelContextReference(), isStarted());
         }
         // because the consumers may also register startup listeners we need to
         // reset
@@ -3246,7 +3204,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
         // StartupListeners (such as timer)
         // so we need to ensure they get started as well
         for (StartupListener startup : startupListeners) {
-            startup.onCamelContextStarted(this, isStarted());
+            startup.onCamelContextStarted(getCamelContextReference(), isStarted());
         }
         // and add the previous started startup listeners to the list so we have
         // them all
@@ -3397,7 +3355,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
                 } else {
                     // when starting we should invoke the lifecycle strategies
                     for (LifecycleStrategy strategy : lifecycleStrategies) {
-                        strategy.onServiceAdd(this, consumer, route);
+                        strategy.onServiceAdd(getCamelContextReference(), consumer, route);
                     }
                     try {
                         startService(consumer);
@@ -3586,7 +3544,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
         if (value instanceof Endpoint) {
             return (Endpoint)value;
         } else if (value instanceof Processor) {
-            return new ProcessorEndpoint(uri, this, (Processor)value);
+            return new ProcessorEndpoint(uri, getCamelContextReference(), (Processor)value);
         } else if (value != null) {
             return convertBeanToEndpoint(uri, value);
         }
@@ -3808,7 +3766,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
         }
 
         try {
-            ManagementStrategy strategy = factory.create(this, options);
+            ManagementStrategy strategy = factory.create(getCamelContextReference(), options);
             if (notifiers != null) {
                 notifiers.forEach(strategy::addEventNotifier);
             }
@@ -3970,11 +3928,11 @@ public abstract class AbstractCamelContext extends ServiceSupport
 
     @Override
     public DataFormat resolveDataFormat(String name) {
-        DataFormat answer = getDataFormatResolver().resolveDataFormat(name, this);
+        DataFormat answer = getDataFormatResolver().resolveDataFormat(name, getCamelContextReference());
 
         // inject CamelContext if aware
         if (answer instanceof CamelContextAware) {
-            ((CamelContextAware)answer).setCamelContext(this);
+            ((CamelContextAware)answer).setCamelContext(getCamelContextReference());
         }
 
         return answer;
@@ -3982,11 +3940,11 @@ public abstract class AbstractCamelContext extends ServiceSupport
 
     @Override
     public DataFormat createDataFormat(String name) {
-        DataFormat answer = getDataFormatResolver().createDataFormat(name, this);
+        DataFormat answer = getDataFormatResolver().createDataFormat(name, getCamelContextReference());
 
         // inject CamelContext if aware
         if (answer instanceof CamelContextAware) {
-            ((CamelContextAware)answer).setCamelContext(this);
+            ((CamelContextAware)answer).setCamelContext(getCamelContextReference());
         }
 
         return answer;
@@ -4424,10 +4382,16 @@ public abstract class AbstractCamelContext extends ServiceSupport
         return "CamelContext(" + getName() + ")";
     }
 
-    class MDCHelper implements AutoCloseable {
+    class LifecycleHelper implements AutoCloseable {
         final Map<String, String> originalContextMap;
+        final ClassLoader tccl;
 
-        MDCHelper() {
+        LifecycleHelper() {
+            // Using the ApplicationClassLoader as the default for TCCL
+            tccl = Thread.currentThread().getContextClassLoader();
+            if (applicationContextClassLoader != null) {
+                Thread.currentThread().setContextClassLoader(applicationContextClassLoader);
+            }
             if (isUseMDCLogging()) {
                 originalContextMap = MDC.getCopyOfContextMap();
                 MDC.put(MDC_CAMEL_CONTEXT_ID, getName());
@@ -4445,6 +4409,7 @@ public abstract class AbstractCamelContext extends ServiceSupport
                     MDC.clear();
                 }
             }
+            Thread.currentThread().setContextClassLoader(tccl);
         }
     }
 
@@ -4532,4 +4497,83 @@ public abstract class AbstractCamelContext extends ServiceSupport
 
     protected abstract ValidatorRegistry<ValidatorKey> createValidatorRegistry();
 
+    @Override
+    public RouteController getInternalRouteController() {
+        return new RouteController() {
+            @Override
+            public Collection<Route> getControlledRoutes() {
+                return AbstractCamelContext.this.getRoutes();
+            }
+
+            @Override
+            public void startAllRoutes() throws Exception {
+                AbstractCamelContext.this.startAllRoutes();
+            }
+
+            @Override
+            public boolean isStartingRoutes() {
+                return AbstractCamelContext.this.isStartingRoutes();
+            }
+
+            @Override
+            public ServiceStatus getRouteStatus(String routeId) {
+                return AbstractCamelContext.this.getRouteStatus(routeId);
+            }
+
+            @Override
+            public void startRoute(String routeId) throws Exception {
+                AbstractCamelContext.this.startRoute(routeId);
+            }
+
+            @Override
+            public void stopRoute(String routeId) throws Exception {
+                AbstractCamelContext.this.stopRoute(routeId);
+            }
+
+            @Override
+            public void stopRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
+                AbstractCamelContext.this.stopRoute(routeId, timeout, timeUnit);
+            }
+
+            @Override
+            public boolean stopRoute(String routeId, long timeout, TimeUnit timeUnit, boolean abortAfterTimeout) throws Exception {
+                return AbstractCamelContext.this.stopRoute(routeId, timeout, timeUnit, abortAfterTimeout);
+            }
+
+            @Override
+            public void suspendRoute(String routeId) throws Exception {
+                AbstractCamelContext.this.suspendRoute(routeId);
+            }
+
+            @Override
+            public void suspendRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
+                AbstractCamelContext.this.suspendRoute(routeId, timeout, timeUnit);
+            }
+
+            @Override
+            public void resumeRoute(String routeId) throws Exception {
+                AbstractCamelContext.this.resumeRoute(routeId);
+            }
+
+            @Override
+            public void setCamelContext(CamelContext camelContext) {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public CamelContext getCamelContext() {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public void start() {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public void stop() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
 }
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultRouteController.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultRouteController.java
index 6b610f1..11d4eba 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultRouteController.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultRouteController.java
@@ -21,19 +21,20 @@ import java.util.Collections;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Route;
 import org.apache.camel.ServiceStatus;
 import org.apache.camel.spi.RouteController;
 import org.apache.camel.support.service.ServiceSupport;
 
 public class DefaultRouteController extends ServiceSupport implements RouteController  {
-    private AbstractCamelContext camelContext;
+    private CamelContext camelContext;
 
     public DefaultRouteController() {
         this(null);
     }
 
-    public DefaultRouteController(AbstractCamelContext camelContext) {
+    public DefaultRouteController(CamelContext camelContext) {
         this.camelContext = camelContext;
     }
 
@@ -43,7 +44,7 @@ public class DefaultRouteController extends ServiceSupport implements RouteContr
 
     @Override
     public void setCamelContext(CamelContext camelContext) {
-        this.camelContext = (AbstractCamelContext) camelContext;
+        this.camelContext = camelContext;
     }
 
     @Override
@@ -69,54 +70,58 @@ public class DefaultRouteController extends ServiceSupport implements RouteContr
     // Route management
     // ***************************************************
 
+    protected RouteController getInternalRouteController() {
+        return camelContext.adapt(ExtendedCamelContext.class).getInternalRouteController();
+    }
+
     @Override
     public void startAllRoutes() throws Exception {
-        camelContext.startAllRoutes();
+        getInternalRouteController().startAllRoutes();
     }
 
     @Override
     public boolean isStartingRoutes() {
-        return camelContext.isStartingRoutes();
+        return getInternalRouteController().isStartingRoutes();
     }
 
     @Override
     public ServiceStatus getRouteStatus(String routeId) {
-        return camelContext.getRouteStatus(routeId);
+        return getInternalRouteController().getRouteStatus(routeId);
     }
 
     @Override
     public void startRoute(String routeId) throws Exception {
-        camelContext.startRoute(routeId);
+        getInternalRouteController().startRoute(routeId);
     }
 
     @Override
     public void stopRoute(String routeId) throws Exception {
-        camelContext.stopRoute(routeId);
+        getInternalRouteController().stopRoute(routeId);
     }
 
     @Override
     public void stopRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
-        camelContext.stopRoute(routeId, timeout, timeUnit);
+        getInternalRouteController().stopRoute(routeId, timeout, timeUnit);
     }
 
     @Override
     public boolean stopRoute(String routeId, long timeout, TimeUnit timeUnit, boolean abortAfterTimeout) throws Exception {
-        return camelContext.stopRoute(routeId, timeout, timeUnit, abortAfterTimeout);
+        return getInternalRouteController().stopRoute(routeId, timeout, timeUnit, abortAfterTimeout);
     }
 
     @Override
     public void suspendRoute(String routeId) throws Exception {
-        camelContext.suspendRoute(routeId);
+        getInternalRouteController().suspendRoute(routeId);
     }
 
     @Override
     public void suspendRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
-        camelContext.suspendRoute(routeId, timeout, timeUnit);
+        getInternalRouteController().suspendRoute(routeId, timeout, timeUnit);
     }
 
     @Override
     public void resumeRoute(String routeId) throws Exception {
-        camelContext.resumeRoute(routeId);
+        getInternalRouteController().resumeRoute(routeId);
     }
 
     // ***************************************************
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/EndpointKey.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/EndpointKey.java
index 46be51c..0082110 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/EndpointKey.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/EndpointKey.java
@@ -18,6 +18,7 @@ package org.apache.camel.impl.engine;
 
 import org.apache.camel.ValueHolder;
 import org.apache.camel.spi.NormalizedEndpointUri;
+import org.apache.camel.support.EndpointHelper;
 import org.apache.camel.util.StringHelper;
 
 /**
@@ -34,7 +35,7 @@ public final class EndpointKey extends ValueHolder<String> implements Normalized
      * Optimized when the uri is already normalized.
      */
     public EndpointKey(String uri, boolean normalized) {
-        super(normalized ? uri : AbstractCamelContext.normalizeEndpointUri(uri));
+        super(normalized ? uri : EndpointHelper.normalizeEndpointUri(uri));
         StringHelper.notEmpty(uri, "uri");
     }
 
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/RouteService.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/RouteService.java
index d67ab7e..8483ab8 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/RouteService.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/RouteService.java
@@ -32,6 +32,7 @@ import org.apache.camel.Consumer;
 import org.apache.camel.Endpoint;
 import org.apache.camel.EndpointAware;
 import org.apache.camel.ErrorHandlerFactory;
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.FailedToStartRouteException;
 import org.apache.camel.Processor;
 import org.apache.camel.Route;
@@ -56,7 +57,7 @@ import static org.apache.camel.spi.UnitOfWork.MDC_ROUTE_ID;
  */
 public class RouteService extends ChildServiceSupport {
 
-    private final AbstractCamelContext camelContext;
+    private final CamelContext camelContext;
     private final Route route;
     private boolean removingRoutes;
     private final Map<Route, Consumer> inputs = new HashMap<>();
@@ -65,7 +66,7 @@ public class RouteService extends ChildServiceSupport {
 
     public RouteService(Route route) {
         this.route = route;
-        this.camelContext = this.route.getCamelContext().adapt(AbstractCamelContext.class);
+        this.camelContext = this.route.getCamelContext();
     }
 
     public String getId() {
@@ -192,7 +193,7 @@ public class RouteService extends ChildServiceSupport {
             }
 
             // add routes to camel context
-            camelContext.addRoute(route);
+            camelContext.adapt(ExtendedCamelContext.class).addRoute(route);
 
             // add the routes to the inflight registry so they are pre-installed
             camelContext.getInflightRepository().addRoute(route.getId());
@@ -253,7 +254,7 @@ public class RouteService extends ChildServiceSupport {
             EventHelper.notifyRouteStopped(camelContext, route);
         }
         if (isRemovingRoutes()) {
-            camelContext.removeRoute(route);
+            camelContext.adapt(ExtendedCamelContext.class).removeRoute(route);
         }
         // need to warm up again
         warmUpDone.set(false);
@@ -291,7 +292,7 @@ public class RouteService extends ChildServiceSupport {
         camelContext.getInflightRepository().removeRoute(route.getId());
 
         // remove the routes from the collections
-        camelContext.removeRoute(route);
+        camelContext.adapt(ExtendedCamelContext.class).removeRoute(route);
 
         // clear inputs on shutdown
         inputs.clear();
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
index 1b9beac..db8eed0 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java
@@ -114,7 +114,7 @@ public class SimpleCamelContext extends AbstractCamelContext {
 
     @Override
     protected TypeConverter createTypeConverter() {
-        return new DefaultTypeConverter(this, getPackageScanClassResolver(), getInjector(),
+        return new DefaultTypeConverter(getCamelContextReference(), getPackageScanClassResolver(), getInjector(),
                 getDefaultFactoryFinder(), isLoadTypeConverters());
     }
 
@@ -134,19 +134,19 @@ public class SimpleCamelContext extends AbstractCamelContext {
     @Override
     protected Injector createInjector() {
         FactoryFinder finder = getDefaultFactoryFinder();
-        return finder.newInstance("Injector", Injector.class).orElse(new DefaultInjector(this));
+        return finder.newInstance("Injector", Injector.class).orElse(new DefaultInjector(getCamelContextReference()));
     }
 
     @Override
     protected PropertiesComponent createPropertiesComponent() {
         return new BaseServiceResolver<>(PropertiesComponent.FACTORY, PropertiesComponent.class)
-                .resolve(this)
+                .resolve(getCamelContextReference())
                 .orElseGet(org.apache.camel.component.properties.PropertiesComponent::new);
     }
 
     @Override
     protected CamelBeanPostProcessor createBeanPostProcessor() {
-        return new DefaultCamelBeanPostProcessor(this);
+        return new DefaultCamelBeanPostProcessor(getCamelContextReference());
     }
 
     @Override
@@ -167,7 +167,7 @@ public class SimpleCamelContext extends AbstractCamelContext {
     @Override
     protected ModelJAXBContextFactory createModelJAXBContextFactory() {
         return new BaseServiceResolver<>(ModelJAXBContextFactory.FACTORY, ModelJAXBContextFactory.class)
-                .resolve(this)
+                .resolve(getCamelContextReference())
                 .orElseThrow(() -> new IllegalArgumentException("Cannot find ModelJAXBContextFactory on classpath. "
                         + "Add camel-xml-jaxb to classpath."));
     }
@@ -184,7 +184,7 @@ public class SimpleCamelContext extends AbstractCamelContext {
 
     @Override
     protected ClassResolver createClassResolver() {
-        return new DefaultClassResolver(this);
+        return new DefaultClassResolver(getCamelContextReference());
     }
 
     @Override
@@ -214,12 +214,13 @@ public class SimpleCamelContext extends AbstractCamelContext {
 
     @Override
     protected RouteController createRouteController() {
-        return new DefaultRouteController(this);
+        // TODO:
+        return new DefaultRouteController(getCamelContextReference());
     }
 
     @Override
     protected ShutdownStrategy createShutdownStrategy() {
-        return new DefaultShutdownStrategy(this);
+        return new DefaultShutdownStrategy(getCamelContextReference());
     }
 
     @Override
@@ -248,7 +249,7 @@ public class SimpleCamelContext extends AbstractCamelContext {
     @Override
     protected RuntimeCamelCatalog createRuntimeCamelCatalog() {
         return new BaseServiceResolver<>(RuntimeCamelCatalog.FACTORY, RuntimeCamelCatalog.class)
-                .resolve(this)
+                .resolve(getCamelContextReference())
                 .orElseThrow(() -> new IllegalArgumentException("Cannot find RuntimeCamelCatalog on classpath. "
                         + "Add camel-core-catalog to classpath."));
     }
@@ -260,20 +261,20 @@ public class SimpleCamelContext extends AbstractCamelContext {
 
     @Override
     protected ManagementNameStrategy createManagementNameStrategy() {
-        return new DefaultManagementNameStrategy(this);
+        return new DefaultManagementNameStrategy(getCamelContextReference());
     }
 
     @Override
     protected HeadersMapFactory createHeadersMapFactory() {
         return new BaseServiceResolver<>(HeadersMapFactory.FACTORY, HeadersMapFactory.class)
-                .resolve(this)
+                .resolve(getCamelContextReference())
                 .orElseGet(DefaultHeadersMapFactory::new);
     }
 
     @Override
     protected BeanProxyFactory createBeanProxyFactory() {
         return new BaseServiceResolver<>(BeanProxyFactory.FACTORY, BeanProxyFactory.class)
-                .resolve(this)
+                .resolve(getCamelContextReference())
                 .orElseThrow(() -> new IllegalArgumentException("Cannot find BeanProxyFactory on classpath. "
                         + "Add camel-bean to classpath."));
     }
@@ -281,7 +282,7 @@ public class SimpleCamelContext extends AbstractCamelContext {
     @Override
     protected BeanProcessorFactory createBeanProcessorFactory() {
         return new BaseServiceResolver<>(BeanProcessorFactory.FACTORY, BeanProcessorFactory.class)
-                .resolve(this)
+                .resolve(getCamelContextReference())
                 .orElseThrow(() -> new IllegalArgumentException("Cannot find BeanProcessorFactory on classpath. "
                         + "Add camel-bean to classpath."));
     }
@@ -294,7 +295,7 @@ public class SimpleCamelContext extends AbstractCamelContext {
     @Override
     protected XMLRoutesDefinitionLoader createXMLRoutesDefinitionLoader() {
         return new BaseServiceResolver<>(XMLRoutesDefinitionLoader.FACTORY, XMLRoutesDefinitionLoader.class)
-                .resolve(this)
+                .resolve(getCamelContextReference())
                 .orElseThrow(() -> new IllegalArgumentException("Cannot find XMLRoutesDefinitionLoader on classpath. "
                         + "Add either camel-xml-io or camel-xml-jaxb to classpath."));
     }
@@ -302,7 +303,7 @@ public class SimpleCamelContext extends AbstractCamelContext {
     @Override
     protected ModelToXMLDumper createModelToXMLDumper() {
         return new BaseServiceResolver<>(ModelToXMLDumper.FACTORY, ModelToXMLDumper.class)
-                .resolve(this)
+                .resolve(getCamelContextReference())
                 .orElseThrow(() -> new IllegalArgumentException("Cannot find ModelToXMLDumper on classpath. "
                         + "Add camel-xml-jaxb to classpath."));
     }
@@ -340,14 +341,14 @@ public class SimpleCamelContext extends AbstractCamelContext {
     @Override
     protected RestRegistryFactory createRestRegistryFactory() {
         return new BaseServiceResolver<>(RestRegistryFactory.FACTORY, RestRegistryFactory.class)
-                .resolve(this)
+                .resolve(getCamelContextReference())
                 .orElseThrow(() -> new IllegalArgumentException("Cannot find RestRegistryFactory on classpath. "
                         + "Add camel-rest to classpath."));
     }
 
     @Override
     protected EndpointRegistry<EndpointKey> createEndpointRegistry(Map<EndpointKey, Endpoint> endpoints) {
-        return new DefaultEndpointRegistry(this, endpoints);
+        return new DefaultEndpointRegistry(getCamelContextReference(), endpoints);
     }
 
     @Override
@@ -358,27 +359,27 @@ public class SimpleCamelContext extends AbstractCamelContext {
     @Override
     protected ReactiveExecutor createReactiveExecutor() {
         return new BaseServiceResolver<>(ReactiveExecutor.FACTORY, ReactiveExecutor.class)
-                .resolve(this)
+                .resolve(getCamelContextReference())
                 .orElseGet(DefaultReactiveExecutor::new);
     }
 
     @Override
     public AsyncProcessor createMulticast(Collection<Processor> processors, ExecutorService executor, boolean shutdownExecutorService) {
-        return new MulticastProcessor(this, processors, null, true, executor, shutdownExecutorService, false, false, 0, null, false, false);
+        return new MulticastProcessor(getCamelContextReference(), processors, null, true, executor, shutdownExecutorService, false, false, 0, null, false, false);
     }
 
     @Override
     protected ValidatorRegistry<ValidatorKey> createValidatorRegistry() {
-        return new DefaultValidatorRegistry(this);
+        return new DefaultValidatorRegistry(getCamelContextReference());
     }
 
     @Override
     protected TransformerRegistry<TransformerKey> createTransformerRegistry() {
-        return new DefaultTransformerRegistry(this);
+        return new DefaultTransformerRegistry(getCamelContextReference());
     }
 
     @Override
     protected ExecutorServiceManager createExecutorServiceManager() {
-        return new BaseExecutorServiceManager(this);
+        return new BaseExecutorServiceManager(getCamelContextReference());
     }
 }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
index dfde2fa..17b9531 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.function.Function;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.FailedToStartRouteException;
 import org.apache.camel.Navigate;
 import org.apache.camel.Processor;
 import org.apache.camel.Route;
@@ -39,11 +40,13 @@ import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.model.RouteDefinitionHelper;
 import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.transformer.TransformerDefinition;
 import org.apache.camel.model.validator.ValidatorDefinition;
 import org.apache.camel.processor.channel.DefaultChannel;
+import org.apache.camel.reifier.RouteReifier;
 import org.apache.camel.reifier.dataformat.DataFormatReifier;
 import org.apache.camel.spi.BeanRepository;
 import org.apache.camel.spi.DataFormat;
@@ -319,7 +322,33 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame
 
     @Override
     public void startRouteDefinitions() throws Exception {
-        model.startRouteDefinitions();
+        List<RouteDefinition> routeDefinitions = model.getRouteDefinitions();
+        if (routeDefinitions != null) {
+            startRouteDefinitions(routeDefinitions);
+        }
+    }
+
+    public void startRouteDefinitions(List<RouteDefinition> routeDefinitions) throws Exception {
+        RouteDefinitionHelper.forceAssignIds(getCamelContextReference(), routeDefinitions);
+        for (RouteDefinition routeDefinition : routeDefinitions) {
+            // assign ids to the routes and validate that the id's is all unique
+            String duplicate = RouteDefinitionHelper.validateUniqueIds(routeDefinition, routeDefinitions);
+            if (duplicate != null) {
+                throw new FailedToStartRouteException(routeDefinition.getId(), "duplicate id detected: " + duplicate + ". Please correct ids to be unique among all your routes.");
+            }
+
+            // must ensure route is prepared, before we can start it
+            if (!routeDefinition.isPrepared()) {
+                RouteDefinitionHelper.prepareRoute(getCamelContextReference(), routeDefinition);
+                routeDefinition.markPrepared();
+            }
+
+            // indicate we are staring the route using this thread so
+            // we are able to query this if needed
+            Route route = new RouteReifier(getCamelContextReference(), routeDefinition).createRoute();
+            RouteService routeService = new RouteService(route);
+            startRouteService(routeService, true);
+        }
     }
 
     @Override
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
index c0a786b..722dae2 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
@@ -28,24 +28,19 @@ import java.util.function.Function;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.ExtendedCamelContext;
-import org.apache.camel.FailedToStartRouteException;
-import org.apache.camel.Route;
-import org.apache.camel.impl.engine.AbstractCamelContext;
-import org.apache.camel.impl.engine.RouteService;
 import org.apache.camel.model.DataFormatDefinition;
 import org.apache.camel.model.HystrixConfigurationDefinition;
 import org.apache.camel.model.Model;
+import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.ProcessorDefinitionHelper;
 import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RouteDefinition;
-import org.apache.camel.model.RouteDefinitionHelper;
 import org.apache.camel.model.RouteFilters;
 import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.transformer.TransformerDefinition;
 import org.apache.camel.model.validator.ValidatorDefinition;
-import org.apache.camel.reifier.RouteReifier;
 
 public class DefaultModel implements Model {
 
@@ -84,7 +79,7 @@ public class DefaultModel implements Model {
         removeRouteDefinitions(list);
         this.routeDefinitions.addAll(list);
         if (shouldStartRoutes()) {
-            startRouteDefinitions(list);
+            getCamelContext().adapt(ModelCamelContext.class).startRouteDefinitions(list);
         }
     }
 
@@ -298,11 +293,6 @@ public class DefaultModel implements Model {
     }
 
     @Override
-    public void startRouteDefinitions() throws Exception {
-        startRouteDefinitions(routeDefinitions);
-    }
-
-    @Override
     public void setRouteFilterPattern(String include, String exclude) {
         setRouteFilter(RouteFilters.filterByPattern(include, exclude));
     }
@@ -317,49 +307,6 @@ public class DefaultModel implements Model {
         this.routeFilter = routeFilter;
     }
 
-    protected void startRouteDefinitions(Collection<RouteDefinition> list) throws Exception {
-        if (list != null) {
-            for (RouteDefinition route : list) {
-                startRoute(route);
-            }
-        }
-    }
-
-    public void startRoute(RouteDefinition routeDefinition) throws Exception {
-        prepare(routeDefinition);
-        start(routeDefinition);
-    }
-
-    protected void prepare(RouteDefinition routeDefinition) throws Exception {
-        // assign ids to the routes and validate that the id's is all unique
-        RouteDefinitionHelper.forceAssignIds(camelContext, routeDefinitions);
-        String duplicate = RouteDefinitionHelper.validateUniqueIds(routeDefinition, routeDefinitions);
-        if (duplicate != null) {
-            throw new FailedToStartRouteException(routeDefinition.getId(), "duplicate id detected: " + duplicate + ". Please correct ids to be unique among all your routes.");
-        }
-
-        // must ensure route is prepared, before we can start it
-        if (!routeDefinition.isPrepared()) {
-            RouteDefinitionHelper.prepareRoute(camelContext, routeDefinition);
-            routeDefinition.markPrepared();
-        }
-    }
-
-    protected void start(RouteDefinition routeDefinition) throws Exception {
-        // indicate we are staring the route using this thread so
-        // we are able to query this if needed
-        AbstractCamelContext mcc = camelContext.adapt(AbstractCamelContext.class);
-        mcc.setStartingRoutes(true);
-        try {
-            Route route = new RouteReifier(camelContext, routeDefinition).createRoute();
-            RouteService routeService = new RouteService(route);
-            mcc.startRouteService(routeService, true);
-        } finally {
-            // we are done staring routes
-            mcc.setStartingRoutes(false);
-        }
-    }
-
     /**
      * Should we start newly added routes?
      */
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/ImmutableCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/ImmutableCamelContext.java
new file mode 100644
index 0000000..a147442
--- /dev/null
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/ImmutableCamelContext.java
@@ -0,0 +1,1657 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.impl.lw;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.function.Function;
+
+import org.apache.camel.AsyncProcessor;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CatalogCamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.ConsumerTemplate;
+import org.apache.camel.Endpoint;
+import org.apache.camel.ErrorHandlerFactory;
+import org.apache.camel.Experimental;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.FluentProducerTemplate;
+import org.apache.camel.GlobalEndpointConfiguration;
+import org.apache.camel.NoSuchLanguageException;
+import org.apache.camel.Processor;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.Route;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.ServiceStatus;
+import org.apache.camel.ShutdownRoute;
+import org.apache.camel.ShutdownRunningTask;
+import org.apache.camel.StartupListener;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.ValueHolder;
+import org.apache.camel.catalog.RuntimeCamelCatalog;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.model.DataFormatDefinition;
+import org.apache.camel.model.HystrixConfigurationDefinition;
+import org.apache.camel.model.ModelCamelContext;
+import org.apache.camel.model.ProcessorDefinition;
+import org.apache.camel.model.Resilience4jConfigurationDefinition;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
+import org.apache.camel.model.rest.RestDefinition;
+import org.apache.camel.model.transformer.TransformerDefinition;
+import org.apache.camel.model.validator.ValidatorDefinition;
+import org.apache.camel.spi.AnnotationBasedProcessorFactory;
+import org.apache.camel.spi.AsyncProcessorAwaitManager;
+import org.apache.camel.spi.BeanIntrospection;
+import org.apache.camel.spi.BeanProcessorFactory;
+import org.apache.camel.spi.BeanProxyFactory;
+import org.apache.camel.spi.BeanRepository;
+import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.spi.CamelContextNameStrategy;
+import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.spi.ComponentResolver;
+import org.apache.camel.spi.ConfigurerResolver;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataFormatResolver;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Debugger;
+import org.apache.camel.spi.DeferServiceFactory;
+import org.apache.camel.spi.EndpointRegistry;
+import org.apache.camel.spi.EndpointStrategy;
+import org.apache.camel.spi.ExecutorServiceManager;
+import org.apache.camel.spi.FactoryFinder;
+import org.apache.camel.spi.FactoryFinderResolver;
+import org.apache.camel.spi.HeadersMapFactory;
+import org.apache.camel.spi.InflightRepository;
+import org.apache.camel.spi.Injector;
+import org.apache.camel.spi.InterceptStrategy;
+import org.apache.camel.spi.Language;
+import org.apache.camel.spi.LanguageResolver;
+import org.apache.camel.spi.LifecycleStrategy;
+import org.apache.camel.spi.LogListener;
+import org.apache.camel.spi.ManagementMBeanAssembler;
+import org.apache.camel.spi.ManagementNameStrategy;
+import org.apache.camel.spi.ManagementStrategy;
+import org.apache.camel.spi.MessageHistoryFactory;
+import org.apache.camel.spi.ModelJAXBContextFactory;
+import org.apache.camel.spi.ModelToXMLDumper;
+import org.apache.camel.spi.NodeIdFactory;
+import org.apache.camel.spi.NormalizedEndpointUri;
+import org.apache.camel.spi.PackageScanClassResolver;
+import org.apache.camel.spi.PackageScanResourceResolver;
+import org.apache.camel.spi.ProcessorFactory;
+import org.apache.camel.spi.PropertiesComponent;
+import org.apache.camel.spi.ReactiveExecutor;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.spi.RestConfiguration;
+import org.apache.camel.spi.RestRegistry;
+import org.apache.camel.spi.RouteController;
+import org.apache.camel.spi.RoutePolicyFactory;
+import org.apache.camel.spi.RouteStartupOrder;
+import org.apache.camel.spi.RuntimeEndpointRegistry;
+import org.apache.camel.spi.ShutdownStrategy;
+import org.apache.camel.spi.StreamCachingStrategy;
+import org.apache.camel.spi.Tracer;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.TransformerRegistry;
+import org.apache.camel.spi.TypeConverterRegistry;
+import org.apache.camel.spi.UnitOfWorkFactory;
+import org.apache.camel.spi.UuidGenerator;
+import org.apache.camel.spi.Validator;
+import org.apache.camel.spi.ValidatorRegistry;
+import org.apache.camel.spi.XMLRoutesDefinitionLoader;
+import org.apache.camel.support.DefaultRegistry;
+import org.apache.camel.support.jsse.SSLContextParameters;
+
+@Experimental
+public class ImmutableCamelContext implements ExtendedCamelContext, CatalogCamelContext, ModelCamelContext {
+
+    protected volatile CamelContext delegate;
+
+    /**
+     * Creates the {@link ModelCamelContext} using
+     * {@link org.apache.camel.support.DefaultRegistry} as registry.
+     * <p/>
+     * Use one of the other constructors to force use an explicit registry.
+     */
+    public ImmutableCamelContext() {
+        delegate = new DefaultCamelContext(false) {
+            @Override
+            public CamelContext getCamelContextReference() {
+                return ImmutableCamelContext.this;
+            }
+        };
+    }
+
+    public CamelContext getCamelContextReference() {
+        return this;
+    }
+
+    /**
+     * Creates the {@link CamelContext} using the given {@link BeanRepository}
+     * as first-choice repository, and the
+     * {@link org.apache.camel.support.SimpleRegistry} as fallback, via the
+     * {@link DefaultRegistry} implementation.
+     *
+     * @param repository the bean repository.
+     */
+    public ImmutableCamelContext(BeanRepository repository) {
+        this(new DefaultRegistry(repository));
+    }
+
+    /**
+     * Creates the {@link ModelCamelContext} using the given registry
+     *
+     * @param registry the registry
+     */
+    public ImmutableCamelContext(Registry registry) {
+        this();
+        setRegistry(registry);
+    }
+
+    protected ImmutableCamelContext(CamelContext delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public boolean isStarted() {
+        return delegate.isStarted();
+    }
+
+    @Override
+    public boolean isStarting() {
+        return delegate.isStarting();
+    }
+
+    @Override
+    public boolean isStopped() {
+        return delegate.isStopped();
+    }
+
+    @Override
+    public boolean isStopping() {
+        return delegate.isStopping();
+    }
+
+    @Override
+    public boolean isSuspended() {
+        return delegate.isSuspended();
+    }
+
+    @Override
+    public boolean isRunAllowed() {
+        return delegate.isRunAllowed();
+    }
+
+    @Override
+    public boolean isSuspending() {
+        return delegate.isSuspending();
+    }
+
+    @Override
+    public void init() {
+        delegate.init();
+    }
+
+    @Override
+    public void suspend() {
+        delegate.suspend();
+    }
+
+    @Override
+    public void resume() {
+        delegate.resume();
+    }
+
+    @Override
+    public void shutdown() {
+        delegate.shutdown();
+    }
+
+    @Override
+    public void close() throws IOException {
+        delegate.close();
+    }
+
+    @Override
+    public <T extends CamelContext> T adapt(Class<T> type) {
+        T res = delegate.adapt(type);
+        if (res == delegate) {
+            return type.cast(this);
+        } else {
+            return res;
+        }
+    }
+
+    @Override
+    public <T> T getExtension(Class<T> type) {
+        return delegate.getExtension(type);
+    }
+
+    @Override
+    public <T> void setExtension(Class<T> type, T module) {
+        delegate.setExtension(type, module);
+    }
+
+    @Override
+    public void start() {
+        delegate.start();
+    }
+
+    @Override
+    public void stop() {
+        delegate.stop();
+    }
+
+    @Override
+    public boolean isVetoStarted() {
+        return delegate.isVetoStarted();
+    }
+
+    @Override
+    public String getName() {
+        return delegate.getName();
+    }
+
+    @Override
+    public CamelContextNameStrategy getNameStrategy() {
+        return delegate.getNameStrategy();
+    }
+
+    @Override
+    public void setNameStrategy(CamelContextNameStrategy nameStrategy) {
+        delegate.setNameStrategy(nameStrategy);
+    }
+
+    @Override
+    public ManagementNameStrategy getManagementNameStrategy() {
+        return delegate.getManagementNameStrategy();
+    }
+
+    @Override
+    public void setManagementNameStrategy(ManagementNameStrategy nameStrategy) {
+        delegate.setManagementNameStrategy(nameStrategy);
+    }
+
+    @Override
+    public String getManagementName() {
+        return delegate.getManagementName();
+    }
+
+    @Override
+    public void setManagementName(String name) {
+        delegate.setManagementName(name);
+    }
+
+    @Override
+    public String getVersion() {
+        return delegate.getVersion();
+    }
+
+    @Override
+    public ServiceStatus getStatus() {
+        return delegate.getStatus();
+    }
+
+    @Override
+    public String getUptime() {
+        return delegate.getUptime();
+    }
+
+    @Override
+    public long getUptimeMillis() {
+        return delegate.getUptimeMillis();
+    }
+
+    @Override
+    public Date getStartDate() {
+        return delegate.getStartDate();
+    }
+
+    @Override
+    public void addService(Object object) throws Exception {
+        delegate.addService(object);
+    }
+
+    @Override
+    public void addService(Object object, boolean stopOnShutdown) throws Exception {
+        delegate.addService(object, stopOnShutdown);
+    }
+
+    @Override
+    public void addService(Object object, boolean stopOnShutdown, boolean forceStart) throws Exception {
+        delegate.addService(object, stopOnShutdown, forceStart);
+    }
+
+    @Override
+    public void addPrototypeService(Object object) throws Exception {
+        delegate.addPrototypeService(object);
+    }
+
+    @Override
+    public boolean removeService(Object object) throws Exception {
+        return delegate.removeService(object);
+    }
+
+    @Override
+    public boolean hasService(Object object) {
+        return delegate.hasService(object);
+    }
+
+    @Override
+    public <T> T hasService(Class<T> type) {
+        return delegate.hasService(type);
+    }
+
+    @Override
+    public <T> Set<T> hasServices(Class<T> type) {
+        return delegate.hasServices(type);
+    }
+
+    @Override
+    public void deferStartService(Object object, boolean stopOnShutdown) throws Exception {
+        delegate.deferStartService(object, stopOnShutdown);
+    }
+
+    @Override
+    public void addStartupListener(StartupListener listener) throws Exception {
+        delegate.addStartupListener(listener);
+    }
+
+    @Override
+    public void addComponent(String componentName, Component component) {
+        delegate.addComponent(componentName, component);
+    }
+
+    @Override
+    public Component hasComponent(String componentName) {
+        return delegate.hasComponent(componentName);
+    }
+
+    @Override
+    public Component getComponent(String componentName) {
+        return delegate.getComponent(componentName);
+    }
+
+    @Override
+    public Component getComponent(String name, boolean autoCreateComponents) {
+        return delegate.getComponent(name, autoCreateComponents);
+    }
+
+    @Override
+    public Component getComponent(String name, boolean autoCreateComponents, boolean autoStart) {
+        return delegate.getComponent(name, autoCreateComponents, autoStart);
+    }
+
+    @Override
+    public <T extends Component> T getComponent(String name, Class<T> componentType) {
+        return delegate.getComponent(name, componentType);
+    }
+
+    @Override
+    public List<String> getComponentNames() {
+        return delegate.getComponentNames();
+    }
+
+    @Override
+    public Component removeComponent(String componentName) {
+        return delegate.removeComponent(componentName);
+    }
+
+    @Override
+    public EndpointRegistry<? extends ValueHolder<String>> getEndpointRegistry() {
+        return delegate.getEndpointRegistry();
+    }
+
+    @Override
+    public Endpoint getEndpoint(String uri) {
+        return delegate.getEndpoint(uri);
+    }
+
+    @Override
+    public Endpoint getEndpoint(String uri, Map<String, Object> parameters) {
+        return delegate.getEndpoint(uri, parameters);
+    }
+
+    @Override
+    public <T extends Endpoint> T getEndpoint(String name, Class<T> endpointType) {
+        return delegate.getEndpoint(name, endpointType);
+    }
+
+    @Override
+    public Collection<Endpoint> getEndpoints() {
+        return delegate.getEndpoints();
+    }
+
+    @Override
+    @Deprecated
+    public Map<String, Endpoint> getEndpointMap() {
+        return delegate.getEndpointMap();
+    }
+
+    @Override
+    public Endpoint hasEndpoint(String uri) {
+        return delegate.hasEndpoint(uri);
+    }
+
+    @Override
+    public Endpoint addEndpoint(String uri, Endpoint endpoint) throws Exception {
+        return delegate.addEndpoint(uri, endpoint);
+    }
+
+    @Override
+    public void removeEndpoint(Endpoint endpoint) throws Exception {
+        delegate.removeEndpoint(endpoint);
+    }
+
+    @Override
+    public Collection<Endpoint> removeEndpoints(String pattern) throws Exception {
+        return delegate.removeEndpoints(pattern);
+    }
+
+    @Override
+    public GlobalEndpointConfiguration getGlobalEndpointConfiguration() {
+        return delegate.getGlobalEndpointConfiguration();
+    }
+
+    @Override
+    public void setRouteController(RouteController routeController) {
+        delegate.setRouteController(routeController);
+    }
+
+    @Override
+    public RouteController getRouteController() {
+        return delegate.getRouteController();
+    }
+
+    @Override
+    public List<Route> getRoutes() {
+        return delegate.getRoutes();
+    }
+
+    @Override
+    public int getRoutesSize() {
+        return delegate.getRoutesSize();
+    }
+
+    @Override
+    public Route getRoute(String id) {
+        return delegate.getRoute(id);
+    }
+
+    @Override
+    public Processor getProcessor(String id) {
+        return delegate.getProcessor(id);
+    }
+
+    @Override
+    public <T extends Processor> T getProcessor(String id, Class<T> type) {
+        return delegate.getProcessor(id, type);
+    }
+
+    @Override
+    public void addRoutes(RoutesBuilder builder) throws Exception {
+        delegate.addRoutes(builder);
+    }
+
+    @Override
+    public boolean removeRoute(String routeId) throws Exception {
+        return delegate.removeRoute(routeId);
+    }
+
+    @Override
+    public void addRoutePolicyFactory(RoutePolicyFactory routePolicyFactory) {
+        delegate.addRoutePolicyFactory(routePolicyFactory);
+    }
+
+    @Override
+    public List<RoutePolicyFactory> getRoutePolicyFactories() {
+        return delegate.getRoutePolicyFactories();
+    }
+
+    @Override
+    public void setRestConfiguration(RestConfiguration restConfiguration) {
+        delegate.setRestConfiguration(restConfiguration);
+    }
+
+    @Override
+    public RestConfiguration getRestConfiguration() {
+        return delegate.getRestConfiguration();
+    }
+
+    @Override
+    @Deprecated
+    public void addRestConfiguration(RestConfiguration restConfiguration) {
+        delegate.addRestConfiguration(restConfiguration);
+    }
+
+    @Override
+    public RestConfiguration getRestConfiguration(String component, boolean defaultIfNotFound) {
+        return delegate.getRestConfiguration(component, defaultIfNotFound);
+    }
+
+    @Override
+    @Deprecated
+    public Collection<RestConfiguration> getRestConfigurations() {
+        return delegate.getRestConfigurations();
+    }
+
+    @Override
+    public RestRegistry getRestRegistry() {
+        return delegate.getRestRegistry();
+    }
+
+    @Override
+    public void setRestRegistry(RestRegistry restRegistry) {
+        delegate.setRestRegistry(restRegistry);
+    }
+
+    @Override
+    public TypeConverter getTypeConverter() {
+        return delegate.getTypeConverter();
+    }
+
+    @Override
+    public TypeConverterRegistry getTypeConverterRegistry() {
+        return delegate.getTypeConverterRegistry();
+    }
+
+    @Override
+    public void setTypeConverterRegistry(TypeConverterRegistry typeConverterRegistry) {
+        delegate.setTypeConverterRegistry(typeConverterRegistry);
+    }
+
+    @Override
+    public Registry getRegistry() {
+        return delegate.getRegistry();
+    }
+
+    @Override
+    public <T> T getRegistry(Class<T> type) {
+        return delegate.getRegistry(type);
+    }
+
+    @Override
+    public Injector getInjector() {
+        return delegate.getInjector();
+    }
+
+    @Override
+    public void setInjector(Injector injector) {
+        delegate.setInjector(injector);
+    }
+
+    @Override
+    public List<LifecycleStrategy> getLifecycleStrategies() {
+        return delegate.getLifecycleStrategies();
+    }
+
+    @Override
+    public void addLifecycleStrategy(LifecycleStrategy lifecycleStrategy) {
+        delegate.addLifecycleStrategy(lifecycleStrategy);
+    }
+
+    @Override
+    public Language resolveLanguage(String language) throws NoSuchLanguageException {
+        return delegate.resolveLanguage(language);
+    }
+
+    @Override
+    public String resolvePropertyPlaceholders(String text) {
+        return delegate.resolvePropertyPlaceholders(text);
+    }
+
+    @Override
+    public PropertiesComponent getPropertiesComponent() {
+        return delegate.getPropertiesComponent();
+    }
+
+    @Override
+    public void setPropertiesComponent(PropertiesComponent propertiesComponent) {
+        delegate.setPropertiesComponent(propertiesComponent);
+    }
+
+    @Override
+    @Deprecated
+    public List<String> getLanguageNames() {
+        return delegate.getLanguageNames();
+    }
+
+    @Override
+    public ProducerTemplate createProducerTemplate() {
+        return delegate.createProducerTemplate();
+    }
+
+    @Override
+    public ProducerTemplate createProducerTemplate(int maximumCacheSize) {
+        return delegate.createProducerTemplate(maximumCacheSize);
+    }
+
+    @Override
+    public FluentProducerTemplate createFluentProducerTemplate() {
+        return delegate.createFluentProducerTemplate();
+    }
+
+    @Override
+    public FluentProducerTemplate createFluentProducerTemplate(int maximumCacheSize) {
+        return delegate.createFluentProducerTemplate(maximumCacheSize);
+    }
+
+    @Override
+    public ConsumerTemplate createConsumerTemplate() {
+        return delegate.createConsumerTemplate();
+    }
+
+    @Override
+    public ConsumerTemplate createConsumerTemplate(int maximumCacheSize) {
+        return delegate.createConsumerTemplate(maximumCacheSize);
+    }
+
+    @Override
+    public DataFormat resolveDataFormat(String name) {
+        return delegate.resolveDataFormat(name);
+    }
+
+    @Override
+    public DataFormat createDataFormat(String name) {
+        return delegate.createDataFormat(name);
+    }
+
+    @Override
+    public Transformer resolveTransformer(String model) {
+        return delegate.resolveTransformer(model);
+    }
+
+    @Override
+    public Transformer resolveTransformer(DataType from, DataType to) {
+        return delegate.resolveTransformer(from, to);
+    }
+
+    @Override
+    public TransformerRegistry getTransformerRegistry() {
+        return delegate.getTransformerRegistry();
+    }
+
+    @Override
+    public Validator resolveValidator(DataType type) {
+        return delegate.resolveValidator(type);
+    }
+
+    @Override
+    public ValidatorRegistry getValidatorRegistry() {
+        return delegate.getValidatorRegistry();
+    }
+
+    @Override
+    public void setGlobalOptions(Map<String, String> globalOptions) {
+        delegate.setGlobalOptions(globalOptions);
+    }
+
+    @Override
+    public Map<String, String> getGlobalOptions() {
+        return delegate.getGlobalOptions();
+    }
+
+    @Override
+    public String getGlobalOption(String key) {
+        return delegate.getGlobalOption(key);
+    }
+
+    @Override
+    public ClassResolver getClassResolver() {
+        return delegate.getClassResolver();
+    }
+
+    @Override
+    public void setClassResolver(ClassResolver resolver) {
+        delegate.setClassResolver(resolver);
+    }
+
+    @Override
+    public ManagementStrategy getManagementStrategy() {
+        return delegate.getManagementStrategy();
+    }
+
+    @Override
+    public void setManagementStrategy(ManagementStrategy strategy) {
+        delegate.setManagementStrategy(strategy);
+    }
+
+    @Override
+    public void disableJMX() throws IllegalStateException {
+        delegate.disableJMX();
+    }
+
+    @Override
+    public InflightRepository getInflightRepository() {
+        return delegate.getInflightRepository();
+    }
+
+    @Override
+    public void setInflightRepository(InflightRepository repository) {
+        delegate.setInflightRepository(repository);
+    }
+
+    @Override
+    public ClassLoader getApplicationContextClassLoader() {
+        return delegate.getApplicationContextClassLoader();
+    }
+
+    @Override
+    public void setApplicationContextClassLoader(ClassLoader classLoader) {
+        delegate.setApplicationContextClassLoader(classLoader);
+    }
+
+    @Override
+    public ShutdownStrategy getShutdownStrategy() {
+        return delegate.getShutdownStrategy();
+    }
+
+    @Override
+    public void setShutdownStrategy(ShutdownStrategy shutdownStrategy) {
+        delegate.setShutdownStrategy(shutdownStrategy);
+    }
+
+    @Override
+    public ExecutorServiceManager getExecutorServiceManager() {
+        return delegate.getExecutorServiceManager();
+    }
+
+    @Override
+    public void setExecutorServiceManager(ExecutorServiceManager executorServiceManager) {
+        delegate.setExecutorServiceManager(executorServiceManager);
+    }
+
+    @Override
+    public MessageHistoryFactory getMessageHistoryFactory() {
+        return delegate.getMessageHistoryFactory();
+    }
+
+    @Override
+    public void setMessageHistoryFactory(MessageHistoryFactory messageHistoryFactory) {
+        delegate.setMessageHistoryFactory(messageHistoryFactory);
+    }
+
+    @Override
+    public Debugger getDebugger() {
+        return delegate.getDebugger();
+    }
+
+    @Override
+    public void setDebugger(Debugger debugger) {
+        delegate.setDebugger(debugger);
+    }
+
+    @Override
+    public Tracer getTracer() {
+        return delegate.getTracer();
+    }
+
+    @Override
+    public void setTracer(Tracer tracer) {
+        delegate.setTracer(tracer);
+    }
+
+    @Override
+    public UuidGenerator getUuidGenerator() {
+        return delegate.getUuidGenerator();
+    }
+
+    @Override
+    public void setUuidGenerator(UuidGenerator uuidGenerator) {
+        delegate.setUuidGenerator(uuidGenerator);
+    }
+
+    @Override
+    public Boolean isLoadTypeConverters() {
+        return delegate.isLoadTypeConverters();
+    }
+
+    @Override
+    public void setLoadTypeConverters(Boolean loadTypeConverters) {
+        delegate.setLoadTypeConverters(loadTypeConverters);
+    }
+
+    @Override
+    public Boolean isTypeConverterStatisticsEnabled() {
+        return delegate.isTypeConverterStatisticsEnabled();
+    }
+
+    @Override
+    public void setTypeConverterStatisticsEnabled(Boolean typeConverterStatisticsEnabled) {
+        delegate.setTypeConverterStatisticsEnabled(typeConverterStatisticsEnabled);
+    }
+
+    @Override
+    public Boolean isUseMDCLogging() {
+        return delegate.isUseMDCLogging();
+    }
+
+    @Override
+    public void setUseMDCLogging(Boolean useMDCLogging) {
+        delegate.setUseMDCLogging(useMDCLogging);
+    }
+
+    @Override
+    public String getMDCLoggingKeysPattern() {
+        return delegate.getMDCLoggingKeysPattern();
+    }
+
+    @Override
+    public void setMDCLoggingKeysPattern(String pattern) {
+        delegate.setMDCLoggingKeysPattern(pattern);
+    }
+
+    @Override
+    public Boolean isUseDataType() {
+        return delegate.isUseDataType();
+    }
+
+    @Override
+    public void setUseDataType(Boolean useDataType) {
+        delegate.setUseDataType(useDataType);
+    }
+
+    @Override
+    public Boolean isUseBreadcrumb() {
+        return delegate.isUseBreadcrumb();
+    }
+
+    @Override
+    public void setUseBreadcrumb(Boolean useBreadcrumb) {
+        delegate.setUseBreadcrumb(useBreadcrumb);
+    }
+
+    @Override
+    public StreamCachingStrategy getStreamCachingStrategy() {
+        return delegate.getStreamCachingStrategy();
+    }
+
+    @Override
+    public void setStreamCachingStrategy(StreamCachingStrategy streamCachingStrategy) {
+        delegate.setStreamCachingStrategy(streamCachingStrategy);
+    }
+
+    @Override
+    public RuntimeEndpointRegistry getRuntimeEndpointRegistry() {
+        return delegate.getRuntimeEndpointRegistry();
+    }
+
+    @Override
+    public void setRuntimeEndpointRegistry(RuntimeEndpointRegistry runtimeEndpointRegistry) {
+        delegate.setRuntimeEndpointRegistry(runtimeEndpointRegistry);
+    }
+
+    @Override
+    public void setSSLContextParameters(SSLContextParameters sslContextParameters) {
+        delegate.setSSLContextParameters(sslContextParameters);
+    }
+
+    @Override
+    public SSLContextParameters getSSLContextParameters() {
+        return delegate.getSSLContextParameters();
+    }
+
+    @Override
+    public void setStreamCaching(Boolean cache) {
+        delegate.setStreamCaching(cache);
+    }
+
+    @Override
+    public Boolean isStreamCaching() {
+        return delegate.isStreamCaching();
+    }
+
+    @Override
+    public void setTracing(Boolean tracing) {
+        delegate.setTracing(tracing);
+    }
+
+    @Override
+    public Boolean isTracing() {
+        return delegate.isTracing();
+    }
+
+    @Override
+    public String getTracingPattern() {
+        return delegate.getTracingPattern();
+    }
+
+    @Override
+    public void setTracingPattern(String tracePattern) {
+        delegate.setTracingPattern(tracePattern);
+    }
+
+    @Override
+    public void setBacklogTracing(Boolean backlogTrace) {
+        delegate.setBacklogTracing(backlogTrace);
+    }
+
+    @Override
+    public Boolean isBacklogTracing() {
+        return delegate.isBacklogTracing();
+    }
+
+    @Override
+    public void setDebugging(Boolean debugging) {
+        delegate.setDebugging(debugging);
+    }
+
+    @Override
+    public Boolean isDebugging() {
+        return delegate.isDebugging();
+    }
+
+    @Override
+    public void setMessageHistory(Boolean messageHistory) {
+        delegate.setMessageHistory(messageHistory);
+    }
+
+    @Override
+    public Boolean isMessageHistory() {
+        return delegate.isMessageHistory();
+    }
+
+    @Override
+    public void setLogMask(Boolean logMask) {
+        delegate.setLogMask(logMask);
+    }
+
+    @Override
+    public Boolean isLogMask() {
+        return delegate.isLogMask();
+    }
+
+    @Override
+    public void setLogExhaustedMessageBody(Boolean logExhaustedMessageBody) {
+        delegate.setLogExhaustedMessageBody(logExhaustedMessageBody);
+    }
+
+    @Override
+    public Boolean isLogExhaustedMessageBody() {
+        return delegate.isLogExhaustedMessageBody();
+    }
+
+    @Override
+    public void setDelayer(Long delay) {
+        delegate.setDelayer(delay);
+    }
+
+    @Override
+    public Long getDelayer() {
+        return delegate.getDelayer();
+    }
+
+    @Override
+    public void setAutoStartup(Boolean autoStartup) {
+        delegate.setAutoStartup(autoStartup);
+    }
+
+    @Override
+    public Boolean isAutoStartup() {
+        return delegate.isAutoStartup();
+    }
+
+    @Override
+    public void setShutdownRoute(ShutdownRoute shutdownRoute) {
+        delegate.setShutdownRoute(shutdownRoute);
+    }
+
+    @Override
+    public ShutdownRoute getShutdownRoute() {
+        return delegate.getShutdownRoute();
+    }
+
+    @Override
+    public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) {
+        delegate.setShutdownRunningTask(shutdownRunningTask);
+    }
+
+    @Override
+    public ShutdownRunningTask getShutdownRunningTask() {
+        return delegate.getShutdownRunningTask();
+    }
+
+    @Override
+    public void setAllowUseOriginalMessage(Boolean allowUseOriginalMessage) {
+        delegate.setAllowUseOriginalMessage(allowUseOriginalMessage);
+    }
+
+    @Override
+    public Boolean isAllowUseOriginalMessage() {
+        return delegate.isAllowUseOriginalMessage();
+    }
+
+    @Override
+    public Boolean isCaseInsensitiveHeaders() {
+        return delegate.isCaseInsensitiveHeaders();
+    }
+
+    @Override
+    public void setCaseInsensitiveHeaders(Boolean caseInsensitiveHeaders) {
+        delegate.setCaseInsensitiveHeaders(caseInsensitiveHeaders);
+    }
+
+    //
+    // ExtendedCamelContext
+    //
+
+    protected ExtendedCamelContext getExtendedCamelContext() {
+        return delegate.adapt(ExtendedCamelContext.class);
+    }
+
+    @Override
+    public void setName(String name) {
+        getExtendedCamelContext().setName(name);
+    }
+
+    @Override
+    public void setRegistry(Registry registry) {
+        getExtendedCamelContext().setRegistry(registry);
+    }
+
+    @Override
+    public void setupRoutes(boolean done) {
+        getExtendedCamelContext().setupRoutes(done);
+    }
+
+    @Override
+    public boolean isSetupRoutes() {
+        return getExtendedCamelContext().isSetupRoutes();
+    }
+
+    @Override
+    public void registerEndpointCallback(EndpointStrategy strategy) {
+        getExtendedCamelContext().registerEndpointCallback(strategy);
+    }
+
+    @Override
+    public Endpoint getPrototypeEndpoint(String uri) {
+        return getExtendedCamelContext().getPrototypeEndpoint(uri);
+    }
+
+    @Override
+    public Endpoint getPrototypeEndpoint(NormalizedEndpointUri uri) {
+        return getExtendedCamelContext().getPrototypeEndpoint(uri);
+    }
+
+    @Override
+    public Endpoint hasEndpoint(NormalizedEndpointUri uri) {
+        return getExtendedCamelContext().hasEndpoint(uri);
+    }
+
+    @Override
+    public Endpoint getEndpoint(NormalizedEndpointUri uri) {
+        return getExtendedCamelContext().getEndpoint(uri);
+    }
+
+    @Override
+    public Endpoint getEndpoint(NormalizedEndpointUri uri, Map<String, Object> parameters) {
+        return getExtendedCamelContext().getEndpoint(uri, parameters);
+    }
+
+    @Override
+    public NormalizedEndpointUri normalizeUri(String uri) {
+        return getExtendedCamelContext().normalizeUri(uri);
+    }
+
+    @Override
+    public List<RouteStartupOrder> getRouteStartupOrder() {
+        return getExtendedCamelContext().getRouteStartupOrder();
+    }
+
+    @Override
+    public CamelBeanPostProcessor getBeanPostProcessor() {
+        return getExtendedCamelContext().getBeanPostProcessor();
+    }
+
+    @Override
+    public ManagementMBeanAssembler getManagementMBeanAssembler() {
+        return getExtendedCamelContext().getManagementMBeanAssembler();
+    }
+
+    @Override
+    public AsyncProcessor createMulticast(Collection<Processor> processors, ExecutorService executor, boolean shutdownExecutorService) {
+        return getExtendedCamelContext().createMulticast(processors, executor, shutdownExecutorService);
+    }
+
+    @Override
+    public ErrorHandlerFactory getErrorHandlerFactory() {
+        return getExtendedCamelContext().getErrorHandlerFactory();
+    }
+
+    @Override
+    public void setErrorHandlerFactory(ErrorHandlerFactory errorHandlerFactory) {
+        getExtendedCamelContext().setErrorHandlerFactory(errorHandlerFactory);
+    }
+
+    @Override
+    public void setNodeIdFactory(NodeIdFactory factory) {
+        getExtendedCamelContext().setNodeIdFactory(factory);
+    }
+
+    @Override
+    public NodeIdFactory getNodeIdFactory() {
+        return getExtendedCamelContext().getNodeIdFactory();
+    }
+
+    @Override
+    public ComponentResolver getComponentResolver() {
+        return getExtendedCamelContext().getComponentResolver();
+    }
+
+    @Override
+    public void setComponentResolver(ComponentResolver componentResolver) {
+        getExtendedCamelContext().setComponentResolver(componentResolver);
+    }
+
+    @Override
+    public LanguageResolver getLanguageResolver() {
+        return getExtendedCamelContext().getLanguageResolver();
+    }
+
+    @Override
+    public void setLanguageResolver(LanguageResolver languageResolver) {
+        getExtendedCamelContext().setLanguageResolver(languageResolver);
+    }
+
+    @Override
+    public DataFormatResolver getDataFormatResolver() {
+        return getExtendedCamelContext().getDataFormatResolver();
+    }
+
+    @Override
+    public void setDataFormatResolver(DataFormatResolver dataFormatResolver) {
+        getExtendedCamelContext().setDataFormatResolver(dataFormatResolver);
+    }
+
+    @Override
+    public PackageScanClassResolver getPackageScanClassResolver() {
+        return getExtendedCamelContext().getPackageScanClassResolver();
+    }
+
+    @Override
+    public void setPackageScanClassResolver(PackageScanClassResolver resolver) {
+        getExtendedCamelContext().setPackageScanClassResolver(resolver);
+    }
+
+    @Override
+    public PackageScanResourceResolver getPackageScanResourceResolver() {
+        return getExtendedCamelContext().getPackageScanResourceResolver();
+    }
+
+    @Override
+    public void setPackageScanResourceResolver(PackageScanResourceResolver resolver) {
+        getExtendedCamelContext().setPackageScanResourceResolver(resolver);
+    }
+
+    @Override
+    public FactoryFinder getDefaultFactoryFinder() {
+        return getExtendedCamelContext().getDefaultFactoryFinder();
+    }
+
+    @Override
+    public FactoryFinder getFactoryFinder(String path) {
+        return getExtendedCamelContext().getFactoryFinder(path);
+    }
+
+    @Override
+    public void setFactoryFinderResolver(FactoryFinderResolver resolver) {
+        getExtendedCamelContext().setFactoryFinderResolver(resolver);
+    }
+
+    @Override
+    public FactoryFinderResolver getFactoryFinderResolver() {
+        return getExtendedCamelContext().getFactoryFinderResolver();
+    }
+
+    @Override
+    public ProcessorFactory getProcessorFactory() {
+        return getExtendedCamelContext().getProcessorFactory();
+    }
+
+    @Override
+    public void setProcessorFactory(ProcessorFactory processorFactory) {
+        getExtendedCamelContext().setProcessorFactory(processorFactory);
+    }
+
+    @Override
+    public ModelJAXBContextFactory getModelJAXBContextFactory() {
+        return getExtendedCamelContext().getModelJAXBContextFactory();
+    }
+
+    @Override
+    public void setModelJAXBContextFactory(ModelJAXBContextFactory modelJAXBContextFactory) {
+        getExtendedCamelContext().setModelJAXBContextFactory(modelJAXBContextFactory);
+    }
+
+    @Override
+    public DeferServiceFactory getDeferServiceFactory() {
+        return getExtendedCamelContext().getDeferServiceFactory();
+    }
+
+    @Override
+    public UnitOfWorkFactory getUnitOfWorkFactory() {
+        return getExtendedCamelContext().getUnitOfWorkFactory();
+    }
+
+    @Override
+    public void setUnitOfWorkFactory(UnitOfWorkFactory unitOfWorkFactory) {
+        getExtendedCamelContext().setUnitOfWorkFactory(unitOfWorkFactory);
+    }
+
+    @Override
+    public AnnotationBasedProcessorFactory getAnnotationBasedProcessorFactory() {
+        return getExtendedCamelContext().getAnnotationBasedProcessorFactory();
+    }
+
+    @Override
+    public BeanProxyFactory getBeanProxyFactory() {
+        return getExtendedCamelContext().getBeanProxyFactory();
+    }
+
+    @Override
+    public BeanProcessorFactory getBeanProcessorFactory() {
+        return getExtendedCamelContext().getBeanProcessorFactory();
+    }
+
+    @Override
+    public ScheduledExecutorService getErrorHandlerExecutorService() {
+        return getExtendedCamelContext().getErrorHandlerExecutorService();
+    }
+
+    @Override
+    public void addInterceptStrategy(InterceptStrategy interceptStrategy) {
+        getExtendedCamelContext().addInterceptStrategy(interceptStrategy);
+    }
+
+    @Override
+    public List<InterceptStrategy> getInterceptStrategies() {
+        return getExtendedCamelContext().getInterceptStrategies();
+    }
+
+    @Override
+    public void setupManagement(Map<String, Object> options) {
+        getExtendedCamelContext().setupManagement(options);
+    }
+
+    @Override
+    public Set<LogListener> getLogListeners() {
+        return getExtendedCamelContext().getLogListeners();
+    }
+
+    @Override
+    public void addLogListener(LogListener listener) {
+        getExtendedCamelContext().addLogListener(listener);
+    }
+
+    @Override
+    public AsyncProcessorAwaitManager getAsyncProcessorAwaitManager() {
+        return getExtendedCamelContext().getAsyncProcessorAwaitManager();
+    }
+
+    @Override
+    public void setAsyncProcessorAwaitManager(AsyncProcessorAwaitManager manager) {
+        getExtendedCamelContext().setAsyncProcessorAwaitManager(manager);
+    }
+
+    @Override
+    public BeanIntrospection getBeanIntrospection() {
+        return getExtendedCamelContext().getBeanIntrospection();
+    }
+
+    @Override
+    public void setBeanIntrospection(BeanIntrospection beanIntrospection) {
+        getExtendedCamelContext().setBeanIntrospection(beanIntrospection);
+    }
+
+    @Override
+    public HeadersMapFactory getHeadersMapFactory() {
+        return getExtendedCamelContext().getHeadersMapFactory();
+    }
+
+    @Override
+    public void setHeadersMapFactory(HeadersMapFactory factory) {
+        getExtendedCamelContext().setHeadersMapFactory(factory);
+    }
+
+    @Override
+    public ReactiveExecutor getReactiveExecutor() {
+        return getExtendedCamelContext().getReactiveExecutor();
+    }
+
+    @Override
+    public void setReactiveExecutor(ReactiveExecutor reactiveExecutor) {
+        getExtendedCamelContext().setReactiveExecutor(reactiveExecutor);
+    }
+
+    @Override
+    public boolean isEventNotificationApplicable() {
+        return getExtendedCamelContext().isEventNotificationApplicable();
+    }
+
+    @Override
+    public void setEventNotificationApplicable(boolean eventNotificationApplicable) {
+        getExtendedCamelContext().setEventNotificationApplicable(eventNotificationApplicable);
+    }
+
+    @Override
+    public void setXMLRoutesDefinitionLoader(XMLRoutesDefinitionLoader xmlRoutesDefinitionLoader) {
+        getExtendedCamelContext().setXMLRoutesDefinitionLoader(xmlRoutesDefinitionLoader);
+    }
+
+    @Override
+    public XMLRoutesDefinitionLoader getXMLRoutesDefinitionLoader() {
+        return getExtendedCamelContext().getXMLRoutesDefinitionLoader();
+    }
+
+    @Override
+    public void setModelToXMLDumper(ModelToXMLDumper modelToXMLDumper) {
+        getExtendedCamelContext().setModelToXMLDumper(modelToXMLDumper);
+    }
+
+    @Override
+    public ModelToXMLDumper getModelToXMLDumper() {
+        return getExtendedCamelContext().getModelToXMLDumper();
+    }
+
+    @Override
+    public RuntimeCamelCatalog getRuntimeCamelCatalog() {
+        return getExtendedCamelContext().getRuntimeCamelCatalog();
+    }
+
+    @Override
+    public void setRuntimeCamelCatalog(RuntimeCamelCatalog runtimeCamelCatalog) {
+        getExtendedCamelContext().setRuntimeCamelCatalog(runtimeCamelCatalog);
+    }
+
+    @Override
+    public ConfigurerResolver getConfigurerResolver() {
+        return getExtendedCamelContext().getConfigurerResolver();
+    }
+
+    @Override
+    public void setConfigurerResolver(ConfigurerResolver configurerResolver) {
+        getExtendedCamelContext().setConfigurerResolver(configurerResolver);
+    }
+
+    @Override
+    public void setAllowAddingNewRoutes(boolean allowAddingNewRoutes) {
+        getExtendedCamelContext().setAllowAddingNewRoutes(allowAddingNewRoutes);
+    }
+
+    @Override
+    public boolean isAllowAddingNewRoutes() {
+        return getExtendedCamelContext().isAllowAddingNewRoutes();
+    }
+
+    @Override
+    @Experimental
+    public void setClearModelReferences(boolean clearModelReferences) {
+        getExtendedCamelContext().setClearModelReferences(clearModelReferences);
+    }
+
+    @Override
+    public boolean isClearModelReferences() {
+        return getExtendedCamelContext().isClearModelReferences();
+    }
+
+    @Override
+    public RouteController getInternalRouteController() {
+        return getExtendedCamelContext().getInternalRouteController();
+    }
+
+    @Override
+    public void addRoute(Route route) {
+        getExtendedCamelContext().addRoute(route);
+    }
+
+    @Override
+    public void removeRoute(Route route) {
+        getExtendedCamelContext().removeRoute(route);
+    }
+
+    //
+    // CatalogCamelContext
+    //
+
+    protected CatalogCamelContext getCatalogCamelContext() {
+        return delegate.adapt(CatalogCamelContext.class);
+    }
+
+    @Override
+    public String getComponentParameterJsonSchema(String componentName) throws IOException {
+        return getCatalogCamelContext().getComponentParameterJsonSchema(componentName);
+    }
+
+    @Override
+    public String getDataFormatParameterJsonSchema(String dataFormatName) throws IOException {
+        return getCatalogCamelContext().getDataFormatParameterJsonSchema(dataFormatName);
+    }
+
+    @Override
+    public String getLanguageParameterJsonSchema(String languageName) throws IOException {
+        return getCatalogCamelContext().getLanguageParameterJsonSchema(languageName);
+    }
+
+    @Override
+    public String getEipParameterJsonSchema(String eipName) throws IOException {
+        return getCatalogCamelContext().getEipParameterJsonSchema(eipName);
+    }
+
+    //
+    // ModelCamelContext
+    //
+
+    protected ModelCamelContext getModelCamelContext() {
+        return delegate.adapt(ModelCamelContext.class);
+    }
+
+    @Override
+    public List<RouteDefinition> getRouteDefinitions() {
+        return getModelCamelContext().getRouteDefinitions();
+    }
+
+    @Override
+    public RouteDefinition getRouteDefinition(String id) {
+        return getModelCamelContext().getRouteDefinition(id);
+    }
+
+    @Override
+    public void addRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
+        getModelCamelContext().addRouteDefinitions(routeDefinitions);
+    }
+
+    @Override
+    public void addRouteDefinition(RouteDefinition routeDefinition) throws Exception {
+        getModelCamelContext().addRouteDefinition(routeDefinition);
+    }
+
+    @Override
+    public void removeRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
+        getModelCamelContext().removeRouteDefinitions(routeDefinitions);
+    }
+
+    @Override
+    public void removeRouteDefinition(RouteDefinition routeDefinition) throws Exception {
+        getModelCamelContext().removeRouteDefinition(routeDefinition);
+    }
+
+    @Override
+    public List<RestDefinition> getRestDefinitions() {
+        return getModelCamelContext().getRestDefinitions();
+    }
+
+    @Override
+    public void addRestDefinitions(Collection<RestDefinition> restDefinitions, boolean addToRoutes) throws Exception {
+        getModelCamelContext().addRestDefinitions(restDefinitions, addToRoutes);
+    }
+
+    @Override
+    public void setDataFormats(Map<String, DataFormatDefinition> dataFormats) {
+        getModelCamelContext().setDataFormats(dataFormats);
+    }
+
+    @Override
+    public Map<String, DataFormatDefinition> getDataFormats() {
+        return getModelCamelContext().getDataFormats();
+    }
+
+    @Override
+    public DataFormatDefinition resolveDataFormatDefinition(String name) {
+        return getModelCamelContext().resolveDataFormatDefinition(name);
+    }
+
+    @Override
+    public ProcessorDefinition<?> getProcessorDefinition(String id) {
+        return getModelCamelContext().getProcessorDefinition(id);
+    }
+
+    @Override
+    public <T extends ProcessorDefinition<T>> T getProcessorDefinition(String id, Class<T> type) {
+        return getModelCamelContext().getProcessorDefinition(id, type);
+    }
+
+    @Override
+    public void setValidators(List<ValidatorDefinition> validators) {
+        getModelCamelContext().setValidators(validators);
+    }
+
+    @Override
+    public HystrixConfigurationDefinition getHystrixConfiguration(String id) {
+        return getModelCamelContext().getHystrixConfiguration(id);
+    }
+
+    @Override
+    public void setHystrixConfiguration(HystrixConfigurationDefinition configuration) {
+        getModelCamelContext().setHystrixConfiguration(configuration);
+    }
+
+    @Override
+    public void setHystrixConfigurations(List<HystrixConfigurationDefinition> configurations) {
+        getModelCamelContext().setHystrixConfigurations(configurations);
+    }
+
+    @Override
+    public void addHystrixConfiguration(String id, HystrixConfigurationDefinition configuration) {
+        getModelCamelContext().addHystrixConfiguration(id, configuration);
+    }
+
+    @Override
+    public Resilience4jConfigurationDefinition getResilience4jConfiguration(String id) {
+        return getModelCamelContext().getResilience4jConfiguration(id);
+    }
+
+    @Override
+    public void setResilience4jConfiguration(Resilience4jConfigurationDefinition configuration) {
+        getModelCamelContext().setResilience4jConfiguration(configuration);
+    }
+
+    @Override
+    public void setResilience4jConfigurations(List<Resilience4jConfigurationDefinition> configurations) {
+        getModelCamelContext().setResilience4jConfigurations(configurations);
+    }
+
+    @Override
+    public void addResilience4jConfiguration(String id, Resilience4jConfigurationDefinition configuration) {
+        getModelCamelContext().addResilience4jConfiguration(id, configuration);
+    }
+
+    @Override
+    public List<ValidatorDefinition> getValidators() {
+        return getModelCamelContext().getValidators();
+    }
+
+    @Override
+    public void setTransformers(List<TransformerDefinition> transformers) {
+        getModelCamelContext().setTransformers(transformers);
+    }
+
+    @Override
+    public List<TransformerDefinition> getTransformers() {
+        return getModelCamelContext().getTransformers();
+    }
+
+    @Override
+    public ServiceCallConfigurationDefinition getServiceCallConfiguration(String serviceName) {
+        return getModelCamelContext().getServiceCallConfiguration(serviceName);
+    }
+
+    @Override
+    public void setServiceCallConfiguration(ServiceCallConfigurationDefinition configuration) {
+        getModelCamelContext().setServiceCallConfiguration(configuration);
+    }
+
+    @Override
+    public void setServiceCallConfigurations(List<ServiceCallConfigurationDefinition> configurations) {
+        getModelCamelContext().setServiceCallConfigurations(configurations);
+    }
+
+    @Override
+    public void addServiceCallConfiguration(String serviceName, ServiceCallConfigurationDefinition configuration) {
+        getModelCamelContext().addServiceCallConfiguration(serviceName, configuration);
+    }
+
+    @Override
+    public void startRouteDefinitions() throws Exception {
+        getModelCamelContext().startRouteDefinitions();
+    }
+
+    @Override
+    public void startRouteDefinitions(List<RouteDefinition> routeDefinitions) throws Exception {
+        getModelCamelContext().startRouteDefinitions(routeDefinitions);
+    }
+
+    @Override
+    public void setRouteFilterPattern(String include, String exclude) {
+        getModelCamelContext().setRouteFilterPattern(include, exclude);
+    }
+
+    @Override
+    public void setRouteFilter(Function<RouteDefinition, Boolean> filter) {
+        getModelCamelContext().setRouteFilter(filter);
+    }
+
+    @Override
+    public Function<RouteDefinition, Boolean> getRouteFilter() {
+        return getModelCamelContext().getRouteFilter();
+    }
+
+    //
+    // Immutable
+    //
+
+    public void makeImmutable() {
+        if (delegate instanceof RuntimeImmutableCamelContext) {
+            throw new IllegalStateException();
+        }
+        delegate.setAutoStartup(false);
+        delegate.start();
+        delegate = new RuntimeImmutableCamelContext(this, delegate);
+    }
+
+    public void startImmutable() {
+        delegate.start();
+    }
+
+}
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/RuntimeImmutableCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/RuntimeImmutableCamelContext.java
new file mode 100644
index 0000000..fbabf55
--- /dev/null
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/RuntimeImmutableCamelContext.java
@@ -0,0 +1,1820 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.impl.lw;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import org.apache.camel.AsyncProcessor;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.CatalogCamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.ConsumerTemplate;
+import org.apache.camel.Endpoint;
+import org.apache.camel.ErrorHandlerFactory;
+import org.apache.camel.ExchangeConstantProvider;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.FluentProducerTemplate;
+import org.apache.camel.GlobalEndpointConfiguration;
+import org.apache.camel.IsSingleton;
+import org.apache.camel.NoSuchEndpointException;
+import org.apache.camel.NoSuchLanguageException;
+import org.apache.camel.Processor;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.ResolveEndpointFailedException;
+import org.apache.camel.Route;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.Service;
+import org.apache.camel.ServiceStatus;
+import org.apache.camel.ShutdownRoute;
+import org.apache.camel.ShutdownRunningTask;
+import org.apache.camel.StartupListener;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.ValueHolder;
+import org.apache.camel.catalog.RuntimeCamelCatalog;
+import org.apache.camel.impl.converter.CoreTypeConverterRegistry;
+import org.apache.camel.impl.engine.DefaultComponentResolver;
+import org.apache.camel.impl.engine.DefaultDataFormatResolver;
+import org.apache.camel.impl.engine.DefaultLanguageResolver;
+import org.apache.camel.impl.engine.EndpointKey;
+import org.apache.camel.spi.AnnotationBasedProcessorFactory;
+import org.apache.camel.spi.AsyncProcessorAwaitManager;
+import org.apache.camel.spi.BeanIntrospection;
+import org.apache.camel.spi.BeanProcessorFactory;
+import org.apache.camel.spi.BeanProxyFactory;
+import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.spi.CamelContextNameStrategy;
+import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.spi.ComponentResolver;
+import org.apache.camel.spi.ConfigurerResolver;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataFormatResolver;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Debugger;
+import org.apache.camel.spi.DeferServiceFactory;
+import org.apache.camel.spi.EndpointRegistry;
+import org.apache.camel.spi.EndpointStrategy;
+import org.apache.camel.spi.ExecutorServiceManager;
+import org.apache.camel.spi.FactoryFinder;
+import org.apache.camel.spi.FactoryFinderResolver;
+import org.apache.camel.spi.HeadersMapFactory;
+import org.apache.camel.spi.InflightRepository;
+import org.apache.camel.spi.Injector;
+import org.apache.camel.spi.InterceptSendToEndpoint;
+import org.apache.camel.spi.InterceptStrategy;
+import org.apache.camel.spi.Language;
+import org.apache.camel.spi.LanguageResolver;
+import org.apache.camel.spi.LifecycleStrategy;
+import org.apache.camel.spi.LogListener;
+import org.apache.camel.spi.ManagementMBeanAssembler;
+import org.apache.camel.spi.ManagementNameStrategy;
+import org.apache.camel.spi.ManagementStrategy;
+import org.apache.camel.spi.MessageHistoryFactory;
+import org.apache.camel.spi.ModelJAXBContextFactory;
+import org.apache.camel.spi.ModelToXMLDumper;
+import org.apache.camel.spi.NodeIdFactory;
+import org.apache.camel.spi.NormalizedEndpointUri;
+import org.apache.camel.spi.PackageScanClassResolver;
+import org.apache.camel.spi.PackageScanResourceResolver;
+import org.apache.camel.spi.ProcessorFactory;
+import org.apache.camel.spi.PropertiesComponent;
+import org.apache.camel.spi.ReactiveExecutor;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.spi.RestConfiguration;
+import org.apache.camel.spi.RestRegistry;
+import org.apache.camel.spi.RouteController;
+import org.apache.camel.spi.RoutePolicyFactory;
+import org.apache.camel.spi.RouteStartupOrder;
+import org.apache.camel.spi.RuntimeEndpointRegistry;
+import org.apache.camel.spi.ShutdownStrategy;
+import org.apache.camel.spi.StreamCachingStrategy;
+import org.apache.camel.spi.Tracer;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.TransformerRegistry;
+import org.apache.camel.spi.TypeConverterRegistry;
+import org.apache.camel.spi.UnitOfWorkFactory;
+import org.apache.camel.spi.UuidGenerator;
+import org.apache.camel.spi.Validator;
+import org.apache.camel.spi.ValidatorRegistry;
+import org.apache.camel.spi.XMLRoutesDefinitionLoader;
+import org.apache.camel.support.CamelContextHelper;
+import org.apache.camel.support.NormalizedUri;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.TimeUtils;
+import org.apache.camel.util.URISupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RuntimeImmutableCamelContext implements ExtendedCamelContext, CatalogCamelContext {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RuntimeImmutableCamelContext.class);
+
+    private final CamelContext reference;
+    private final Registry registry;
+    private final CoreTypeConverterRegistry typeConverter;
+    private final ModelJAXBContextFactory modelJAXBContextFactory;
+    private final RuntimeCamelCatalog camelRuntimeCatalog;
+    private final ComponentResolver componentResolver;
+    private final LanguageResolver languageResolver;
+    private final DataFormatResolver dataFormatResolver;
+    private final UuidGenerator uuidGenerator;
+    private final EndpointRegistry<EndpointKey> endpoints;
+    private final Map<String, Component> components;
+    private final Map<String, Language> languages;
+    private final PropertiesComponent propertiesComponent;
+    private final BeanIntrospection beanIntrospection;
+    private final HeadersMapFactory headersMapFactory;
+    private final ReactiveExecutor reactiveExecutor;
+    private final AsyncProcessorAwaitManager asyncProcessorAwaitManager;
+    private final ExecutorServiceManager executorServiceManager;
+    private final ShutdownStrategy shutdownStrategy;
+    private final ClassLoader applicationContextClassLoader;
+    private final UnitOfWorkFactory unitOfWorkFactory;
+    private final RouteController routeController;
+    private final InflightRepository inflightRepository;
+    private final Injector injector;
+    private final ClassResolver classResolver;
+    private final Map<String, String> globalOptions;
+    private final String name;
+    private final boolean eventNotificationApplicable;
+    private final boolean useDataType;
+    private final boolean useBreadcrumb;
+    private final String mdcLoggingKeysPattern;
+    private final boolean useMDCLogging;
+    private final List<Route> routes;
+    private final boolean messageHistory;
+    private final boolean allowUseOriginalMessage;
+    private final String version;
+    private Date startDate;
+
+    RuntimeImmutableCamelContext(CamelContext reference, CamelContext context) {
+        this.reference = reference;
+        registry = context.getRegistry();
+        typeConverter = new CoreTypeConverterRegistry(context.getTypeConverterRegistry());
+        modelJAXBContextFactory = context.adapt(ExtendedCamelContext.class).getModelJAXBContextFactory();
+        camelRuntimeCatalog = context.adapt(ExtendedCamelContext.class).getRuntimeCamelCatalog();
+        routes = Collections.unmodifiableList(context.getRoutes());
+        uuidGenerator = context.getUuidGenerator();
+        componentResolver = context.adapt(ExtendedCamelContext.class).getComponentResolver();
+        languageResolver = context.adapt(ExtendedCamelContext.class).getLanguageResolver();
+        dataFormatResolver = context.adapt(ExtendedCamelContext.class).getDataFormatResolver();
+        endpoints = (EndpointRegistry) context.getEndpointRegistry();
+        components = context.getComponentNames().stream()
+                .collect(Collectors.toMap(s -> s, s -> context.hasComponent(s)));
+        languages = context.getLanguageNames().stream()
+                .collect(Collectors.toMap(s -> s, s -> context.resolveLanguage(s)));
+        propertiesComponent = context.getPropertiesComponent();
+        beanIntrospection = context.adapt(ExtendedCamelContext.class).getBeanIntrospection();
+        headersMapFactory = context.adapt(ExtendedCamelContext.class).getHeadersMapFactory();
+        reactiveExecutor = context.adapt(ExtendedCamelContext.class).getReactiveExecutor();
+        asyncProcessorAwaitManager = context.adapt(ExtendedCamelContext.class).getAsyncProcessorAwaitManager();
+        executorServiceManager = context.getExecutorServiceManager();
+        shutdownStrategy = context.getShutdownStrategy();
+        applicationContextClassLoader = context.getApplicationContextClassLoader();
+        unitOfWorkFactory = context.adapt(ExtendedCamelContext.class).getUnitOfWorkFactory();
+        routeController = context.getRouteController();
+        inflightRepository = context.getInflightRepository();
+        globalOptions = context.getGlobalOptions();
+        injector = context.getInjector();
+        classResolver = context.getClassResolver();
+        name = context.getName();
+        eventNotificationApplicable = context.adapt(ExtendedCamelContext.class).isEventNotificationApplicable();
+        useDataType = context.isUseDataType();
+        useBreadcrumb = context.isUseBreadcrumb();
+        mdcLoggingKeysPattern = context.getMDCLoggingKeysPattern();
+        useMDCLogging = context.isUseMDCLogging();
+        messageHistory = context.isMessageHistory();
+        allowUseOriginalMessage = context.isAllowUseOriginalMessage();
+        version = context.getVersion();
+    }
+
+    public CamelContext getCamelContextReference() {
+        return reference;
+    }
+
+    //
+    // Lifecycle
+    //
+
+    @Override
+    public boolean isStarted() {
+        return false;
+    }
+
+    @Override
+    public boolean isStarting() {
+        return false;
+    }
+
+    @Override
+    public boolean isStopped() {
+        return false;
+    }
+
+    @Override
+    public boolean isStopping() {
+        return false;
+    }
+
+    @Override
+    public boolean isSuspended() {
+        return false;
+    }
+
+    @Override
+    public boolean isRunAllowed() {
+        return false;
+    }
+
+    @Override
+    public boolean isSuspending() {
+        return false;
+    }
+
+    @Override
+    public void init() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void suspend() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void resume() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void start() {
+        startDate = new Date();
+        LOG.info("Apache Camel {} (CamelContext: {}) is starting", getVersion(), getName());
+        for (Route route : routes) {
+            route.getConsumer().start();
+        }
+    }
+
+    @Override
+    public void stop() {
+        for (Route route : routes) {
+            route.getConsumer().stop();
+        }
+    }
+
+    @Override
+    public void shutdown() {
+    }
+
+    @Override
+    public void close() throws IOException {
+        stop();
+    }
+
+    //
+    // RuntimeConfig
+    //
+
+    @Override
+    public void setStreamCaching(Boolean cache) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isStreamCaching() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isTracing() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getTracingPattern() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isBacklogTracing() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isDebugging() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isMessageHistory() {
+        return messageHistory;
+    }
+
+    @Override
+    public Boolean isLogMask() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isLogExhaustedMessageBody() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Long getDelayer() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isAutoStartup() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ShutdownRoute getShutdownRoute() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ShutdownRunningTask getShutdownRunningTask() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAllowUseOriginalMessage(Boolean allowUseOriginalMessage) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isAllowUseOriginalMessage() {
+        return allowUseOriginalMessage;
+    }
+
+    @Override
+    public Boolean isCaseInsensitiveHeaders() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setCaseInsensitiveHeaders(Boolean caseInsensitiveHeaders) {
+        throw new UnsupportedOperationException();
+    }
+
+
+    //
+    // Model
+    //
+
+    @Override
+    public Registry getRegistry() {
+        return registry;
+    }
+
+    @Override
+    public TypeConverterRegistry getTypeConverterRegistry() {
+        return typeConverter;
+    }
+
+    @Override
+    public ModelJAXBContextFactory getModelJAXBContextFactory() {
+        return modelJAXBContextFactory;
+    }
+
+    @Override
+    public ComponentResolver getComponentResolver() {
+        return componentResolver;
+    }
+
+    @Override
+    public LanguageResolver getLanguageResolver() {
+        return languageResolver;
+    }
+
+    @Override
+    public DataFormatResolver getDataFormatResolver() {
+        return dataFormatResolver;
+    }
+
+    @Override
+    public UuidGenerator getUuidGenerator() {
+        return uuidGenerator;
+    }
+
+    @Override
+    public <T extends CamelContext> T adapt(Class<T> type) {
+        if (type.isInstance(this)) {
+            return type.cast(this);
+        }
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> T getExtension(Class<T> type) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> void setExtension(Class<T> type, T module) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isVetoStarted() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public CamelContextNameStrategy getNameStrategy() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setNameStrategy(CamelContextNameStrategy nameStrategy) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ManagementNameStrategy getManagementNameStrategy() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setManagementNameStrategy(ManagementNameStrategy nameStrategy) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getManagementName() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setManagementName(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getVersion() {
+        return version;
+    }
+
+    @Override
+    public ServiceStatus getStatus() {
+        return ServiceStatus.Started;
+    }
+
+    @Override
+    public String getUptime() {
+        long delta = getUptimeMillis();
+        if (delta == 0) {
+            return "";
+        }
+        return TimeUtils.printDuration(delta);
+    }
+
+    @Override
+    public long getUptimeMillis() {
+        if (startDate == null) {
+            return 0;
+        }
+        return new Date().getTime() - startDate.getTime();
+    }
+
+    @Override
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    @Override
+    public void addService(Object object) throws Exception {
+    }
+
+    @Override
+    public void addService(Object object, boolean stopOnShutdown) throws Exception {
+
+    }
+
+    @Override
+    public void addService(Object object, boolean stopOnShutdown, boolean forceStart) throws Exception {
+
+    }
+
+    @Override
+    public void addPrototypeService(Object object) throws Exception {
+
+    }
+
+    @Override
+    public boolean removeService(Object object) throws Exception {
+        return false;
+    }
+
+    @Override
+    public boolean hasService(Object object) {
+        return false;
+    }
+
+    @Override
+    public <T> T hasService(Class<T> type) {
+        return null;
+    }
+
+    @Override
+    public <T> Set<T> hasServices(Class<T> type) {
+        return null;
+    }
+
+    @Override
+    public void deferStartService(Object object, boolean stopOnShutdown) throws Exception {
+    }
+
+    @Override
+    public void addStartupListener(StartupListener listener) throws Exception {
+    }
+
+    @Override
+    public Component hasComponent(String componentName) {
+        return components.get(componentName);
+    }
+
+    @Override
+    public Component getComponent(String componentName) {
+        return getComponent(name, true, true);
+    }
+
+    @Override
+    public Component getComponent(String name, boolean autoCreateComponents) {
+        return getComponent(name, autoCreateComponents, true);
+    }
+
+    @Override
+    public Component getComponent(String name, boolean autoCreateComponents, boolean autoStart) {
+        return components.get(name);
+    }
+
+    @Override
+    public <T extends Component> T getComponent(String name, Class<T> componentType) {
+        return componentType.cast(hasComponent(name));
+    }
+
+    @Override
+    public List<String> getComponentNames() {
+        return new ArrayList<>(components.keySet());
+    }
+
+    @Override
+    public EndpointRegistry<? extends ValueHolder<String>> getEndpointRegistry() {
+        return endpoints;
+    }
+
+    @Override
+    public Endpoint getEndpoint(String uri) {
+        return doGetEndpoint(uri, false, false);
+    }
+
+    /**
+     * Normalize uri so we can do endpoint hits with minor mistakes and
+     * parameters is not in the same order.
+     *
+     * @param uri the uri
+     * @return normalized uri
+     * @throws ResolveEndpointFailedException if uri cannot be normalized
+     */
+    protected static String normalizeEndpointUri(String uri) {
+        try {
+            uri = URISupport.normalizeUri(uri);
+        } catch (Exception e) {
+            throw new ResolveEndpointFailedException(uri, e);
+        }
+        return uri;
+    }
+
+    @Override
+    public Endpoint getEndpoint(String uri, Map<String, Object> parameters) {
+        return doGetEndpoint(uri, parameters, false);
+    }
+
+    @Override
+    public <T extends Endpoint> T getEndpoint(String name, Class<T> endpointType) {
+        Endpoint endpoint = getEndpoint(name);
+        if (endpoint == null) {
+            throw new NoSuchEndpointException(name);
+        }
+        if (endpoint instanceof InterceptSendToEndpoint) {
+            endpoint = ((InterceptSendToEndpoint)endpoint).getOriginalEndpoint();
+        }
+        if (endpointType.isInstance(endpoint)) {
+            return endpointType.cast(endpoint);
+        } else {
+            throw new IllegalArgumentException("The endpoint is not of type: " + endpointType + " but is: " + endpoint.getClass().getCanonicalName());
+        }
+    }
+
+    @Override
+    public Collection<Endpoint> getEndpoints() {
+        return new ArrayList<>(endpoints.values());
+    }
+
+    @Override
+    public Map<String, Endpoint> getEndpointMap() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Endpoint hasEndpoint(String uri) {
+        return endpoints.get(new EndpointKey(uri));
+    }
+
+    @Override
+    public GlobalEndpointConfiguration getGlobalEndpointConfiguration() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RouteController getRouteController() {
+        return routeController;
+    }
+
+    @Override
+    public List<Route> getRoutes() {
+        return routes;
+    }
+
+    @Override
+    public int getRoutesSize() {
+        return routes.size();
+    }
+
+    @Override
+    public Route getRoute(String id) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Processor getProcessor(String id) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T extends Processor> T getProcessor(String id, Class<T> type) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<RoutePolicyFactory> getRoutePolicyFactories() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RestConfiguration getRestConfiguration() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RestConfiguration getRestConfiguration(String component, boolean defaultIfNotFound) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Collection<RestConfiguration> getRestConfigurations() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RestRegistry getRestRegistry() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public TypeConverter getTypeConverter() {
+        return typeConverter;
+    }
+
+    @Override
+    public <T> T getRegistry(Class<T> type) {
+        return type.cast(registry);
+    }
+
+    @Override
+    public Injector getInjector() {
+        return injector;
+    }
+
+    @Override
+    public List<LifecycleStrategy> getLifecycleStrategies() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Language resolveLanguage(String language) throws NoSuchLanguageException {
+        Language answer;
+        synchronized (languages) {
+            answer = languages.get(language);
+            // check if the language is singleton, if so return the shared
+            // instance
+            if (answer instanceof IsSingleton) {
+                boolean singleton = ((IsSingleton)answer).isSingleton();
+                if (singleton) {
+                    return answer;
+                }
+            }
+            // language not known or not singleton, then use resolver
+            answer = getLanguageResolver().resolveLanguage(language, reference);
+            // inject CamelContext if aware
+            if (answer != null) {
+                if (answer instanceof CamelContextAware) {
+                    ((CamelContextAware)answer).setCamelContext(reference);
+                }
+                if (answer instanceof Service) {
+                    try {
+                        startService((Service)answer);
+                    } catch (Exception e) {
+                        throw RuntimeCamelException.wrapRuntimeCamelException(e);
+                    }
+                }
+                languages.put(language, answer);
+            }
+        }
+        return answer;
+    }
+
+    @Override
+    public String resolvePropertyPlaceholders(String text) {
+        if (text != null && text.contains(PropertiesComponent.PREFIX_TOKEN)) {
+            // the parser will throw exception if property key was not found
+            return getPropertiesComponent().parseUri(text);
+        }
+        // is the value a known field (currently we only support
+        // constants from Exchange.class)
+        if (text != null && text.startsWith("Exchange.")) {
+            String field = StringHelper.after(text, "Exchange.");
+            String constant = ExchangeConstantProvider.lookup(field);
+            if (constant != null) {
+                return constant;
+            } else {
+                throw new IllegalArgumentException("Constant field with name: " + field + " not found on Exchange.class");
+            }
+        }
+        // return original text as is
+        return text;
+    }
+
+    @Override
+    public PropertiesComponent getPropertiesComponent() {
+        return propertiesComponent;
+    }
+
+    @Override
+    public List<String> getLanguageNames() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ProducerTemplate createProducerTemplate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ProducerTemplate createProducerTemplate(int maximumCacheSize) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FluentProducerTemplate createFluentProducerTemplate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FluentProducerTemplate createFluentProducerTemplate(int maximumCacheSize) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ConsumerTemplate createConsumerTemplate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ConsumerTemplate createConsumerTemplate(int maximumCacheSize) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DataFormat resolveDataFormat(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DataFormat createDataFormat(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Transformer resolveTransformer(String model) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Transformer resolveTransformer(DataType from, DataType to) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public TransformerRegistry getTransformerRegistry() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Validator resolveValidator(DataType type) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ValidatorRegistry getValidatorRegistry() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setGlobalOptions(Map<String, String> globalOptions) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, String> getGlobalOptions() {
+        return globalOptions;
+    }
+
+    @Override
+    public String getGlobalOption(String key) {
+        String value = getGlobalOptions().get(key);
+        if (ObjectHelper.isNotEmpty(value)) {
+            try {
+                value = resolvePropertyPlaceholders(value);
+            } catch (Exception e) {
+                throw new RuntimeCamelException("Error getting global option: " + key, e);
+            }
+        }
+        return value;
+    }
+
+    @Override
+    public ClassResolver getClassResolver() {
+        return classResolver;
+    }
+
+    @Override
+    public ManagementStrategy getManagementStrategy() {
+        return null;
+    }
+
+    @Override
+    public void disableJMX() throws IllegalStateException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public InflightRepository getInflightRepository() {
+        return inflightRepository;
+    }
+
+    @Override
+    public ClassLoader getApplicationContextClassLoader() {
+        return applicationContextClassLoader;
+    }
+
+    @Override
+    public ShutdownStrategy getShutdownStrategy() {
+        return shutdownStrategy;
+    }
+
+    @Override
+    public ExecutorServiceManager getExecutorServiceManager() {
+        return executorServiceManager;
+    }
+
+    @Override
+    public MessageHistoryFactory getMessageHistoryFactory() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Debugger getDebugger() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Tracer getTracer() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isLoadTypeConverters() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setLoadTypeConverters(Boolean loadTypeConverters) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isTypeConverterStatisticsEnabled() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setTypeConverterStatisticsEnabled(Boolean typeConverterStatisticsEnabled) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isUseMDCLogging() {
+        return useMDCLogging;
+    }
+
+    @Override
+    public void setUseMDCLogging(Boolean useMDCLogging) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getMDCLoggingKeysPattern() {
+        return mdcLoggingKeysPattern;
+    }
+
+    @Override
+    public void setMDCLoggingKeysPattern(String pattern) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isUseDataType() {
+        return useDataType;
+    }
+
+    @Override
+    public void setUseDataType(Boolean useDataType) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Boolean isUseBreadcrumb() {
+        return useBreadcrumb;
+    }
+
+    @Override
+    public void setUseBreadcrumb(Boolean useBreadcrumb) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public StreamCachingStrategy getStreamCachingStrategy() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RuntimeEndpointRegistry getRuntimeEndpointRegistry() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SSLContextParameters getSSLContextParameters() {
+        throw new UnsupportedOperationException();
+    }
+
+    //
+    // ExtendedCamelContext
+    //
+
+    @Override
+    public Endpoint getPrototypeEndpoint(String uri) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Endpoint getPrototypeEndpoint(NormalizedEndpointUri uri) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Endpoint hasEndpoint(NormalizedEndpointUri uri) {
+        EndpointKey key;
+        if (uri instanceof EndpointKey) {
+            key = (EndpointKey) uri;
+        } else {
+            key = getEndpointKeyPreNormalized(uri.getUri());
+        }
+        return endpoints.get(key);
+    }
+
+    @Override
+    public Endpoint getEndpoint(NormalizedEndpointUri uri) {
+        return doGetEndpoint(uri.getUri(), true, false);
+    }
+
+    @Override
+    public Endpoint getEndpoint(NormalizedEndpointUri uri, Map<String, Object> parameters) {
+        return doGetEndpoint(uri.getUri(), parameters, true);
+    }
+
+    protected Endpoint doGetEndpoint(String uri, boolean normalized, boolean prototype) {
+        StringHelper.notEmpty(uri, "uri");
+        // in case path has property placeholders then try to let property
+        // component resolve those
+        if (!normalized) {
+            try {
+                uri = resolvePropertyPlaceholders(uri);
+            } catch (Exception e) {
+                throw new ResolveEndpointFailedException(uri, e);
+            }
+        }
+        final String rawUri = uri;
+        // normalize uri so we can do endpoint hits with minor mistakes and
+        // parameters is not in the same order
+        if (!normalized) {
+            uri = normalizeEndpointUri(uri);
+        }
+        String scheme;
+        Endpoint answer = null;
+        if (!prototype) {
+            // use optimized method to get the endpoint uri
+            EndpointKey key = getEndpointKeyPreNormalized(uri);
+            // only lookup and reuse existing endpoints if not prototype scoped
+            answer = endpoints.get(key);
+        }
+        // unknown scheme
+        if (answer == null) {
+            throw new NoSuchEndpointException(uri);
+        }
+        return answer;
+    }
+
+    protected Endpoint doGetEndpoint(String uri, Map<String, Object> parameters, boolean normalized) {
+        StringHelper.notEmpty(uri, "uri");
+        // in case path has property placeholders then try to let property
+        // component resolve those
+        if (!normalized) {
+            try {
+                uri = resolvePropertyPlaceholders(uri);
+            } catch (Exception e) {
+                throw new ResolveEndpointFailedException(uri, e);
+            }
+        }
+        final String rawUri = uri;
+        // normalize uri so we can do endpoint hits with minor mistakes and
+        // parameters is not in the same order
+        if (!normalized) {
+            uri = normalizeEndpointUri(uri);
+        }
+        Endpoint answer;
+        String scheme = null;
+        // use optimized method to get the endpoint uri
+        EndpointKey key = getEndpointKeyPreNormalized(uri);
+        answer = endpoints.get(key);
+        // unknown scheme
+        if (answer == null) {
+            throw new ResolveEndpointFailedException(uri, "No component found with scheme: " + scheme);
+        }
+        return answer;
+    }
+
+    protected EndpointKey getEndpointKeyPreNormalized(String uri) {
+        return new EndpointKey(uri, true);
+    }
+
+    @Override
+    public NormalizedEndpointUri normalizeUri(String uri) {
+        try {
+            uri = resolvePropertyPlaceholders(uri);
+            uri = normalizeEndpointUri(uri);
+            return new NormalizedUri(uri);
+        } catch (Exception e) {
+            throw new ResolveEndpointFailedException(uri, e);
+        }
+    }
+
+    @Override
+    public List<RouteStartupOrder> getRouteStartupOrder() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CamelBeanPostProcessor getBeanPostProcessor() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ManagementMBeanAssembler getManagementMBeanAssembler() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AsyncProcessor createMulticast(Collection<Processor> processors, ExecutorService executor, boolean shutdownExecutorService) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ErrorHandlerFactory getErrorHandlerFactory() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PackageScanClassResolver getPackageScanClassResolver() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PackageScanResourceResolver getPackageScanResourceResolver() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FactoryFinder getDefaultFactoryFinder() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FactoryFinder getFactoryFinder(String path) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public FactoryFinderResolver getFactoryFinderResolver() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ProcessorFactory getProcessorFactory() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DeferServiceFactory getDeferServiceFactory() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public UnitOfWorkFactory getUnitOfWorkFactory() {
+        return unitOfWorkFactory;
+    }
+
+    @Override
+    public AnnotationBasedProcessorFactory getAnnotationBasedProcessorFactory() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public BeanProxyFactory getBeanProxyFactory() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public BeanProcessorFactory getBeanProcessorFactory() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ScheduledExecutorService getErrorHandlerExecutorService() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<InterceptStrategy> getInterceptStrategies() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set<LogListener> getLogListeners() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AsyncProcessorAwaitManager getAsyncProcessorAwaitManager() {
+        return asyncProcessorAwaitManager;
+    }
+
+    @Override
+    public BeanIntrospection getBeanIntrospection() {
+        return beanIntrospection;
+    }
+
+    @Override
+    public HeadersMapFactory getHeadersMapFactory() {
+        return headersMapFactory;
+    }
+
+    @Override
+    public ReactiveExecutor getReactiveExecutor() {
+        return reactiveExecutor;
+    }
+
+    @Override
+    public boolean isEventNotificationApplicable() {
+        return eventNotificationApplicable;
+    }
+
+    @Override
+    public ModelToXMLDumper getModelToXMLDumper() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RuntimeCamelCatalog getRuntimeCamelCatalog() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ConfigurerResolver getConfigurerResolver() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isAllowAddingNewRoutes() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isClearModelReferences() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addRoute(Route route) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeRoute(Route route) {
+        throw new UnsupportedOperationException();
+    }
+
+    //
+    // CatalogCamelContext
+    //
+
+    @Override
+    public String getComponentParameterJsonSchema(String componentName) throws IOException {
+        Class<?> clazz;
+        Object instance = getRegistry().lookupByNameAndType(componentName, Component.class);
+        if (instance != null) {
+            clazz = instance.getClass();
+        } else {
+            clazz = getFactoryFinder(DefaultComponentResolver.RESOURCE_PATH).findClass(componentName).orElse(null);
+            if (clazz == null) {
+                instance = hasComponent(componentName);
+                if (instance != null) {
+                    clazz = instance.getClass();
+                } else {
+                    return null;
+                }
+            }
+        }
+        // special for ActiveMQ as it is really just JMS
+        if ("ActiveMQComponent".equals(clazz.getSimpleName())) {
+            return getComponentParameterJsonSchema("jms");
+        } else {
+            return getJsonSchema(clazz.getPackage().getName(), componentName);
+        }
+    }
+
+    @Override
+    public String getDataFormatParameterJsonSchema(String dataFormatName) throws IOException {
+        Class<?> clazz;
+        Object instance = getRegistry().lookupByNameAndType(dataFormatName, DataFormat.class);
+        if (instance != null) {
+            clazz = instance.getClass();
+        } else {
+            clazz = getFactoryFinder(DefaultDataFormatResolver.DATAFORMAT_RESOURCE_PATH).findClass(dataFormatName).orElse(null);
+            if (clazz == null) {
+                return null;
+            }
+        }
+        return getJsonSchema(clazz.getPackage().getName(), dataFormatName);
+    }
+
+    @Override
+    public String getLanguageParameterJsonSchema(String languageName) throws IOException {
+        Class<?> clazz;
+        Object instance = getRegistry().lookupByNameAndType(languageName, Language.class);
+        if (instance != null) {
+            clazz = instance.getClass();
+        } else {
+            clazz = getFactoryFinder(DefaultLanguageResolver.LANGUAGE_RESOURCE_PATH).findClass(languageName).orElse(null);
+            if (clazz == null) {
+                return null;
+            }
+        }
+        return getJsonSchema(clazz.getPackage().getName(), languageName);
+    }
+
+    @Override
+    public String getEipParameterJsonSchema(String eipName) throws IOException {
+        // the eip json schema may be in some of the sub-packages so look until
+        // we find it
+        String[] subPackages = new String[] { "", "/config", "/dataformat", "/language", "/loadbalancer", "/rest" };
+        for (String sub : subPackages) {
+            String path = CamelContextHelper.MODEL_DOCUMENTATION_PREFIX + sub + "/" + eipName + ".json";
+            InputStream inputStream = getClassResolver().loadResourceAsStream(path);
+            if (inputStream != null) {
+                try {
+                    return IOHelper.loadText(inputStream);
+                } finally {
+                    IOHelper.close(inputStream);
+                }
+            }
+        }
+        return null;
+    }
+
+    private String getJsonSchema(String packageName, String name) throws IOException {
+        String path = packageName.replace('.', '/') + "/" + name + ".json";
+        InputStream inputStream = getClassResolver().loadResourceAsStream(path);
+        if (inputStream != null) {
+            try {
+                return IOHelper.loadText(inputStream);
+            } finally {
+                IOHelper.close(inputStream);
+            }
+        }
+        return null;
+    }
+
+    //
+    // Unsupported mutable methods
+    //
+
+    @Override
+    public void setName(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setRegistry(Registry registry) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setupRoutes(boolean done) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isSetupRoutes() {
+        return false;
+    }
+
+    @Override
+    public void setStreamCachingStrategy(StreamCachingStrategy streamCachingStrategy) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setErrorHandlerFactory(ErrorHandlerFactory errorHandlerFactory) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setComponentResolver(ComponentResolver componentResolver) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setLanguageResolver(LanguageResolver languageResolver) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setDataFormatResolver(DataFormatResolver dataFormatResolver) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setPackageScanClassResolver(PackageScanClassResolver resolver) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setPackageScanResourceResolver(PackageScanResourceResolver resolver) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setFactoryFinderResolver(FactoryFinderResolver resolver) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setProcessorFactory(ProcessorFactory processorFactory) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setModelJAXBContextFactory(ModelJAXBContextFactory modelJAXBContextFactory) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setUnitOfWorkFactory(UnitOfWorkFactory unitOfWorkFactory) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addInterceptStrategy(InterceptStrategy interceptStrategy) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setupManagement(Map<String, Object> options) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addLogListener(LogListener listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAsyncProcessorAwaitManager(AsyncProcessorAwaitManager manager) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setBeanIntrospection(BeanIntrospection beanIntrospection) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setHeadersMapFactory(HeadersMapFactory factory) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setReactiveExecutor(ReactiveExecutor reactiveExecutor) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setEventNotificationApplicable(boolean eventNotificationApplicable) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setXMLRoutesDefinitionLoader(XMLRoutesDefinitionLoader xmlRoutesDefinitionLoader) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setModelToXMLDumper(ModelToXMLDumper modelToXMLDumper) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setRuntimeCamelCatalog(RuntimeCamelCatalog runtimeCamelCatalog) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setConfigurerResolver(ConfigurerResolver configurerResolver) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAllowAddingNewRoutes(boolean allowAddingNewRoutes) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setClearModelReferences(boolean clearModelReferences) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public XMLRoutesDefinitionLoader getXMLRoutesDefinitionLoader() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void registerEndpointCallback(EndpointStrategy strategy) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setNodeIdFactory(NodeIdFactory factory) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Endpoint addEndpoint(String uri, Endpoint endpoint) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeEndpoint(Endpoint endpoint) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Collection<Endpoint> removeEndpoints(String pattern) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public NodeIdFactory getNodeIdFactory() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setRuntimeEndpointRegistry(RuntimeEndpointRegistry runtimeEndpointRegistry) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setSSLContextParameters(SSLContextParameters sslContextParameters) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setTracer(Tracer tracer) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setUuidGenerator(UuidGenerator uuidGenerator) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addComponent(String componentName, Component component) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Component removeComponent(String componentName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setRouteController(RouteController routeController) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addRoutes(RoutesBuilder builder) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeRoute(String routeId) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addRoutePolicyFactory(RoutePolicyFactory routePolicyFactory) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setRestConfiguration(RestConfiguration restConfiguration) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addRestConfiguration(RestConfiguration restConfiguration) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setRestRegistry(RestRegistry restRegistry) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setDebugger(Debugger debugger) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setTracing(Boolean tracing) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setTracingPattern(String tracePattern) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setBacklogTracing(Boolean backlogTrace) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setDebugging(Boolean debugging) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setMessageHistory(Boolean messageHistory) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setLogMask(Boolean logMask) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setLogExhaustedMessageBody(Boolean logExhaustedMessageBody) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setDelayer(Long delay) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAutoStartup(Boolean autoStartup) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setShutdownRoute(ShutdownRoute shutdownRoute) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setClassResolver(ClassResolver resolver) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setManagementStrategy(ManagementStrategy strategy) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setInflightRepository(InflightRepository repository) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setApplicationContextClassLoader(ClassLoader classLoader) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setShutdownStrategy(ShutdownStrategy shutdownStrategy) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setExecutorServiceManager(ExecutorServiceManager executorServiceManager) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setMessageHistoryFactory(MessageHistoryFactory messageHistoryFactory) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setTypeConverterRegistry(TypeConverterRegistry typeConverterRegistry) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setInjector(Injector injector) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addLifecycleStrategy(LifecycleStrategy lifecycleStrategy) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setPropertiesComponent(PropertiesComponent propertiesComponent) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RouteController getInternalRouteController() {
+        return new RouteController() {
+            @Override
+            public Collection<Route> getControlledRoutes() {
+                return routes;
+            }
+            @Override
+            public void startAllRoutes() throws Exception {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public boolean isStartingRoutes() {
+                return false;
+            }
+            @Override
+            public ServiceStatus getRouteStatus(String routeId) {
+                return ServiceStatus.Started;
+            }
+            @Override
+            public void startRoute(String routeId) throws Exception {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public void stopRoute(String routeId) throws Exception {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public void stopRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public boolean stopRoute(String routeId, long timeout, TimeUnit timeUnit, boolean abortAfterTimeout) throws Exception {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public void suspendRoute(String routeId) throws Exception {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public void suspendRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public void resumeRoute(String routeId) throws Exception {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public void setCamelContext(CamelContext camelContext) {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public CamelContext getCamelContext() {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public void start() {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public void stop() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    private void startService(Service service) throws Exception {
+        // and register startup aware so they can be notified when
+        // camel context has been started
+        if (service instanceof StartupListener) {
+            StartupListener listener = (StartupListener)service;
+            addStartupListener(listener);
+        }
+        if (service instanceof CamelContextAware) {
+            CamelContextAware aware = (CamelContextAware)service;
+            aware.setCamelContext(reference);
+        }
+        service.start();
+    }
+}
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java
index e03f1d2..4ac17d7 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java
@@ -289,11 +289,6 @@ public interface Model {
     void addServiceCallConfiguration(String serviceName, ServiceCallConfigurationDefinition configuration);
 
     /**
-     * Start all routes from this model.
-     */
-    void startRouteDefinitions() throws Exception;
-
-    /**
      * Used for filtering routes routes matching the given pattern, which
      * follows the following rules: - Match by route id - Match by route input
      * endpoint uri The matching is using exact match, by wildcard and regular
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/ModelCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/ModelCamelContext.java
index 7d9fb3f..ea3eafb 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/ModelCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/ModelCamelContext.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.model;
 
+import java.util.List;
+
 import org.apache.camel.CamelContext;
 
 /**
@@ -23,4 +25,11 @@ import org.apache.camel.CamelContext;
  */
 public interface ModelCamelContext extends CamelContext, Model {
 
+    /**
+     * Start all routes from this model.
+     */
+    void startRouteDefinitions() throws Exception;
+
+    void startRouteDefinitions(List<RouteDefinition> routeDefinitions) throws Exception;
+
 }
diff --git a/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java b/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
index 8af9e69..cae2fed 100644
--- a/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
+++ b/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
@@ -24,6 +24,7 @@ import org.apache.camel.builder.NotifyBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.lw.ImmutableCamelContext;
 import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.spi.Language;
 import org.apache.camel.spi.Registry;
@@ -43,6 +44,7 @@ public abstract class ContextTestSupport extends TestSupport {
     protected volatile ConsumerTemplate consumer;
     protected volatile NotifyBuilder oneExchangeDone;
     private boolean useRouteBuilder = true;
+    private boolean useImmutableContext = true;
     private Service camelContextService;
 
     /**
@@ -60,6 +62,14 @@ public abstract class ContextTestSupport extends TestSupport {
         this.useRouteBuilder = useRouteBuilder;
     }
 
+    public boolean isUseImmutableContext() {
+        return useImmutableContext;
+    }
+
+    public void setUseImmutableContext(boolean useImmutableContext) {
+        this.useImmutableContext = useImmutableContext;
+    }
+
     public Service getCamelContextService() {
         return camelContextService;
     }
@@ -170,10 +180,14 @@ public abstract class ContextTestSupport extends TestSupport {
         if (camelContextService != null) {
             camelContextService.start();
         } else {
-            if (context instanceof DefaultCamelContext) {
-                DefaultCamelContext defaultCamelContext = (DefaultCamelContext)context;
-                if (!defaultCamelContext.isStarted()) {
-                    defaultCamelContext.start();
+            if (context instanceof ImmutableCamelContext) {
+                ImmutableCamelContext ctx = (ImmutableCamelContext) context;
+                Boolean autoStartup = ctx.isAutoStartup();
+                ctx.setAutoStartup(false);
+                ctx.start();
+                ctx.makeImmutable();
+                if (autoStartup != null && autoStartup) {
+                    ctx.startImmutable();
                 }
             } else {
                 context.start();
@@ -182,11 +196,19 @@ public abstract class ContextTestSupport extends TestSupport {
     }
 
     protected CamelContext createCamelContext() throws Exception {
-        DefaultCamelContext context = new DefaultCamelContext(false);
+        CamelContext context;
+        if (useImmutableContext) {
+            ImmutableCamelContext ctx = new ImmutableCamelContext();
+            ctx.setRegistry(createRegistry());
+            context = ctx;
+        } else {
+            DefaultCamelContext ctx = new DefaultCamelContext(false);
+            ctx.setRegistry(createRegistry());
+            context = ctx;
+        }
         if (!useJmx()) {
             context.disableJMX();
         }
-        context.setRegistry(createRegistry());
         context.setLoadTypeConverters(isLoadTypeConverters());
         return context;
     }
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index 3ac7b7b..0c48dee 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -53,8 +53,8 @@ import org.apache.camel.spi.PropertyConfigurer;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.support.LifecycleStrategySupport;
 import org.apache.camel.support.PropertyBindingSupport;
+import org.apache.camel.support.service.BaseService;
 import org.apache.camel.support.service.ServiceHelper;
-import org.apache.camel.support.service.ServiceSupport;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
@@ -71,7 +71,7 @@ import static org.apache.camel.util.StringHelper.matches;
 /**
  * Base class for main implementations to allow bootstrapping Camel in standalone mode.
  */
-public abstract class BaseMainSupport extends ServiceSupport {
+public abstract class BaseMainSupport extends BaseService {
 
     private static final Logger LOG = LoggerFactory.getLogger(BaseMainSupport.class);
 
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java
index 11df373..71312ca 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/EndpointHelper.java
@@ -55,6 +55,23 @@ public final class EndpointHelper {
     }
 
     /**
+     * Normalize uri so we can do endpoint hits with minor mistakes and
+     * parameters is not in the same order.
+     *
+     * @param uri the uri
+     * @return normalized uri
+     * @throws ResolveEndpointFailedException if uri cannot be normalized
+     */
+    public static String normalizeEndpointUri(String uri) {
+        try {
+            uri = URISupport.normalizeUri(uri);
+        } catch (Exception e) {
+            throw new ResolveEndpointFailedException(uri, e);
+        }
+        return uri;
+    }
+
+    /**
      * Creates a {@link PollingConsumer} and polls all pending messages on the endpoint
      * and invokes the given {@link Processor} to process each {@link Exchange} and then closes
      * down the consumer and throws any exceptions thrown.
@@ -120,11 +137,7 @@ public final class EndpointHelper {
         }
 
         // normalize uri so we can do endpoint hits with minor mistakes and parameters is not in the same order
-        try {
-            uri = URISupport.normalizeUri(uri);
-        } catch (Exception e) {
-            throw new ResolveEndpointFailedException(uri, e);
-        }
+        uri = normalizeEndpointUri(uri);
 
         // we need to test with and without scheme separators (//)
         boolean match = PatternHelper.matchPattern(toggleUriSchemeSeparators(uri), pattern);