You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/08/30 11:59:49 UTC

[camel] 05/06: camel-jbang - Allow to load OSGi with embedded

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 c3813a64eb575cff7cbaca0abbcb5c568f09f152
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Aug 30 13:31:57 2023 +0200

    camel-jbang - Allow to load OSGi <blueprint> with embedded <camelContext>
---
 .../java/org/apache/camel/main/util/XmlHelper.java |  12 ++
 .../xml/blueprint/BlueprintXmlBeansHandler.java    | 129 +++++++++++++++++++++
 .../main/xml/spring/SpringXmlBeansHandler.java     |   8 +-
 3 files changed, 145 insertions(+), 4 deletions(-)

diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/util/XmlHelper.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/util/XmlHelper.java
index 52b843abfcf..0a362f18334 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/util/XmlHelper.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/util/XmlHelper.java
@@ -20,6 +20,8 @@ import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
+import org.w3c.dom.Node;
+
 import org.apache.camel.util.ObjectHelper;
 
 public final class XmlHelper {
@@ -60,4 +62,14 @@ public final class XmlHelper {
         return factory;
     }
 
+    public static String getAttribute(Node node, String key) {
+        if (node != null && node.hasAttributes()) {
+            Node attr = node.getAttributes().getNamedItem(key);
+            if (attr != null) {
+                return attr.getNodeValue();
+            }
+        }
+        return null;
+    }
+
 }
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java
index 959dd09a610..9316a5df26a 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java
@@ -16,13 +16,25 @@
  */
 package org.apache.camel.main.xml.blueprint;
 
+import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.StringJoiner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.main.MainConfigurationProperties;
+import org.apache.camel.main.util.XmlHelper;
 import org.apache.camel.main.xml.spring.SpringXmlBeansHandler;
