You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by or...@apache.org on 2023/03/29 10:00:17 UTC

[camel] 01/03: CAMEL-15105: created a plugin manager to manage extensions to the context

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

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

commit e0376969239d08d9cf9c14022f5393a0766fcbc4
Author: Otavio Rodolfo Piske <an...@gmail.com>
AuthorDate: Thu Mar 23 11:45:05 2023 +0100

    CAMEL-15105: created a plugin manager to manage extensions to the context
---
 .../org/apache/camel/ExtendedCamelContext.java     | 23 ++++++++
 .../java/org/apache/camel/spi/PluginManager.java   | 36 +++++++++++++
 .../camel/impl/engine/AbstractCamelContext.java    | 37 +++----------
 .../impl/engine/DefaultCamelContextExtension.java  | 27 ++++++++++
 .../impl/engine/DefaultContextPluginManager.java   | 63 ++++++++++++++++++++++
 .../impl/lw/LightweightCamelContextExtension.java  | 16 ++++++
 6 files changed, 172 insertions(+), 30 deletions(-)

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 6566b09778a..641a0bac7fc 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
@@ -61,6 +61,7 @@ import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PackageScanResourceResolver;
 import org.apache.camel.spi.PeriodTaskResolver;
 import org.apache.camel.spi.PeriodTaskScheduler;
+import org.apache.camel.spi.PluginManager;
 import org.apache.camel.spi.ProcessorExchangeFactory;
 import org.apache.camel.spi.ProcessorFactory;
 import org.apache.camel.spi.ReactiveExecutor;
@@ -910,4 +911,26 @@ public interface ExtendedCamelContext {
      */
     void setPeriodTaskResolver(PeriodTaskResolver periodTaskResolver);
 
+    /**
+     * Gets access to the internal plugin manager
+     * @return the internal plugin manager
+     */
+    @Deprecated
+    PluginManager getPluginManager();
+
+    /**
+     * Gets a plugin of the given type.
+     *
+     * @param  type the type of the extension
+     * @return      the extension, or <tt>null</tt> if no extension has been installed.
+     */
+    <T> T getContextPlugin(Class<T> type);
+
+    /**
+     * Allows installation of custom plugins to the Camel context.
+     *
+     * @param type   the type of the extension
+     * @param module the instance of the extension
+     */
+    <T> void addContextPlugin(Class<T> type, T module);
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/PluginManager.java b/core/camel-api/src/main/java/org/apache/camel/spi/PluginManager.java
new file mode 100644
index 00000000000..504ca54ab75
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/PluginManager.java
@@ -0,0 +1,36 @@
+/*
+ * 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.spi;
+
+public interface PluginManager {
+    /**
+     * Gets a plugin of the given type.
+     *
+     * @param  type the type of the extension
+     * @return      the extension, or <tt>null</tt> if no extension has been installed.
+     */
+    <T> T getContextPlugin(Class<T> type);
+
+    /**
+     * Allows installation of custom plugins to the Camel context.
+     *
+     * @param type   the type of the extension
+     * @param module the instance of the extension
+     */
+    <T> void addContextPlugin(Class<T> type, T module);
+}
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index 17e696579a7..fbd1ec9333e 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -40,6 +40,7 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
 import java.util.function.Supplier;
 
 import org.apache.camel.CamelContext;
@@ -133,6 +134,7 @@ import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PackageScanResourceResolver;
 import org.apache.camel.spi.PeriodTaskResolver;
 import org.apache.camel.spi.PeriodTaskScheduler;
+import org.apache.camel.spi.PluginManager;
 import org.apache.camel.spi.ProcessorExchangeFactory;
 import org.apache.camel.spi.ProcessorFactory;
 import org.apache.camel.spi.PropertiesComponent;
@@ -271,8 +273,8 @@ public abstract class AbstractCamelContext extends BaseService
     private final InternalRouteStartupManager internalRouteStartupManager = new InternalRouteStartupManager(this);
     private final List<RouteStartupOrder> routeStartupOrder = new ArrayList<>();
     private final StopWatch stopWatch = new StopWatch(false);
-    private final Map<Class<?>, Object> extensions = new ConcurrentHashMap<>();
-    private final ThreadLocal<Set<String>> componentsInCreation = ThreadLocal.withInitial(HashSet::new);
+    private final PluginManager pluginManager;
+    private final ThreadLocal<Set<String>> componentsInCreation = ThreadLocal.withInitial(() -> new HashSet<>());
     private VetoCamelContextStartException vetoed;
     private String managementName;
     private ClassLoader applicationContextClassLoader;
@@ -387,6 +389,7 @@ public abstract class AbstractCamelContext extends BaseService
         this.bootstraps.add(bootstrapFactories::clear);
 
         this.internalServiceManager = new InternalServiceManager(this, internalRouteStartupManager, startupListeners);
