You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by "davsclaus (via GitHub)" <gi...@apache.org> on 2023/08/30 11:59:49 UTC

[GitHub] [camel] davsclaus opened a new pull request, #11240: Blueprint

davsclaus opened a new pull request, #11240:
URL: https://github.com/apache/camel/pull/11240

   # Description
   
   <!--
   - Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
   -->
   
   # Target
   
   - [ ] I checked that the commit is targeting the correct branch (note that Camel 3 uses `camel-3.x`, whereas Camel 4 uses the `main` branch)
   
   # Tracking
   - [ ] If this is a large change, bug fix, or code improvement, I checked there is a [JIRA issue](https://issues.apache.org/jira/browse/CAMEL) filed for the change (usually before you start working on it).
   
   <!--
   # *Note*: trivial changes like, typos, minor documentation fixes and other small items do not require a JIRA issue. In this case your pull request should address just this issue, without pulling in other changes.
   -->
   
   # Apache Camel coding standards and style
   
   - [ ] I checked that each commit in the pull request has a meaningful subject line and body.
   
   <!--
   If you're unsure, you can format the pull request title like `[CAMEL-XXX] Fixes bug in camel-file component`, where you replace `CAMEL-XXX` with the appropriate JIRA issue.
   -->
   
   - [ ] I have run `mvn clean install -DskipTests` locally and I have committed all auto-generated changes
   
   <!--
   You can run the aforementioned command in your module so that the build auto-formats your code. This will also be verified as part of the checks and your PR may be rejected if if there are uncommited changes after running `mvn clean install -DskipTests`.
   
   You can learn more about the contribution guidelines at https://github.com/apache/camel/blob/main/CONTRIBUTING.md
   -->
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [camel] orpiske commented on a diff in pull request #11240: Blueprint

Posted by "orpiske (via GitHub)" <gi...@apache.org>.
orpiske commented on code in PR #11240:
URL: https://github.com/apache/camel/pull/11240#discussion_r1310419137


##########
dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlBlueprintLoadTest.java:
##########
@@ -0,0 +1,39 @@
+/*
+ * 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.dsl.xml.io;
+
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.support.PluginHelper;
+import org.junit.jupiter.api.Test;
+
+public class XmlBlueprintLoadTest {
+
+    @Test
+    public void testLoadRoutesBuilderFromXml() throws Exception {
+        try (DefaultCamelContext context = new DefaultCamelContext()) {
+            // load OSGi blueprint XML <blueprint> with embedded <camelContext>
+            Resource resource = PluginHelper.getResourceLoader(context).resolveResource(
+                    "/org/apache/camel/dsl/xml/io/blueprintRoutes.xml");
+
+            PluginHelper.getRoutesLoader(context).loadRoutes(resource);
+
+            // should be able to parse the file and not fail (camel-jbang supports creating spring beans)
+        }
+    }

Review Comment:
   I think it would be good to have assertions here. Probably move the test body to a separate method and describe the expectations using `assertDoesNotThrow` (or the opposite, if the expectation is for it to throw). 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [camel] davsclaus commented on a diff in pull request #11240: Blueprint

Posted by "davsclaus (via GitHub)" <gi...@apache.org>.
davsclaus commented on code in PR #11240:
URL: https://github.com/apache/camel/pull/11240#discussion_r1310587806


##########
dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java:
##########
@@ -0,0 +1,226 @@
+/*
+ * 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.blueprint;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+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.support.PropertyBindingSupport;
+import org.apache.camel.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Used for parsing and discovering legacy OSGi <blueprint> XML to make it runnable on camel-jbang, and for tooling to
+ * migrate this to modern Camel DSL in plain Camel XML or YAML DSL.
+ */
+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<>();
+    private final List<RegistryBeanDefinition> delayedRegistrations = new ArrayList<>();
+
+    /**
+     * Parses the XML documents and discovers blueprint beans, which will be created manually via Camel.
+     */
+    public void processBlueprintBeans(
+            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 def = createBeanModel(camelContext, id, n);
+            LOG.info("Creating bean: {}", def);
+            registerBeanDefinition(camelContext, def, true);
+        }
+
+        if (!delayedRegistrations.isEmpty()) {
+            // some of the beans were not available yet, so we have to try register them now
+            for (RegistryBeanDefinition def : delayedRegistrations) {
+                LOG.info("Creating bean (2nd-try): {}", def);
+                registerBeanDefinition(camelContext, def, false);
+            }
+            delayedRegistrations.clear();
+        }
+
+    }
+
+    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);