+import org.apache.camel.model.Model;
+import org.apache.camel.model.app.RegistryBeanDefinition;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceLoader;
+import org.apache.camel.util.StringHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,6 +45,12 @@ import org.slf4j.LoggerFactory;
 public class BlueprintXmlBeansHandler {
 
     private static final Logger LOG = LoggerFactory.getLogger(SpringXmlBeansHandler.class);
+    private static final Pattern BLUEPRINT_PATTERN = Pattern.compile("(\\$\\{.*?})"); // non-greedy mode
+
+    // when preparing blueprint-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 Map<String, Node> delayedBeans = new LinkedHashMap<>();
+    private final Map<String, Resource> resources = new LinkedHashMap<>();
 
     /**
      * Parses the XML documents and discovers blueprint beans, which will be created manually via Camel.
@@ -41,13 +59,124 @@ public class BlueprintXmlBeansHandler {
             CamelContext camelContext, MainConfigurationProperties config, final Map<String, Document> xmls) {
 
         LOG.debug("Loading beans from classic OSGi <blueprint> XML");
+
+        xmls.forEach((id, doc) -> {
+            if (id.startsWith("camel-xml-io-dsl-blueprint-xml:")) {
+                // this is a camel bean via camel-xml-io-dsl
+                String fileName = StringHelper.afterLast(id, ":");
+                discoverBeans(camelContext, fileName, doc);
+            }
+        });
     }
 
     /**
      * Invoked at later stage to create and register Blueprint beans into Camel {@link org.apache.camel.spi.Registry}.
      */
     public void createAndRegisterBeans(CamelContext camelContext) {
+        LOG.info("Discovered {} OSGi <blueprint> XML beans", delayedBeans.size());
+
+        for (Map.Entry<String, Node> entry : delayedBeans.entrySet()) {
+            String id = entry.getKey();
+            Node n = entry.getValue();
+            RegistryBeanDefinition bean = createBeanModel(camelContext, id, n);
+            // create bean and register to camel
+
+            LOG.info("Creating bean: {}", bean);
+            // TODO: create bean from the model
+
+            // register bean into model (as a BeanRegistry that allows Camel DSL to know about these beans)
+            Model model = camelContext.getCamelContextExtension().getContextPlugin(Model.class);
+            model.addRegistryBean(bean);
+        }
+    }
+
+    private RegistryBeanDefinition createBeanModel(CamelContext camelContext, String name, Node node) {
+        RegistryBeanDefinition rrd = new RegistryBeanDefinition();
+        rrd.setResource(resources.get(name));
+        rrd.setType(XmlHelper.getAttribute(node, "class"));
+        rrd.setName(name);
+
+        // constructor arguments
+        StringJoiner sj = new StringJoiner(", ");
+        NodeList props = node.getChildNodes();
+        for (int i = 0; i < props.getLength(); i++) {
+            Node child = props.item(i);
+            // assume the args are in order (1, 2)
+            if ("argument".equals(child.getNodeName())) {
+                String val = XmlHelper.getAttribute(child, "value");
+                String ref = XmlHelper.getAttribute(child, "ref");
+                if (val != null) {
+                    sj.add("'" + extractValue(camelContext, val, false) + "'");
+                } else if (ref != null) {
+                    sj.add("'#bean:" + extractValue(camelContext, ref, false) + "'");
+                }
+            }
+        }
+        if (sj.length() > 0) {
+            rrd.setType("#class:" + rrd.getType() + "(" + sj + ")");
+        }
+
+        // property values
+        Map<String, Object> properties = new LinkedHashMap<>();
+        props = node.getChildNodes();
+        for (int i = 0; i < props.getLength(); i++) {
+            Node child = props.item(i);
+            // assume the args are in order (1, 2)
+            if ("property".equals(child.getNodeName())) {
+                String key = XmlHelper.getAttribute(child, "name");
+                String val = XmlHelper.getAttribute(child, "value");
+                String ref = XmlHelper.getAttribute(child, "ref");
+
+                // TODO: List/Map properties
+                if (key != null && val != null) {
+                    properties.put(key, extractValue(camelContext, val, false));
+                } else if (key != null && ref != null) {
+                    properties.put(key, extractValue(camelContext, "#bean:" + ref, false));
+                }
+            }
+        }
+        if (!properties.isEmpty()) {
+            rrd.setProperties(properties);
+        }
+
+        return rrd;
+    }
+
+    private void discoverBeans(CamelContext camelContext, String fileName, Document dom) {
+        Resource resource = camelContext.getCamelContextExtension().getContextPlugin(ResourceLoader.class)
+                .resolveResource("file:" + fileName);
+
+        NodeList beans = dom.getElementsByTagName("bean");
+        for (int i = 0; i < beans.getLength(); i++) {
+            Node n = beans.item(i);
+            if (n.hasAttributes()) {
+                String id = XmlHelper.getAttribute(n, "id");
+                if (id != null) {
+                    delayedBeans.put(id, n);
+                    resources.put(id, resource);
+                }
+            }
+        }
+    }
+
+    protected String extractValue(CamelContext camelContext, String val, boolean resolve) {
+        // blueprint placeholder prefix
+        if (val != null && val.contains("${")) {
+            Matcher matcher = BLUEPRINT_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;
     }
 
 }
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/spring/SpringXmlBeansHandler.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/spring/SpringXmlBeansHandler.java
index f84ae377082..4473c26a98a 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/spring/SpringXmlBeansHandler.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/spring/SpringXmlBeansHandler.java
@@ -245,7 +245,7 @@ public class SpringXmlBeansHandler {
                 if (val instanceof TypedStringValue tsv) {
                     sj.add("'" + extractValue(camelContext, tsv.getValue(), false) + "'");
                 } else if (val instanceof BeanReference br) {
-                    sj.add("'#bean:" + br.getBeanName() + "'");
+                    sj.add("'#bean:" + extractValue(camelContext, br.getBeanName(), false) + "'");
                 }
             }
             if (sj.length() > 0) {
@@ -264,7 +264,7 @@ public class SpringXmlBeansHandler {
                     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());
+                        properties.put(key, "#bean:" + extractValue(camelContext, br.getBeanName(), false));
                     } else if (val instanceof List) {
                         int i = 0;
                         Iterator<?> it = ObjectHelper.createIterator(val);
@@ -274,7 +274,7 @@ public class SpringXmlBeansHandler {
                             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());
+                                properties.put(k, "#bean:" + extractValue(camelContext, br.getBeanName(), false));
                             }
                             i++;
                         }
@@ -286,7 +286,7 @@ public class SpringXmlBeansHandler {
                             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());
+                                properties.put(k, "#bean:" + extractValue(camelContext, br.getBeanName(), false));
                             }
                         }
                     }