You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by gg...@apache.org on 2023/06/07 12:09:35 UTC

[camel] branch main updated: [CAMEL-18189] Add documentation about support

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

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


The following commit(s) were added to refs/heads/main by this push:
     new 2d912c91799 [CAMEL-18189] Add documentation about <bean> support
2d912c91799 is described below

commit 2d912c91799a18c2c17e8617de592171ee62eee0
Author: Grzegorz Grzybek <gr...@gmail.com>
AuthorDate: Wed Jun 7 12:51:03 2023 +0200

    [CAMEL-18189] Add documentation about <bean> support
---
 .../modules/ROOT/pages/camel-jbang.adoc            | 149 +++++++++++++++++++++
 .../java/org/apache/camel/main/KameletMain.java    |   1 +
 .../org/apache/camel/main/KameletMainTest.java     |  16 +++
 .../java/org/apache/camel/main/app/Greeter.java    |  15 ++-
 .../org/apache/camel/main/xml/spring-camel2.xml    |  44 ++++++
 .../src/main/docs/java-xml-io-dsl.adoc             |  58 ++++++++
 6 files changed, 282 insertions(+), 1 deletion(-)

diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
index 94c7acdb2cf..8ef85480537 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
@@ -438,6 +438,13 @@ If you do not want Camel JBang to download over the internet, you can turn this
 camel run foo.java --download=false
 ----
 