Review Comment:
   Its the same code from elsewhere where we grab spring placeholder -> camel placeholder.
   
   core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [camel] davsclaus commented on pull request #11240: Blueprint

Posted by "davsclaus (via GitHub)" <gi...@apache.org>.
davsclaus commented on PR #11240:
URL: https://github.com/apache/camel/pull/11240#issuecomment-1699149608

   they have different namespace so the model needs to be that naming, but the xml-io-dsl should moved the code into their own module (there is a JIRA) eg camel-xml-io-springxml camel-xml-io-blueprint
   
   Also the point is not to run 100% but to assist users to migrate away via jbang


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [camel] github-actions[bot] commented on pull request #11240: Blueprint

Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #11240:
URL: https://github.com/apache/camel/pull/11240#issuecomment-1699028441

   :star2: Thank you for your contribution to the Apache Camel project! :star2: 
   
   :camel: Maintainers, please note that first-time contributors *require manual approval* for the GitHub Actions to run.
   
   :warning: Please note that the changes on this PR may be **tested automatically** if they change components.
   
   :robot: Use the command `/component-test (camel-)component-name1 (camel-)component-name2..` to request a test from the test bot.
   
   If necessary Apache Camel Committers may access logs and test results in the job summaries!


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [camel] davsclaus merged pull request #11240: Blueprint

Posted by "davsclaus (via GitHub)" <gi...@apache.org>.
davsclaus merged PR #11240:
URL: https://github.com/apache/camel/pull/11240


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [camel] essobedo commented on pull request #11240: Blueprint

Posted by "essobedo (via GitHub)" <gi...@apache.org>.
essobedo commented on PR #11240:
URL: https://github.com/apache/camel/pull/11240#issuecomment-1699047116

   Interesting feature, I'm just wondering in which case we could need both spring and blueprint beans? Maybe replacing spring beans with something more generic like "external beans" could be good enough, WDYT?


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [camel] essobedo commented on a diff in pull request #11240: Blueprint

Posted by "essobedo (via GitHub)" <gi...@apache.org>.
essobedo commented on code in PR #11240:
URL: https://github.com/apache/camel/pull/11240#discussion_r1310344894


##########
core/camel-xml-io/src/main/java/org/apache/camel/xml/in/BaseParser.java:
##########
@@ -368,6 +367,20 @@ protected String getNextTag(String name, String name2) throws XmlPullParserExcep
         return pn;
     }
 
+    protected String getNextTag(String name, String name2, String name3) throws XmlPullParserException, IOException {
+        if (parser.nextTag() != XmlPullParser.START_TAG) {
+            throw new XmlPullParserException("Expected starting tag");
+        }
+
+        String pn = parser.getName();
+        boolean match = Objects.equals(name, pn) || Objects.equals(name2, pn) || Objects.equals(name3, pn);;

Review Comment:
   ```suggestion
           boolean match = Objects.equals(name, pn) || Objects.equals(name2, pn) || Objects.equals(name3, pn);
   ```



##########
dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java:
##########
@@ -0,0 +1,226 @@
+/*
+ * 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.blueprint;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+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.support.PropertyBindingSupport;
+import org.apache.camel.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Used for parsing and discovering legacy OSGi <blueprint> XML to make it runnable on camel-jbang, and for tooling to
+ * migrate this to modern Camel DSL in plain Camel XML or YAML DSL.
+ */
+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<>();
+    private final List<RegistryBeanDefinition> delayedRegistrations = new ArrayList<>();
+
+    /**
+     * Parses the XML documents and discovers blueprint beans, which will be created manually via Camel.
+     */
+    public void processBlueprintBeans(
+            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 def = createBeanModel(camelContext, id, n);
+            LOG.info("Creating bean: {}", def);
+            registerBeanDefinition(camelContext, def, true);
+        }
+
+        if (!delayedRegistrations.isEmpty()) {
+            // some of the beans were not available yet, so we have to try register them now
+            for (RegistryBeanDefinition def : delayedRegistrations) {
+                LOG.info("Creating bean (2nd-try): {}", def);
+                registerBeanDefinition(camelContext, def, false);
+            }
+            delayedRegistrations.clear();
+        }
+
+    }
+
+    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);

