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

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

commit 38ceae15f834149eae948e5cc694a59b5ecb8b98
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Wed Aug 30 09:54:09 2023 +0200

    CAMEL-19807: Move spring XML <beans> logic to its own class
---
 .../java/org/apache/camel/main/KameletMain.java    | 280 +------------------
 .../camel/main/xml/SpringXmlBeansHandler.java      | 304 +++++++++++++++++++++
 2 files changed, 310 insertions(+), 274 deletions(-)

diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
index c2f947f032f..aaea4d2631d 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
@@ -16,24 +16,13 @@
  */
 package org.apache.camel.main;
 
-import java.io.ByteArrayInputStream;
 import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
-import java.util.StringJoiner;
 import java.util.TreeMap;
-import java.util.function.Supplier;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import org.w3c.dom.Document;
 
@@ -70,8 +59,7 @@ import org.apache.camel.main.download.PackageNameSourceLoader;
 import org.apache.camel.main.download.TypeConverterLoaderDownloadListener;
 import org.apache.camel.main.injection.AnnotationDependencyInjection;
 import org.apache.camel.main.util.ExtraFilesClassLoader;
-import org.apache.camel.model.Model;
-import org.apache.camel.model.app.RegistryBeanDefinition;
+import org.apache.camel.main.xml.SpringXmlBeansHandler;
 import org.apache.camel.spi.ClassResolver;
 import org.apache.camel.spi.CliConnector;
 import org.apache.camel.spi.CliConnectorFactory;
@@ -87,29 +75,10 @@ import org.apache.camel.spi.RoutesLoader;
 import org.apache.camel.spi.UriFactoryResolver;
 import org.apache.camel.startup.jfr.FlightRecorderStartupStepRecorder;
 import org.apache.camel.support.DefaultContextReloadStrategy;
-import org.apache.camel.support.ObjectHelper;
 import org.apache.camel.support.PluginHelper;
 import org.apache.camel.support.RouteOnDemandReloadStrategy;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.tooling.maven.MavenGav;