+If you do not want Camel JBang to use your existing Maven settings file, you can use:
+
+[source,bash]
+----
+camel run foo.java --maven-settings=false
+----
+
 [#_adding_custom_jars]
 === Adding custom JARs
 
@@ -1589,6 +1596,8 @@ And these annotations should work on all runtimes
 - `@org.apache.camel.BindToRegistry` on a method to create a bean by invoking the method.
 - `@org.apache.camel.Converter` on class level to auto-register the xref:type-converter.adoc[type converters] from the class.
 
+IMPORTANT: You can use `@BeanInject` annotation to refer to existing bean annotated with `@BindToRegistry`, however this is possibe if the dependency is registered before the dependant.
+
 ==== Using Spring Boot dependency injection
 
 You can use the following Spring Boot annotations:
@@ -1607,6 +1616,146 @@ You can use the following Quarkus annotations:
 - `@org.eclipse.microprofile.config.inject.ConfigProperty` to inject a xref:using-propertyplaceholder.adoc[property placeholder]. Such as a property defined in `application.properties`.
 - `@javax.enterprise.inject.Produces` on a method to create a bean by invoking the method. `@javax.inject.Named` can be used to specify the bean id.
 
+==== Using beans in Camel XML DSL
+
+Since Camel *4.0.0*, when using xref:components:others:java-xml-io-dsl.adoc[XML DSL] we can declare additional beans in similar way as in xref:components:others:yaml-dsl.adoc[YAML DSL]. Such beans will be added to xref:registry.adoc[Registry] and can be referred to for example from routes.
+
+[source,xml]
+----
+<camel>
+
+	<bean name="beanFromMap" type="com.acme.MyBean">
+		<properties>
+			<property key="foo" value="bar" />
+		</properties>
+	</bean>
+
+</camel>
+----
+
+The properties of the bean can be defined using either nested `<property>` and `<properties>` elements or using dotted properties style, as shown in the example below:
+
+[source,xml]
+----
+<camel>
+
+    <!-- nested properties style -->
+	<bean name="beanFromMap" type="com.acme.MyBean">
+		<properties>
+			<property key="field1" value="f1_p" />
+			<property key="field2" value="f2_p" />
+			<property key="nested">
+				<properties>
+					<property key="field1" value="nf1_p" />
+					<property key="field2" value="nf2_p" />
+				</properties>
+			</property>
+		</properties>
+	</bean>
+
+    <!-- dotted properties style -->
+	<bean name="beanFromProps" type="com.acme.MyBean">
+		<properties>
+			<property key="field1" value="f1_p" />
+			<property key="field2" value="f2_p" />
+			<property key="nested.field1" value="nf1_p" />
+			<property key="nested.field2" value="nf2_p" />
+		</properties>
+	</bean>
+
+</camel>
+----
+
+==== Using Spring beans in Camel XML DSL
+
+Since Camel *4.0.0*, when using xref:components:others:java-xml-io-dsl.adoc[XML DSL], we can also declare _beans_ using Spring Beans XML namespace. All these beans will be added to xref:registry.adoc[Registry].
+
+This will not make the application managed by Spring Framework / Spring Boot. Simply Camel will leverage existing support for generic bean definition including:
+
+* dependency injection
+* constructor injection
+* dependency cycles
+* wiring existing Camel objects (like `org.apache.camel.CamelContext`)
+
+xref:components:others:java-xml-io-dsl.adoc[XML DSL] allows to use XML documents that define routes, rests and route templates. Since Camel *4.0.0* these documents may use new root XML element (either `<camel>` or `<beans>` to resemble Spring XML DSL), where other Camel elements (like `<routes>`) are contained.
+
+Here's an example `camel.xml` file, which defines both the routes and beans used (referred to) by the route definition:
+
+.camel.xml
+[source,xml]
+----
+<camel>
+
+    <beans xmlns="http://www.springframework.org/schema/beans">
+        <bean id="messageString" class="java.lang.String">
+            <constructor-arg index="0" value="Hello"/>
+        </bean>
+
+        <bean id="greeter" class="org.apache.camel.main.app.Greeter">
+            <description>Spring Bean</description>
+            <property name="message">
+                <bean class="org.apache.camel.main.app.GreeterMessage">
+                    <property name="msg" ref="messageString"/>
+                </bean>
+            </property>
+        </bean>
+    </beans>
+
+    <route id="my-route">
+        <from uri="direct:start"/>
+        <bean ref="greeter"/>
+        <to uri="mock:finish"/>
+    </route>
+
+</camel>
+----
+
+This document contains embedded `<beans>` element using Spring Beans XML namespace (`http://www.springframework.org/schema/beans`) - Camel passes this element directly to Spring `org.springframework.beans.factory.xml.XmlBeanDefinitionReader` and all read beans are used to populate xref:registry.adoc[Camel Registry].
+
+The beans declared this way may use references to some predefined Camel beans. Currently these are handled:
+
+* "CamelContext" - an instance of current `org.apache.camel.CamelContext`
+* "MainConfiguration" - an instance of `org.apache.camel.main.MainConfigurationProperties` used for `org.apache.camel.main.KameletMain`
+
+So we can use this XML fragment without actually defining what `CamelContext` is.
+
+[source,xml]
+----
+<camel>
+
+    <beans xmlns="http://www.springframework.org/schema/beans">
+        <bean id="greeter" class="org.apache.camel.main.app.Greeter">
+            <property name="camelContext" ref="CamelContext"/>
+            <!-- ... -->
+        </bean>
+    </beans>
+
+    <route id="my-route">
+        <from uri="direct:start"/>
+        <bean ref="greeter"/>
+        <to uri="mock:finish"/>
+    </route>
+
+</camel>
+----
+
+What's more, we can declare some additional beans that can affect internal mechanics of `CamelContext` being run. `org.apache.camel.main.DefaultConfigurationConfigurer` is used by xref:components:others:main.adoc[Camel Main] to configure `CamelContext` using beans found in xref:registry.adoc[Camel Registry].
+
+For example we can customize used `org.apache.camel.spi.UuidGenerator` with this XML fragment to replace UUID generator used by Camel (which defaults to `org.apache.camel.support.DefaultUuidGenerator`):
+
+[source,xml]
+----
+<camel>
+
+    <beans xmlns="http://www.springframework.org/schema/beans">
+        <bean id="customUUIDGenerator" class="org.apache.camel.support.ShortUuidGenerator" />
+    </beans>
+
+</camel>
+----
+
+That's it - Camel context will then look up for the instances of `org.apache.camel.spi.UuidGenerator` and if one is found, it'll be used by Camel.
+
 === Debugging
 
 There are two kinds of debugging:
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 e72f650bb03..955d9fe38a6 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
@@ -616,6 +616,7 @@ public class KameletMain extends MainCommandLineSupport {
         beanFactory.setAllowCircularReferences(true); // for now
 
         // 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
         Set<String> infraBeanNames = Set.of("CamelContext", "MainConfiguration");
         beanFactory.registerSingleton("CamelContext", camelContext);
         beanFactory.registerSingleton("MainConfiguration", config);
diff --git a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/KameletMainTest.java b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/KameletMainTest.java
index 33257f6c3f2..854bf77b9c0 100644
--- a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/KameletMainTest.java
+++ b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/KameletMainTest.java
@@ -54,6 +54,22 @@ public class KameletMainTest {
         });
     }
 