+        this.pluginManager = new DefaultContextPluginManager(internalServiceManager);
 
         if (build) {
             try {
@@ -444,38 +447,12 @@ public abstract class AbstractCamelContext extends BaseService
             return type.cast(this);
         }
 
-        // lookup by direct implementatiin
-        Object extension = extensions.get(type);
-        if (extension == null) {
-            // fallback and lookup via interfaces
-            for (Object e : extensions.values()) {
-                if (type.isInstance(e)) {
-                    return type.cast(e);
-                }
-            }
-        }
-        if (extension instanceof Supplier) {
-            extension = ((Supplier) extension).get();
-            setExtension(type, (T) extension);
-        }
-        return (T) extension;
+        return pluginManager.getContextPlugin(type);
     }
 
     @Override
     public <T> void setExtension(Class<T> type, T module) {
-        if (module != null) {
-            try {
-                extensions.put(type, internalServiceManager.addService(module));
-            } catch (Exception e) {
-                throw RuntimeCamelException.wrapRuntimeCamelException(e);
-            }
-        }
-    }
-
-    public <T> void setDefaultExtension(Class<T> type, Supplier<T> module) {
-        if (module != null) {
-            extensions.putIfAbsent(type, module);
-        }
+        pluginManager.addContextPlugin(type, module);
     }
 
     @Override
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java
index 2e739885ad3..4aeaa519cd0 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java
@@ -80,6 +80,7 @@ import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PackageScanResourceResolver;
 import org.apache.camel.spi.PeriodTaskResolver;
 import org.apache.camel.spi.PeriodTaskScheduler;
+import org.apache.camel.spi.PluginManager;
 import org.apache.camel.spi.ProcessorExchangeFactory;
 import org.apache.camel.spi.ProcessorFactory;
 import org.apache.camel.spi.PropertiesComponent;
@@ -108,6 +109,7 @@ class DefaultCamelContextExtension implements ExtendedCamelContext {
     private final List<InterceptStrategy> interceptStrategies = new ArrayList<>();
     private final Map<String, FactoryFinder> factories = new ConcurrentHashMap<>();
     private final Set<LogListener> logListeners = new LinkedHashSet<>();
+    private final PluginManager pluginManager = new DefaultContextPluginManager();
     private volatile String description;
     @Deprecated
     private ErrorHandlerFactory errorHandlerFactory;
@@ -1150,4 +1152,29 @@ class DefaultCamelContextExtension implements ExtendedCamelContext {
     public String getTestExcludeRoutes() {
         return camelContext.getTestExcludeRoutes();
     }
+
+    @Override
+    public PluginManager getPluginManager() {
+        return pluginManager;
+    }
+
+    @Override
+    public <T> T getContextPlugin(Class<T> type) {
+        T ret = pluginManager.getContextPlugin(type);
+
+        // Note: this is because of interfaces like Model which are still tightly coupled with the context
+        if (ret == null) {
+            if (type.isInstance(camelContext)) {
+                return type.cast(camelContext);
+            }
+        }
+
+        return ret;
+    }
+
+    @Override
+    public <T> void addContextPlugin(Class<T> type, T module) {
+        final T addedModule = camelContext.getInternalServiceManager().addService(module);
+        pluginManager.addContextPlugin(type, addedModule);
+    }
 }
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultContextPluginManager.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultContextPluginManager.java
new file mode 100644
index 00000000000..090078ba97d
--- /dev/null
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultContextPluginManager.java
@@ -0,0 +1,63 @@
+/*
+ * 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.engine;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.PluginManager;
+
+public class DefaultContextPluginManager implements PluginManager {
+    private final Map<Class<?>, Object> extensions = new ConcurrentHashMap<>();
+
+    public DefaultContextPluginManager() {
+
+    }
+
+    @Override
+    public <T> T getContextPlugin(Class<T> type) {
+        // lookup by direct implementation
+        Object extension = extensions.get(type);
+        if (extension == null) {
+            // fallback and lookup via interfaces
+            for (Object e : extensions.values()) {
+                if (type.isInstance(e)) {
+                    return type.cast(e);
+                }
+            }
+        }
+        if (extension instanceof Supplier) {
+            extension = ((Supplier) extension).get();
+            addContextPlugin(type, (T) extension);
+        }
+        return (T) extension;
+    }
+
+    @Override
+    public <T> void addContextPlugin(Class<T> type, T module) {
+        if (module != null) {
+            try {
+                extensions.put(type, module);
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeCamelException(e);
+            }
+        }
+    }
+}
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContextExtension.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContextExtension.java
index 25ed86d82da..6125fdd7fef 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContextExtension.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContextExtension.java
@@ -75,6 +75,7 @@ import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PackageScanResourceResolver;
 import org.apache.camel.spi.PeriodTaskResolver;
 import org.apache.camel.spi.PeriodTaskScheduler;
+import org.apache.camel.spi.PluginManager;
 import org.apache.camel.spi.ProcessorExchangeFactory;
 import org.apache.camel.spi.ProcessorFactory;
 import org.apache.camel.spi.PropertiesComponent;
@@ -893,6 +894,21 @@ class LightweightCamelContextExtension implements ExtendedCamelContext {
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public PluginManager getPluginManager() {
+        return camelContext.getCamelContextExtension().getPluginManager();
+    }
+
+    @Override
+    public <T> T getContextPlugin(Class<T> type) {
+        return camelContext.getCamelContextExtension().getPluginManager().getContextPlugin(type);
+    }
+
+    @Override
+    public <T> void addContextPlugin(Class<T> type, T module) {
+        camelContext.getCamelContextExtension().addContextPlugin(type, module);
+    }
+
     Endpoint doGetEndpoint(String uri, boolean normalized, boolean prototype) {
         StringHelper.notEmpty(uri, "uri");
         // in case path has property placeholders then try to let property