2.7. Property Placeholders
Overview
The property placeholders feature can be used to substitute strings into various contexts (such as endpoint URIs and attributes in XML DSL elements), where the placeholder settings are stored in Java properties files. This feature can be useful, if you want to share settings between different Apache Camel applications or if you want to centralize certain configuration settings.
For example, the following route sends requests to a Web server, whose host and port are substituted by the placeholders,
{{remote.host}}
and {{remote.port}}
:
from("direct:start").to("http://{{remote.host}}:{{remote.port}}");
The placeholder values are defined in a Java properties file, as follows:
# Java properties file remote.host=myserver.com remote.port=8080
Note
Property Placeholders support an encoding option that enables you to read the
.properties
file, using a specific character set such as UTF-8. However, by default, it implements the ISO-8859-1 character set.
Apache Camel using the
PropertyPlaceholders
support the following:
- Specify the default value together with the key to lookup.
- No need to define the
PropertiesComponent
, if all the placeholder keys consist of default values, which are to be used. - Use third-party functions to lookup the property values. It enables you to implement your own logic.NoteProvide three out of the box functions to lookup values from OS environmental variable, JVM system properties, or the service name idiom.
Property files
Property settings are stored in one or more Java properties files and must conform to the standard Java properties file format. Each property setting appears on its own line, in the format
Key=Value
. Lines with #
or !
as the first non-blank character are treated as comments.
For example, a property file could have content as shown in Example 2.4, “Sample Property File”.
Example 2.4. Sample Property File
# Property placeholder settings # (in Java properties file format) cool.end=mock:result cool.result=result cool.concat=mock:{{cool.result}} cool.start=direct:cool cool.showid=true cheese.end=mock:cheese cheese.quote=Camel rocks cheese.type=Gouda bean.foo=foo bean.bar=bar
Resolving properties
The properties component must be configured with the locations of one or more property files before you can start using it in route definitions. You must provide the property values using one of the following resolvers:
-
classpath:PathName,PathName,...
- (Default) Specifies locations on the classpath, where PathName is a file pathname delimited using forward slashes.
-
file:PathName,PathName,...
- Specifies locations on the file system, where PathName is a file pathname delimited using forward slashes.
-
ref:BeanID
- Specifies the ID of a
java.util.Properties
object in the registry. -
blueprint:BeanID
- Specifies the ID of a
cm:property-placeholder
bean, which is used in the context of an OSGi blueprint file to access properties defined in the OSGi Configuration Admin service. For details, see the section called “Integration with OSGi blueprint property placeholders”.
For example, to specify the
com/fusesource/cheese.properties
property file and the com/fusesource/bar.properties
property file, both located on the classpath, you would use the following location string:
com/fusesource/cheese.properties,com/fusesource/bar.properties
Note
You can omit the
classpath:
prefix in this example, because the classpath resolver is used by default.
Specifying locations using system properties and environment variables
You can embed Java system properties and O/S environment variables in a location PathName.
Java system properties can be embedded in a location resolver using the syntax,
${PropertyName}
. For example, if the root directory of Red Hat JBoss Fuse is stored in the Java system property, karaf.home
, you could embed that directory value in a file location, as follows:
file:${karaf.home}/etc/foo.properties
O/S environment variables can be embedded in a location resolver using the syntax,
${env:VarName}
. For example, if the root directory of JBoss Fuse is stored in the environment variable, SMX_HOME
, you could embed that directory value in a file location, as follows:
file:${env:SMX_HOME}/etc/foo.properties
Configuring the properties component
Before you can start using property placeholders, you must configure the properties component, specifying the locations of one or more property files.
In the Java DSL, you can configure the properties component with the property file locations, as follows:
// Java import org.apache.camel.component.properties.PropertiesComponent; ... PropertiesComponent pc = new PropertiesComponent(); pc.setLocation("com/fusesource/cheese.properties,com/fusesource/bar.properties"); context.addComponent("properties", pc);
As shown in the
addComponent()
call, the name of the properties component must be set to properties
.
In the XML DSL, you can configure the properties component using the dedicated
propertyPlacholder
element, as follows:
<camelContext ...> <propertyPlaceholder id="properties" location="com/fusesource/cheese.properties,com/fusesource/bar.properties" /> </camelContext>
If you want the properties component to ignore any missing
.properties
files when it is being initialized, you can set the ignoreMissingLocation
option to true
(normally, a missing .properties
file would result in an error being raised).
Additionally, if you want the properties component to ignore any missing locations that are specified using Java system properties or O/S environment variables, you can set the
ignoreMissingLocation
option to true
.
Placeholder syntax
After it is configured, the property component automatically substitutes placeholders (in the appropriate contexts). The syntax of a placeholder depends on the context, as follows:
- In endpoint URIs and in Spring XML files—the placeholder is specified as
{{Key}}
. - When setting XML DSL attributes—
xs:string
attributes are set using the following syntax:AttributeName="{{Key}}"
Other attribute types (for example,xs:int
orxs:boolean
) must be set using the following syntax:prop:AttributeName="Key"
Whereprop
is associated with thehttp://camel.apache.org/schema/placeholder
namespace. - When setting Java DSL EIP options—to set an option on an Enterprise Integration Pattern (EIP) command in the Java DSL, add a
placeholder()
clause like the following to the fluent DSL:.placeholder("OptionName", "Key")
- In Simple language expressions—the placeholder is specified as
${properties:Key}
.
Substitution in endpoint URIs
Wherever an endpoint URI string appears in a route, the first step in parsing the endpoint URI is to apply the property placeholder parser. The placeholder parser automatically substitutes any property names appearing between double braces,
{{Key}}
. For example, given the property settings shown in Example 2.4, “Sample Property File”, you could define a route as follows:
from("{{cool.start}}") .to("log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}") .to("mock:{{cool.result}}");
By default, the placeholder parser looks up the
properties
bean ID in the registry to find the property component. If you prefer, you can explicitly specify the scheme in the endpoint URIs. For example, by prefixing properties:
to each of the endpoint URIs, you can define the following equivalent route:
from("properties:{{cool.start}}") .to("properties:log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}") .to("properties:mock:{{cool.result}}");
When specifying the scheme explicitly, you also have the option of specifying options to the properties component. For example, to override the property file location, you could set the
location
option as follows:
from("direct:start").to("properties:{{bar.end}}?location=com/mycompany/bar.properties");
Substitution in Spring XML files
You can also use property placeholders in the XML DSL, for setting various attributes of the DSL elements. In this context, the placholder syntax also uses double braces,
{{Key}}
. For example, you could define a jmxAgent
element using property placeholders, as follows:
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> <propertyPlaceholder id="properties" location="org/apache/camel/spring/jmx.properties"/> <!-- we can use property placeholders when we define the JMX agent --> <jmxAgent id="agent" registryPort="{{myjmx.port}}" usePlatformMBeanServer="{{myjmx.usePlatform}}" createConnector="true" statisticsLevel="RoutesOnly" /> <route> <from uri="seda:start"/> <to uri="mock:result"/> </route> </camelContext>
Substitution of XML DSL attribute values
You can use the regular placeholder syntax for specifying attribute values of
xs:string
type—for example, <jmxAgent registryPort="{{myjmx.port}}" ...>
. But for attributes of any other type (for example, xs:int
or xs:boolean
), you must use the special syntax, prop:AttributeName="Key"
.
For example, given that a property file defines the
stop.flag
property to have the value, true
, you can use this property to set the stopOnException
boolean attribute, as follows:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:prop="http://camel.apache.org/schema/placeholder" ... > <bean id="illegal" class="java.lang.IllegalArgumentException"> <constructor-arg index="0" value="Good grief!"/> </bean> <camelContext xmlns="http://camel.apache.org/schema/spring"> <propertyPlaceholder id="properties" location="classpath:org/apache/camel/component/properties/myprop.properties" xmlns="http://camel.apache.org/schema/spring"/> <route> <from uri="direct:start"/> <multicast prop:stopOnException="stop.flag"> <to uri="mock:a"/> <throwException ref="damn"/> <to uri="mock:b"/> </multicast> </route> </camelContext> </beans>
Important
The
prop
prefix must be explicitly assigned to the http://camel.apache.org/schema/placeholder
namespace in your Spring file, as shown in the beans
element of the preceding example.
Substitution of Java DSL EIP options
When invoking an EIP command in the Java DSL, you can set any EIP option using the value of a property placeholder, by adding a sub-clause of the form,
placeholder("OptionName", "Key")
.
For example, given that a property file defines the
stop.flag
property to have the value, true
, you can use this property to set the stopOnException
option of the multicast EIP, as follows:
from("direct:start") .multicast().placeholder("stopOnException", "stop.flag") .to("mock:a").throwException(new IllegalAccessException("Damn")).to("mock:b");
Substitution in Simple language expressions
You can also substitute property placeholders in Simple language expressions, but in this case the syntax of the placeholder is
${properties:Key}
. For example, you can substitute the cheese.quote
placeholder inside a Simple expression, as follows:
from("direct:start") .transform().simple("Hi ${body} do you think ${properties:cheese.quote}?");
You can specify a default value for the property, using the syntax,
${properties:Key:DefaultVal}
. For example:
from("direct:start") .transform().simple("Hi ${body} do you think ${properties:cheese.quote:cheese is good}?");
It is also possible to override the location of the property file using the syntax,
${properties-location:Location:Key}
. For example, to substitute the bar.quote
placeholder using the settings from the com/mycompany/bar.properties
property file, you can define a Simple expression as follows:
from("direct:start") .transform().simple("Hi ${body}. ${properties-location:com/mycompany/bar.properties:bar.quote}.");
Using Property Placeholders in the XML DSL
In older releases, the
xs:string
type attributes were used to support placeholders in the XML DSL. For example, the timeout attribute would be a xs:int
type. Therefore, you cannot set a string value as the placeholder key.
From Apache Camel 2.7 onwards, this is now possible by using a special placeholder namespace. The following example illustrates the prop prefix for the namespace. It enables you to use the prop prefix in the attributes in the XML DSLs.
Note
In the Multicast, set the option
stopOnException
as the value of the placeholder with the key stop
. Also, in the properties file, define the value as
stop=true
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:prop="http://camel.apache.org/schema/placeholder" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd "> <!-- Notice in the declaration above, we have defined the prop prefix as the Camel placeholder namespace --> <bean id="damn" class="java.lang.IllegalArgumentException"> <constructor-arg index="0" value="Damn"/> </bean> <camelContext xmlns="http://camel.apache.org/schema/spring"> <propertyPlaceholder id="properties" location="classpath:org/apache/camel/component/properties/myprop.properties" xmlns="http://camel.apache.org/schema/spring"/> <route> <from uri="direct:start"/> <!-- use prop namespace, to define a property placeholder, which maps to option stopOnException={{stop}} --> <multicast prop:stopOnException="stop"> <to uri="mock:a"/> <throwException ref="damn"/> <to uri="mock:b"/> </multicast> </route> </camelContext> </beans>
Integration with OSGi blueprint property placeholders
If you deploy your route into the Red Hat JBoss Fuse OSGi container, you can integrate the Apache Camel property placeholder mechanism with JBoss Fuse's blueprint property placeholder mechanism (in fact, the integration is enabled by default). There are two basic approaches to setting up the integration, as follows:
Implicit blueprint integration
If you define a
camelContext
element inside an OSGi blueprint file, the Apache Camel property placeholder mechanism automatically integrates with the blueprint property placeholder mechanism. That is, placeholders obeying the Apache Camel syntax (for example, {{cool.end}}
) that appear within the scope of camelContext
are implicitly resolved by looking up the blueprint property placeholder mechanism.
For example, consider the following route defined in an OSGi blueprint file, where the last endpoint in the route is defined by the property placeholder,
{{result}}
:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> <!-- OSGI blueprint property placeholder --> <cm:property-placeholder id="myblueprint.placeholder" persistent-id="camel.blueprint"> <!-- list some properties for this test --> <cm:default-properties> <cm:property name="result" value="mock:result"/> </cm:default-properties> </cm:property-placeholder> <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <!-- in the route we can use {{ }} placeholders which will look up in blueprint, as Camel will auto detect the OSGi blueprint property placeholder and use it --> <route> <from uri="direct:start"/> <to uri="mock:foo"/> <to uri="{{result}}"/> </route> </camelContext> </blueprint>
The blueprint property placeholder mechanism is initialized by creating a
cm:property-placeholder
bean. In the preceding example, the cm:property-placeholder
bean is associated with the camel.blueprint
persistent ID, where a persistent ID is the standard way of referencing a group of related properties from the OSGi Configuration Admin service. In other words, the cm:property-placeholder
bean provides access to all of the properties defined under the camel.blueprint
persistent ID. It is also possible to specify default values for some of the properties (using the nested cm:property
elements).
In the context of blueprint, the Apache Camel placeholder mechanism searches for an instance of
cm:property-placeholder
in the bean registry. If it finds such an instance, it automatically integrates the Apache Camel placeholder mechanism, so that placeholders like, {{result}}
, are resolved by looking up the key in the blueprint property placeholder mechanism (in this example, through the myblueprint.placeholder
bean).
Note
The default blueprint placeholder syntax (accessing the blueprint properties directly) is
${Key}
. Hence, outside the scope of a camelContext
element, the placeholder syntax you must use is ${Key}
. Whereas, inside the scope of a camelContext
element, the placeholder syntax you must use is {{Key}}
.
Explicit blueprint integration
If you want to have more control over where the Apache Camel property placeholder mechanism finds its properties, you can define a
propertyPlaceholder
element and specify the resolver locations explicitly.
For example, consider the following blueprint configuration, which differs from the previous example in that it creates an explicit
propertyPlaceholder
instance:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> <!-- OSGI blueprint property placeholder --> <cm:property-placeholder id="myblueprint.placeholder" persistent-id="camel.blueprint"> <!-- list some properties for this test --> <cm:default-properties> <cm:property name="result" value="mock:result"/> </cm:default-properties> </cm:property-placeholder> <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <!-- using Camel properties component and refer to the blueprint property placeholder by its id --> <propertyPlaceholder id="properties" location="blueprint:myblueprint.placeholder"/> <!-- in the route we can use {{ }} placeholders which will lookup in blueprint --> <route> <from uri="direct:start"/> <to uri="mock:foo"/> <to uri="{{result}}"/> </route> </camelContext> </blueprint>
In the preceding example, the
propertyPlaceholder
element specifies explicitly which cm:property-placeholder
bean to use by setting the location to blueprint:myblueprint.placeholder
. That is, the blueprint:
resolver explicitly references the ID, myblueprint.placeholder
, of the cm:property-placeholder
bean.
This style of configuration is useful, if there is more than one
cm:property-placeholder
bean defined in the blueprint file and you need to specify which one to use. It also makes it possible to source properties from multiple locations, by specifying a comma-separated list of locations. For example, if you wanted to look up properties both from the cm:property-placeholder
bean and from the properties file, myproperties.properties
, on the classpath, you could define the propertyPlaceholder
element as follows:
<propertyPlaceholder id="properties" location="blueprint:myblueprint.placeholder,classpath:myproperties.properties"/>
Integration with Spring property placeholders
If you define your Apache Camel application using XML DSL in a Spring XML file, you can integrate the Apache Camel property placeholder mechanism with Spring property placeholder mechanism by declaring a Spring bean of type,
org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer
.
Define a
BridgePropertyPlaceholderConfigurer
, which replaces both Apache Camel's propertyPlaceholder
element and Spring's ctx:property-placeholder
element in the Spring XML file. You can then refer to the configured properties using either the Spring ${PropName}
syntax or the Apache Camel {{PropName}}
syntax.
For example, defining a bridge property placeholder that reads its property settings from the
cheese.properties
file:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ctx="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- Bridge Spring property placeholder with Camel --> <!-- Do not use <ctx:property-placeholder ... > at the same time --> <bean id="bridgePropertyPlaceholder" class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer"> <property name="location" value="classpath:org/apache/camel/component/properties/cheese.properties"/> </bean> <!-- A bean that uses Spring property placeholder --> <!-- The ${hi} is a spring property placeholder --> <bean id="hello" class="org.apache.camel.component.properties.HelloBean"> <property name="greeting" value="${hi}"/> </bean> <camelContext xmlns="http://camel.apache.org/schema/spring"> <!-- Use Camel's property placeholder {{ }} style --> <route> <from uri="direct:{{cool.bar}}"/> <bean ref="hello"/> <to uri="{{cool.end}}"/> </route> </camelContext> </beans>
Note
Alternatively, you can set the
location
attribute of the BridgePropertyPlaceholderConfigurer
to point at a Spring properties file. The Spring properties file syntax is fully supported.