-import org.apache.camel.util.StringHelper;
-import org.springframework.beans.MutablePropertyValues;
-import org.springframework.beans.PropertyValue;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.CannotLoadBeanClassException;
-import org.springframework.beans.factory.SmartFactoryBean;
-import org.springframework.beans.factory.SmartInitializingSingleton;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.BeanReference;
-import org.springframework.beans.factory.config.ConstructorArgumentValues;
-import org.springframework.beans.factory.config.TypedStringValue;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.springframework.beans.factory.support.DefaultListableBeanFactory;
-import org.springframework.beans.factory.support.GenericBeanDefinition;
-import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
-import org.springframework.core.io.AbstractResource;
-import org.springframework.core.io.Resource;
-import org.springframework.core.metrics.StartupStep;
 
 /**
  * A Main class for booting up Camel with Kamelet in standalone mode.
@@ -118,8 +87,6 @@ public class KameletMain extends MainCommandLineSupport {
 
     public static final String DEFAULT_KAMELETS_LOCATION = 
"classpath:/kamelets,github:apache:camel-kamelets/kamelets";
 
-    private static final Pattern SPRING_PATTERN = 
Pattern.compile("(\\$\\{.*?})"); // non-greedy mode
-
     protected final MainRegistry registry = new MainRegistry();
     private boolean download = true;
     private String repos;
@@ -132,10 +99,7 @@ public class KameletMain extends MainCommandLineSupport {
     private DownloadListener downloadListener;
     private DependencyDownloaderClassLoader classLoader;
 
-    // when preparing spring-based beans, we may have problems loading classes 
which are provided with Java DSL
-    // that's why some beans should be processed later
-    private final List<String> delayedBeans = new LinkedList<>();
-    private Set<String> infraBeanNames;
+    private final SpringXmlBeansHandler springXmlBeansHandler = new 
SpringXmlBeansHandler();
 
     public KameletMain() {
         configureInitialProperties(DEFAULT_KAMELETS_LOCATION);
@@ -695,249 +659,17 @@ public class KameletMain extends MainCommandLineSupport {
         if (!springXmls.isEmpty()) {
             // camel-kamelet-main has access to Spring libraries, so we can 
grab XML documents representing
             // actual Spring Beans and read them using Spring's BeanFactory to 
populate Camel registry
-            processSpringBeans(camelContext, config, springXmls);
+            springXmlBeansHandler.processSpringBeans(camelContext, config, 
springXmls);
         }
         if (!blueprintXmls.isEmpty()) {
-            processBlueprintBeans(camelContext, config, blueprintXmls);
+            // TODO: blueprint
         }
     }
 
-    private void processBlueprintBeans(
-            CamelContext camelContext, MainConfigurationProperties config, 
final Map<String, Document> xmls) {
-
-        LOG.debug("Loading beans from legacy OSGi <blueprint> XML");
-        // TODO: detect and process beans
-    }
-
-    private void processSpringBeans(
-            CamelContext camelContext, MainConfigurationProperties config, 
final Map<String, Document> xmls) {
-
-        LOG.debug("Loading beans from classic Spring <beans> XML");
-
-        // we _could_ create something like 
org.apache.camel.spring.spi.ApplicationContextBeanRepository, but
-        // wrapping DefaultListableBeanFactory and use it as one of the
-        // org.apache.camel.support.DefaultRegistry.repositories, but for now 
let's use it to populate
-        // Spring registry and then copy the beans (whether the scope is)
-        final DefaultListableBeanFactory beanFactory = new 
DefaultListableBeanFactory();
-        beanFactory.setAllowCircularReferences(true); // for now
-        beanFactory.setBeanClassLoader(classLoader);
-        beanFactory.setBeanExpressionResolver((value, beanExpressionContext) 
-> extractValue(value, true));
-        registry.bind("SpringBeanFactory", beanFactory);
-
-        // register some existing beans (the list may change)
-        // would be nice to keep the documentation up to date: 
docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
-        infraBeanNames = Set.of("CamelContext", "MainConfiguration");
-        beanFactory.registerSingleton("CamelContext", camelContext);
-        beanFactory.registerSingleton("MainConfiguration", config);
-        // ...
-
-        // instead of generating an MX parser for spring-beans.xsd and use it 
to read the docs, we can simply
-        // pass w3c Documents directly to Spring
-        final XmlBeanDefinitionReader reader = new 
XmlBeanDefinitionReader(beanFactory);
-        xmls.forEach((id, doc) -> {
-            reader.registerBeanDefinitions(doc, new AbstractResource() {
-                @Override
-                public String getFilename() {
-                    if (id.startsWith("camel-xml-io-dsl-spring-xml:")) {
-                        // this is a camel bean via camel-xml-io-dsl
-                        return StringHelper.afterLast(id, ":");
-                    }
-                    return null;
-                }
-
-                @Override
-                public String getDescription() {
-                    return id;
-                }
-
-                @Override
-                public InputStream getInputStream() throws IOException {
-                    return new ByteArrayInputStream(new byte[0]);
-                }
-            });
-        });
-
-        // for full interaction between Spring ApplicationContext and its 
BeanFactory see
-        // 
org.springframework.context.support.AbstractApplicationContext.refresh()
-        // see 
org.springframework.context.support.AbstractApplicationContext.prepareBeanFactory()
 to check
-        // which extra/infra beans are added
-        beanFactory.freezeConfiguration();
-
-        List<String> beanNames = 
Arrays.asList(beanFactory.getBeanDefinitionNames());
-
-        // Trigger initialization of all non-lazy singleton beans...
-        instantiateAndRegisterBeans(beanFactory, beanNames);
-    }
-
     @Override
     protected void postProcessCamelRegistry(CamelContext camelContext, 
MainConfigurationProperties config) {
-        if (delayedBeans.isEmpty()) {
-            return;
-        }
-
-        DefaultListableBeanFactory beanFactory
-                = registry.lookupByNameAndType("SpringBeanFactory", 
DefaultListableBeanFactory.class);
-
-        // we have some beans with classes that we couldn't load before. now, 
after loading the routes
-        // we may have the needed class definitions
-        for (String beanName : delayedBeans) {
-            BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName);
-            if (bd instanceof AbstractBeanDefinition abd) {
-                if (!abd.hasBeanClass()) {
-                    Class<?> c = 
camelContext.getClassResolver().resolveClass(abd.getBeanClassName());
-                    abd.setBeanClass(c);
-                }
-            }
-        }
-
-        instantiateAndRegisterBeans(beanFactory, delayedBeans);
-    }
-
-    private void instantiateAndRegisterBeans(DefaultListableBeanFactory 
beanFactory, List<String> beanNames) {
-        List<String> instantiatedBeanNames = new LinkedList<>();
-
-        for (String beanName : beanNames) {
-            BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName);
-            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
-                try {
-                    if (beanFactory.isFactoryBean(beanName)) {
-                        Object bean = 
beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
-                        if (bean instanceof SmartFactoryBean<?> 
smartFactoryBean && smartFactoryBean.isEagerInit()) {
-                            beanFactory.getBean(beanName);
-                            instantiatedBeanNames.add(beanName);
-                        }
-                    } else {
-                        beanFactory.getBean(beanName);
-                        instantiatedBeanNames.add(beanName);
-                    }
-                } catch (CannotLoadBeanClassException ignored) {
-                    // we'll try to resolve later
-                    delayedBeans.add(beanName);
-                }
-            }
-        }
-
-        // Trigger post-initialization callback for all applicable beans...
-        for (String beanName : instantiatedBeanNames) {
-            Object singletonInstance = beanFactory.getSingleton(beanName);
-            if (singletonInstance instanceof SmartInitializingSingleton 
smartSingleton) {
-                StartupStep smartInitialize = 
beanFactory.getApplicationStartup()
-                        .start("spring.beans.smart-initialize")
-                        .tag("beanName", beanName);
-                smartSingleton.afterSingletonsInstantiated();
-                smartInitialize.end();
-            }
-        }
-
-        for (String name : instantiatedBeanNames) {
-            if (infraBeanNames.contains(name)) {
-                continue;
-            }
-            BeanDefinition def = beanFactory.getBeanDefinition(name);
-            if (def.isSingleton()) {
-                // just grab the singleton and put into registry
-                registry.bind(name, beanFactory.getBean(name));
-            } else {
-                // rely on the bean factory to implement prototype scope
-                registry.bind(name, (Supplier<Object>) () -> 
beanFactory.getBean(name));
-            }
-
-            // register bean into model (as a BeanRegistry that allows Camel 
DSL to know about these beans)
-            Model model = 
camelContext.getCamelContextExtension().getContextPlugin(Model.class);
-            if (model != null) {
-                RegistryBeanDefinition rrd = new RegistryBeanDefinition();
-                if (def instanceof GenericBeanDefinition gbd) {
-                    // set camel resource to refer to the source file
-                    Resource res = gbd.getResource();
-                    if (res != null) {
-                        String fn = res.getFilename();
-                        if (fn != null) {
-                            
rrd.setResource(camelContext.getCamelContextExtension().getContextPlugin(ResourceLoader.class)
-                                    .resolveResource("file:" + fn));
-                        }
-                    }
-                }
-                rrd.setType(def.getBeanClassName());
-                rrd.setName(name);
-                model.addRegistryBean(rrd);
-
-                // constructor arguments
-                ConstructorArgumentValues ctr = 
def.getConstructorArgumentValues();
-                StringJoiner sj = new StringJoiner(", ");
-                for (ConstructorArgumentValues.ValueHolder v : 
ctr.getIndexedArgumentValues().values()) {
-                    Object val = v.getValue();
-                    if (val instanceof TypedStringValue tsv) {
-                        sj.add("'" + extractValue(tsv.getValue(), false) + 
"'");
-                    } else if (val instanceof BeanReference br) {
-                        sj.add("'#bean:" + br.getBeanName() + "'");
-                    }
-                }
-                if (sj.length() > 0) {
-                    rrd.setType("#class:" + def.getBeanClassName() + "(" + sj 
+ ")");
-                }
-                // property values
-                if (def.hasPropertyValues()) {
-                    Map<String, Object> properties = new LinkedHashMap<>();
-                    rrd.setProperties(properties);
-
-                    MutablePropertyValues values = def.getPropertyValues();
-                    for (PropertyValue v : values) {
-                        String key = v.getName();
-                        PropertyValue src = v.getOriginalPropertyValue();
-                        Object val = src.getValue();
-                        if (val instanceof TypedStringValue tsv) {
-                            properties.put(key, extractValue(tsv.getValue(), 
false));
-                        } else if (val instanceof BeanReference br) {
-                            properties.put(key, "#bean:" + br.getBeanName());
-                        } else if (val instanceof List) {
-                            int i = 0;
-                            Iterator<?> it = ObjectHelper.createIterator(val);
-                            while (it.hasNext()) {
-                                String k = key + "[" + i + "]";
-                                val = it.next();
-                                if (val instanceof TypedStringValue tsv) {
-                                    properties.put(k, 
extractValue(tsv.getValue(), false));
-                                } else if (val instanceof BeanReference br) {
-                                    properties.put(k, "#bean:" + 
br.getBeanName());
-                                }
-                                i++;
-                            }
-                        } else if (val instanceof Map) {
-                            Map<TypedStringValue, Object> map = (Map) val;
-                            for (Map.Entry<TypedStringValue, Object> entry : 
map.entrySet()) {
-                                String k = key + "[" + 
entry.getKey().getValue() + "]";
-                                val = entry.getValue();
-                                if (val instanceof TypedStringValue tsv) {
-                                    properties.put(k, 
extractValue(tsv.getValue(), false));
-                                } else if (val instanceof BeanReference br) {
-                                    properties.put(k, "#bean:" + 
br.getBeanName());
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    protected String extractValue(String val, boolean resolve) {
-        // spring placeholder prefix
-        if (val != null && val.contains("${")) {
-            Matcher matcher = SPRING_PATTERN.matcher(val);
-            while (matcher.find()) {
-                String group = matcher.group(1);
-                String replace = "{{" + group.substring(2, group.length() - 1) 
+ "}}";
-                val = matcher.replaceFirst(replace);
-                // we changed so reset matcher so it can find more
-                matcher.reset(val);
-            }
-        }
-
-        if (resolve && camelContext != null) {
-            // if running camel then resolve property placeholders from beans
-            val = camelContext.resolvePropertyPlaceholders(val);
-        }
-        return val;
+        springXmlBeansHandler.createAndRegisterBeans(camelContext);
+        // TODO: blueprint
     }
 
     @Override
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/SpringXmlBeansHandler.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/SpringXmlBeansHandler.java
new file mode 100644
index 00000000000..fba5be91821
--- /dev/null
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/SpringXmlBeansHandler.java
@@ -0,0 +1,304 @@
+/*
+ * 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.main.xml;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.w3c.dom.Document;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.main.MainConfigurationProperties;
+import org.apache.camel.model.Model;
+import org.apache.camel.model.app.RegistryBeanDefinition;
+import org.apache.camel.spi.ResourceLoader;
+import org.apache.camel.support.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.CannotLoadBeanClassException;
+import org.springframework.beans.factory.SmartFactoryBean;
+import org.springframework.beans.factory.SmartInitializingSingleton;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanReference;
+import org.springframework.beans.factory.config.ConstructorArgumentValues;
+import org.springframework.beans.factory.config.TypedStringValue;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.GenericBeanDefinition;
+import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
+import org.springframework.core.io.AbstractResource;
+import org.springframework.core.io.Resource;
+import org.springframework.core.metrics.StartupStep;
+
+public class SpringXmlBeansHandler {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(SpringXmlBeansHandler.class);
+    private static final Pattern SPRING_PATTERN = 
Pattern.compile("(\\$\\{.*?})"); // non-greedy mode
+
+    // when preparing spring-based beans, we may have problems loading classes 
which are provided with Java DSL
+    // that's why some beans should be processed later
+    private final List<String> delayedBeans = new LinkedList<>();
+    private Set<String> infraBeanNames;
+
+    public void createAndRegisterBeans(CamelContext camelContext) {
+        if (delayedBeans.isEmpty()) {
+            return;
+        }
+
+        DefaultListableBeanFactory beanFactory
+                = 
camelContext.getRegistry().lookupByNameAndType("SpringBeanFactory", 
DefaultListableBeanFactory.class);
+
+        // we have some beans with classes that we couldn't load before. now, 
after loading the routes
+        // we may have the needed class definitions
+        for (String beanName : delayedBeans) {
+            BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName);
+            if (bd instanceof AbstractBeanDefinition abd) {
+                if (!abd.hasBeanClass()) {
+                    Class<?> c = 
camelContext.getClassResolver().resolveClass(abd.getBeanClassName());
+                    abd.setBeanClass(c);
+                }
+            }
+        }
+
+        instantiateAndRegisterBeans(camelContext, beanFactory, delayedBeans);
+    }
+
+    public void processSpringBeans(
+            CamelContext camelContext, MainConfigurationProperties config, 
final Map<String, Document> xmls) {
+
+        LOG.debug("Loading beans from classic Spring <beans> XML");
+
+        // we _could_ create something like 
org.apache.camel.spring.spi.ApplicationContextBeanRepository, but
+        // wrapping DefaultListableBeanFactory and use it as one of the
+        // org.apache.camel.support.DefaultRegistry.repositories, but for now 
let's use it to populate
+        // Spring registry and then copy the beans (whether the scope is)
+        final DefaultListableBeanFactory beanFactory = new 
DefaultListableBeanFactory();
+        beanFactory.setAllowCircularReferences(true); // for now
+        
beanFactory.setBeanClassLoader(camelContext.getApplicationContextClassLoader());
+        beanFactory.setBeanExpressionResolver((value, beanExpressionContext) 
-> extractValue(camelContext, value, true));
+        camelContext.getRegistry().bind("SpringBeanFactory", beanFactory);
+
+        // register some existing beans (the list may change)
+        // would be nice to keep the documentation up to date: 
docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+        infraBeanNames = Set.of("CamelContext", "MainConfiguration");
+        beanFactory.registerSingleton("CamelContext", camelContext);
+        beanFactory.registerSingleton("MainConfiguration", config);
+        // ...
+
+        // instead of generating an MX parser for spring-beans.xsd and use it 
to read the docs, we can simply
+        // pass w3c Documents directly to Spring
+        final XmlBeanDefinitionReader reader = new 
XmlBeanDefinitionReader(beanFactory);
+        xmls.forEach((id, doc) -> {
+            reader.registerBeanDefinitions(doc, new AbstractResource() {
+                @Override
+                public String getFilename() {
+                    if (id.startsWith("camel-xml-io-dsl-spring-xml:")) {
+                        // this is a camel bean via camel-xml-io-dsl
+                        return StringHelper.afterLast(id, ":");
+                    }
+                    return null;
+                }
+
+                @Override
+                public String getDescription() {
+                    return id;
+                }
+
+                @Override
+                public InputStream getInputStream() throws IOException {
+                    return new ByteArrayInputStream(new byte[0]);
+                }
+            });
+        });
+
+        // for full interaction between Spring ApplicationContext and its 
BeanFactory see
+        // 
org.springframework.context.support.AbstractApplicationContext.refresh()
+        // see 
org.springframework.context.support.AbstractApplicationContext.prepareBeanFactory()
 to check
+        // which extra/infra beans are added
+        beanFactory.freezeConfiguration();
+
+        List<String> beanNames = 
Arrays.asList(beanFactory.getBeanDefinitionNames());
+
+        // Trigger initialization of all non-lazy singleton beans...
+        instantiateAndRegisterBeans(camelContext, beanFactory, beanNames);
+    }
+
+    private void instantiateAndRegisterBeans(
+            CamelContext camelContext, DefaultListableBeanFactory beanFactory, 
List<String> beanNames) {
+        List<String> instantiatedBeanNames = new LinkedList<>();
+
+        for (String beanName : beanNames) {
+            BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName);
+            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
+                try {
+                    if (beanFactory.isFactoryBean(beanName)) {
+                        Object bean = 
beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
+                        if (bean instanceof SmartFactoryBean<?> 
smartFactoryBean && smartFactoryBean.isEagerInit()) {
+                            beanFactory.getBean(beanName);
+                            instantiatedBeanNames.add(beanName);
+                        }
+                    } else {
+                        beanFactory.getBean(beanName);
+                        instantiatedBeanNames.add(beanName);
+                    }
+                } catch (CannotLoadBeanClassException ignored) {
+                    // we'll try to resolve later
+                    delayedBeans.add(beanName);
+                }
+            }
+        }
+
+        // Trigger post-initialization callback for all applicable beans...
+        for (String beanName : instantiatedBeanNames) {
+            Object singletonInstance = beanFactory.getSingleton(beanName);
+            if (singletonInstance instanceof SmartInitializingSingleton 
smartSingleton) {
+                StartupStep smartInitialize = 
beanFactory.getApplicationStartup()
+                        .start("spring.beans.smart-initialize")
+                        .tag("beanName", beanName);
+                smartSingleton.afterSingletonsInstantiated();
+                smartInitialize.end();
+            }
+        }
+
+        for (String name : instantiatedBeanNames) {
+            if (infraBeanNames.contains(name)) {
+                continue;
+            }
+            BeanDefinition def = beanFactory.getBeanDefinition(name);
+            if (def.isSingleton()) {
+                // just grab the singleton and put into registry
+                camelContext.getRegistry().bind(name, 
beanFactory.getBean(name));
+            } else {
+                // rely on the bean factory to implement prototype scope
+                camelContext.getRegistry().bind(name, (Supplier<Object>) () -> 
beanFactory.getBean(name));
+            }
+
+            // register bean into model (as a BeanRegistry that allows Camel 
DSL to know about these beans)
+            Model model = 
camelContext.getCamelContextExtension().getContextPlugin(Model.class);
+            if (model != null) {
+                RegistryBeanDefinition rrd = new RegistryBeanDefinition();
+                if (def instanceof GenericBeanDefinition gbd) {
+                    // set camel resource to refer to the source file
+                    Resource res = gbd.getResource();
+                    if (res != null) {
+                        String fn = res.getFilename();
+                        if (fn != null) {
+                            
rrd.setResource(camelContext.getCamelContextExtension().getContextPlugin(ResourceLoader.class)
+                                    .resolveResource("file:" + fn));
+                        }
+                    }
+                }
+                rrd.setType(def.getBeanClassName());
+                rrd.setName(name);
+                model.addRegistryBean(rrd);
+
+                // constructor arguments
+                ConstructorArgumentValues ctr = 
def.getConstructorArgumentValues();
+                StringJoiner sj = new StringJoiner(", ");
+                for (ConstructorArgumentValues.ValueHolder v : 
ctr.getIndexedArgumentValues().values()) {
+                    Object val = v.getValue();
+                    if (val instanceof TypedStringValue tsv) {
+                        sj.add("'" + extractValue(camelContext, 
tsv.getValue(), false) + "'");
+                    } else if (val instanceof BeanReference br) {
+                        sj.add("'#bean:" + br.getBeanName() + "'");
+                    }
+                }
+                if (sj.length() > 0) {
+                    rrd.setType("#class:" + def.getBeanClassName() + "(" + sj 
+ ")");
+                }
+                // property values
+                if (def.hasPropertyValues()) {
+                    Map<String, Object> properties = new LinkedHashMap<>();
+                    rrd.setProperties(properties);
+
+                    MutablePropertyValues values = def.getPropertyValues();
+                    for (PropertyValue v : values) {
+                        String key = v.getName();
+                        PropertyValue src = v.getOriginalPropertyValue();
+                        Object val = src.getValue();
+                        if (val instanceof TypedStringValue tsv) {
+                            properties.put(key, extractValue(camelContext, 
tsv.getValue(), false));
+                        } else if (val instanceof BeanReference br) {
+                            properties.put(key, "#bean:" + br.getBeanName());
+                        } else if (val instanceof List) {
+                            int i = 0;
+                            Iterator<?> it = ObjectHelper.createIterator(val);
+                            while (it.hasNext()) {
+                                String k = key + "[" + i + "]";
+                                val = it.next();
+                                if (val instanceof TypedStringValue tsv) {
+                                    properties.put(k, 
extractValue(camelContext, tsv.getValue(), false));
+                                } else if (val instanceof BeanReference br) {
+                                    properties.put(k, "#bean:" + 
br.getBeanName());
+                                }
+                                i++;
+                            }
+                        } else if (val instanceof Map) {
+                            Map<TypedStringValue, Object> map = (Map) val;
+                            for (Map.Entry<TypedStringValue, Object> entry : 
map.entrySet()) {
+                                String k = key + "[" + 
entry.getKey().getValue() + "]";
+                                val = entry.getValue();
+                                if (val instanceof TypedStringValue tsv) {
+                                    properties.put(k, 
extractValue(camelContext, tsv.getValue(), false));
+                                } else if (val instanceof BeanReference br) {
+                                    properties.put(k, "#bean:" + 
br.getBeanName());
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    protected String extractValue(CamelContext camelContext, String val, 
boolean resolve) {
+        // spring placeholder prefix
+        if (val != null && val.contains("${")) {
+            Matcher matcher = SPRING_PATTERN.matcher(val);
+            while (matcher.find()) {
+                String group = matcher.group(1);
+                String replace = "{{" + group.substring(2, group.length() - 1) 
+ "}}";
+                val = matcher.replaceFirst(replace);
+                // we changed so reset matcher so it can find more
+                matcher.reset(val);
+            }
+        }
+
+        if (resolve && camelContext != null) {
+            // if running camel then resolve property placeholders from beans
+            val = camelContext.resolvePropertyPlaceholders(val);
+        }
+        return val;
+    }
+
+}

Reply via email to