Review Comment:
   Unless I miss something the group is the same value as the match, so maybe the group is not even needed in the regular expression



##########
dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java:
##########
@@ -0,0 +1,226 @@
+/*
+ * 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.blueprint;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+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.support.PropertyBindingSupport;
+import org.apache.camel.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Used for parsing and discovering legacy OSGi <blueprint> XML to make it runnable on camel-jbang, and for tooling to
+ * migrate this to modern Camel DSL in plain Camel XML or YAML DSL.
+ */
+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<>();
+    private final List<RegistryBeanDefinition> delayedRegistrations = new ArrayList<>();
+
+    /**
+     * Parses the XML documents and discovers blueprint beans, which will be created manually via Camel.
+     */
+    public void processBlueprintBeans(
+            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 def = createBeanModel(camelContext, id, n);
+            LOG.info("Creating bean: {}", def);
+            registerBeanDefinition(camelContext, def, true);
+        }
+
+        if (!delayedRegistrations.isEmpty()) {
+            // some of the beans were not available yet, so we have to try register them now
+            for (RegistryBeanDefinition def : delayedRegistrations) {
+                LOG.info("Creating bean (2nd-try): {}", def);
+                registerBeanDefinition(camelContext, def, false);
+            }
+            delayedRegistrations.clear();
+        }
+
+    }
+
+    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);

Review Comment:
   Or it could be replaced by `Pattern.compile("\\$\\{(.*?)}")` to avoid calling `substring`



##########
dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java:
##########
@@ -0,0 +1,226 @@
+/*
+ * 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.blueprint;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+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.support.PropertyBindingSupport;
+import org.apache.camel.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Used for parsing and discovering legacy OSGi <blueprint> XML to make it runnable on camel-jbang, and for tooling to
+ * migrate this to modern Camel DSL in plain Camel XML or YAML DSL.
+ */
+public class BlueprintXmlBeansHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SpringXmlBeansHandler.class);

Review Comment:
   ```suggestion
       private static final Logger LOG = LoggerFactory.getLogger(BlueprintXmlBeansHandler.class);
   ```



##########
dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/spring/SpringXmlBeansHandler.java:
##########
@@ -0,0 +1,318 @@
+/*
+ * 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.spring;
+
+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;
+
+/**
+ * Used for parsing and discovering legacy Spring XML <beans> to make it runnable on camel-jbang, and for tooling to
+ * migrate this to modern Camel DSL in plain Camel XML or YAML DSL.
+ */
+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;

Review Comment:
   should be set and final otherwise line # 204 could throw an NPE



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [camel] davsclaus commented on a diff in pull request #11240: Blueprint

Posted by "davsclaus (via GitHub)" <gi...@apache.org>.
davsclaus commented on code in PR #11240:
URL: https://github.com/apache/camel/pull/11240#discussion_r1310596314


##########
dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/xml/blueprint/BlueprintXmlBeansHandler.java:
##########
@@ -0,0 +1,226 @@
+/*
+ * 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.blueprint;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+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.support.PropertyBindingSupport;
+import org.apache.camel.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Used for parsing and discovering legacy OSGi <blueprint> XML to make it runnable on camel-jbang, and for tooling to
+ * migrate this to modern Camel DSL in plain Camel XML or YAML DSL.
+ */
+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<>();
+    private final List<RegistryBeanDefinition> delayedRegistrations = new ArrayList<>();
+
+    /**
+     * Parses the XML documents and discovers blueprint beans, which will be created manually via Camel.
+     */
+    public void processBlueprintBeans(
+            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 def = createBeanModel(camelContext, id, n);
+            LOG.info("Creating bean: {}", def);
+            registerBeanDefinition(camelContext, def, true);
+        }
+
+        if (!delayedRegistrations.isEmpty()) {
+            // some of the beans were not available yet, so we have to try register them now
+            for (RegistryBeanDefinition def : delayedRegistrations) {
+                LOG.info("Creating bean (2nd-try): {}", def);
+                registerBeanDefinition(camelContext, def, false);
+            }
+            delayedRegistrations.clear();
+        }
+
+    }
+
+    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);

Review Comment:
   Yes good idea to move the group so its the value as-is and avoid the substring



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org