+    @Test
+    public void testRouteWithSpringBeansAndCamelDependencies() throws Exception {
+        doTestMain("classpath:org/apache/camel/main/xml/spring-camel2.xml", (main, camelContext) -> {
+            try {
+                MockEndpoint endpoint = camelContext.getEndpoint("mock:finish", MockEndpoint.class);
+                endpoint.expectedBodiesReceived("Hello World (" + System.identityHashCode(camelContext) + ")");
+
+                main.getCamelTemplate().sendBody("direct:start", "I'm World");
+
+                endpoint.assertIsSatisfied();
+            } catch (Exception e) {
+                fail(e.getMessage());
+            }
+        });
+    }
+
     protected void doTestMain(String includes, BiConsumer<KameletMain, CamelContext> consumer) throws Exception {
         KameletMain main = new KameletMain();
 
diff --git a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/app/Greeter.java b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/app/Greeter.java
index 1ec8ef91036..52d29755c1c 100644
--- a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/app/Greeter.java
+++ b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/app/Greeter.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.main.app;
 
+import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.util.StringHelper;
@@ -28,6 +29,8 @@ public class Greeter implements Processor {
 
     private Integer number;
 
+    private CamelContext camelContext;
+
     public void setMessage(GreeterMessage message) {
         this.message = message;
     }
@@ -40,10 +43,20 @@ public class Greeter implements Processor {
         this.bean = bean;
     }
 
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
     @Override
     public void process(Exchange exchange) throws Exception {
         String msg = exchange.getIn().getBody(String.class);
-        exchange.getIn().setBody(message.getMsg() + " " + StringHelper.after(msg, "I'm ") + " (" + number + ")");
+        if (camelContext != null) {
+            exchange.getIn().setBody(message.getMsg() + " " + StringHelper.after(msg, "I'm ")
+                                     + " (" + System.identityHashCode(camelContext) + ")");
+        } else {
+            exchange.getIn().setBody(message.getMsg() + " " + StringHelper.after(msg, "I'm ")
+                                     + " (" + number + ")");
+        }
     }
 
 }
diff --git a/dsl/camel-kamelet-main/src/test/resources/org/apache/camel/main/xml/spring-camel2.xml b/dsl/camel-kamelet-main/src/test/resources/org/apache/camel/main/xml/spring-camel2.xml
new file mode 100644
index 00000000000..e39caba291c
--- /dev/null
+++ b/dsl/camel-kamelet-main/src/test/resources/org/apache/camel/main/xml/spring-camel2.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<camel>
+
+    <beans xmlns="http://www.springframework.org/schema/beans">
+
+        <bean id="messageString" class="java.lang.String">
+            <constructor-arg index="0" value="Hello"/>
+        </bean>
+
+        <bean id="greeter" class="org.apache.camel.main.app.Greeter">
+            <property name="camelContext" ref="CamelContext"/>
+            <property name="message">
+                <bean class="org.apache.camel.main.app.GreeterMessage">
+                    <property name="msg" ref="messageString"/>
+                </bean>
+            </property>
+        </bean>
+    </beans>
+
+    <route id="r2">
+        <from uri="direct:start"/>
+        <bean ref="greeter"/>
+        <to uri="mock:finish"/>
+    </route>
+
+</camel>
diff --git a/dsl/camel-xml-io-dsl/src/main/docs/java-xml-io-dsl.adoc b/dsl/camel-xml-io-dsl/src/main/docs/java-xml-io-dsl.adoc
index 823923e973a..d2f5d7b66fc 100644
--- a/dsl/camel-xml-io-dsl/src/main/docs/java-xml-io-dsl.adoc
+++ b/dsl/camel-xml-io-dsl/src/main/docs/java-xml-io-dsl.adoc
@@ -57,6 +57,64 @@ kamel run my-route.xml
 camel run my-route.xml
 ----
 
+*Since Camel 4.0.0*
+
+It is now possible with `xml-io-dsl` to declare some beans to be bound to xref:manual::registry.adoc[Camel Registry] in similar way as with xref:yaml-dsl.adoc[YAML DSL]. Beans may be declared in XML and have their properties (also nested) defined. For example:
+
+[source,xml]
+----
+<camel>
+
+	<bean name="beanFromProps" type="com.acme.MyBean">
+		<properties>
+			<property key="field1" value="f1_p" />
+			<property key="field2" value="f2_p" />
+			<property key="nested.field1" value="nf1_p" />
+			<property key="nested.field2" value="nf2_p" />
+		</properties>
+	</bean>
+
+</camel>
+----
+
+While keeping all the benefits of fast XML parser used by `xml-io-dsl`, Camel can also process XML elements declared in other XML namespaces and process them separately. With this mechanism it is possible to include XML elements using Spring's `http://www.springframework.org/schema/beans` namespace.
+
+This brings the flexibility of Spring Beans into xref:components:others:main.adoc[Camel Main] without actually running any Spring Application Context (or Spring Boot). When elements from Spring namespace are found, they are used to populate and configure an instance of `org.springframework.beans.factory.support.DefaultListableBeanFactory` and leverage Spring dependency injection to wire the beans together. These beans are then exposed through normal xref:manual::registry.adoc[Camel Regis [...]
+
+Here's an example `camel.xml` file, which defines both the routes and beans used (referred to) by the route definition:
+
+.camel.xml
+[source,xml]
+----
+<camel>
+
+    <beans xmlns="http://www.springframework.org/schema/beans">
+        <bean id="messageString" class="java.lang.String">
+            <constructor-arg index="0" value="Hello"/>
+        </bean>
+
+        <bean id="greeter" class="org.apache.camel.main.app.Greeter">
+            <description>Spring Bean</description>
+            <property name="message">
+                <bean class="org.apache.camel.main.app.GreeterMessage">
+                    <property name="msg" ref="messageString"/>
+                </bean>
+            </property>
+        </bean>
+    </beans>
+
+    <route id="my-route">
+        <from uri="direct:start"/>
+        <bean ref="greeter"/>
+        <to uri="mock:finish"/>
+    </route>
+
+</camel>
+----
+
+A `my-route` route is referring to `greeter` bean which is defined using Spring `<bean>` element.
+
+More examples can be found in xref:manual:ROOT:camel-jbang.adoc#_using_spring_beans_in_camel_xml_dsl[Camel JBang] page.
 
 == See Also