use system properties proxy settings for camel http4 - spring

I'm trying to use the System Properties' proxy settings for the http4 component to no avail.
The documentation gives this example:
<camelContext>
<properties>
<property key="http.proxyHost" value="172.168.18.9"/>
<property key="http.proxyPort" value="8080"/>
</properties>
</camelContext>
but that's just using hardcoded values.
Is there a way to use placeholders within the camelContext properties?

First of all, you need the PropertiesComponent to resolve properties within the <camelContext>:
<bean id="propertiesComponent" class="org.apache.camel.component.properties.PropertiesComponent" />
You don't need to specify a location, if you just need support for one of the following:
EnvPropertiesFunction
SysPropertiesFunction
ServicePropertiesFunction
Now you can use placeholders in the camelContext properties:
<camelContext>
<properties>
<property key="http.proxyHost" value="{{http.proxyHost}}"/>
<property key="http.proxyPort" value="{{http.proxyPort}}"/>
</properties>
</camelContext>
One other thing to note is that this will fail if the system property is not set. You can (and probably should) specify a default value after a colon
<property key="http.proxyHost" value="{{http.proxyHost:}}"/>
<property key="http.proxyPort" value="{{http.proxyPort:}}"/>
to assure it works in both cases.

Related

Apache Camel Spring DSL, referring to an environment variable HOSTNAME

I am using Apache Camel 2.16.0 with Spring DSL
I have a Spring context XML in which I have defined a Property PlaceHolder to read the properties from various files as follows-
<bean id="propertyPlaceholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="ignoreResourceNotFound" value="false"/>
<property name="locations">
<list>
<value>classpath:/properties/versioning.properties</value>
<value>classpath:/properties/#{inetAddress.hostName}.properties</value>
</list>
</property>
</bean>
<bean id="inetAddress" class="java.net.InetAddress" factory-method="getLocalHost"/>
The property values are used to construct other beans such as -
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.gjt.mm.mysql.Driver"/>
<property name="url" value="${${LIVE_}DATASOURCE_URL}"/>
<property name="username" value="${${LIVE_}DATASOURCE_USERNAME}"/>
<property name="password" value="${${LIVE_}DATASOURCE_PASSWORD}"/>
</bean>
This works fine, I can see the beans being created.
I also have another Spring Context XML in the same app which has a camel context and I want to use the some other properties defined in the same properties files. I know that camel supports Spring Property Placeholder, see below excerpts from the context -
<camelContext id="charge-process-context" xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder id="properties"
location="classpath:/properties/versioning.properties,
properties/${env:HOSTNAME}.properties"
xmlns="http://camel.apache.org/schema/spring" />
.....
.....
</camelContext>
As part of this context, I have a route that uses https component that uses the values from the property file such as below -
<to uri="https4:{{LIVE_AUTH_RESPONSE_HOST}}:{{LIVE_AUTH_RESPONSE_PORT}}/{{LIVE_AUTH_RESPONSE_CONTEXT_PATH}}"/>
This route does not start and throws following exception -
Caused by: java.lang.IllegalArgumentException: Cannot find system environment with key: HOSTNAME
at org.apache.camel.util.FilePathResolver.resolvePath(FilePathResolver.java:54)
at org.apache.camel.component.properties.PropertiesComponent.parseLocations(PropertiesComponent.java:434)
at org.apache.camel.component.properties.PropertiesComponent.parseUri(PropertiesComponent.java:163)
at org.apache.camel.component.properties.PropertiesComponent.parseUri(PropertiesComponent.java:148)
at org.apache.camel.impl.DefaultCamelContext.resolvePropertyPlaceholders(DefaultCamelContext.java:2261)
at org.apache.camel.model.ProcessorDefinitionHelper.resolvePropertyPlaceholders(ProcessorDefinitionHelper.java:730)
at org.apache.camel.model.ProcessorDefinition.createOutputsProcessorImpl(ProcessorDefinition.java:427)
at org.apache.camel.model.ProcessorDefinition.createOutputsProcessor(ProcessorDefinition.java:413)
at org.apache.camel.model.ProcessorDefinition.createOutputsProcessor(ProcessorDefinition.java:165)
at org.apache.camel.model.ExpressionNode.createFilterProcessor(ExpressionNode.java:109)
at org.apache.camel.model.WhenDefinition.createProcessor(WhenDefinition.java:74)
at org.apache.camel.model.WhenDefinition.createProcessor(WhenDefinition.java:32)
at org.apache.camel.model.ProcessorDefinition.createProcessor(ProcessorDefinition.java:483)
at org.apache.camel.model.ChoiceDefinition.createProcessor(ChoiceDefinition.java:135)
at org.apache.camel.model.ProcessorDefinition.makeProcessorImpl(ProcessorDefinition.java:534)
at org.apache.camel.model.ProcessorDefinition.makeProcessor(ProcessorDefinition.java:495)
at org.apache.camel.model.ProcessorDefinition.addRoutes(ProcessorDefinition.java:219)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1069)
Please Note: I am deploying my application as a war file on Tomcat 8 on an AWS instance.
I have a Dev Environment on Windows 10 and I have found this working on the Windows OS. I have also seen that the file FilePathResolver.java in Apache Camel 2.16 uses System.getenv(key) to obtain the value i.e. System.getenv("HOSTNAME") which returns a null on AWS instance and a correct value on Windows 10. I also tried using env:hostname (small case letters for unix) but still no luck ...
I found a solution at http://camel.apache.org/using-propertyplaceholder.html
at Bridging Spring and Camel Property Placeholders
It mentions following -
The Spring Framework does not allow 3rd party frameworks such as Apache Camel to seamless hook into the Spring property placeholder mechanism. However you can easily bridge Spring and Camel by declaring a Spring bean with the type org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer, which is a Spring org.springframework.beans.factory.config.PropertyPlaceholderConfigurer type.

Apache Ignite not resolving properties in configuration XML

I am looking to load a number of values into my server configuration.xml from a properties file.
However, on adding the placeholders I start getting, property cannot be resolved errors. Preferably I would like to use Jasypt, which has loaded up fine, but has the same issue, property cannot be resolved.
Sample placeholder:
<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="ignite.properties"/>
</bean>
Sample Bean:
<property name="sslContextFactory">
<bean class="org.apache.ignite.ssl.SslContextFactory">
<property name="keyStoreFilePath" value="ignite.jks"/>
<property name="keyStorePassword" value="${some.password}"/>
<property name="keyStoreType" value="JKS"/>
<property name="protocol" value="TLSv1.2"/>
<property name="trustManagers">
<bean class="org.apache.ignite.ssl.SslContextFactory" factory-method="getDisabledTrustManager"/>
</property>
</bean>
</property>
Is it possible, is there a library I should have added, it otherwise runs fine if I do not use properties.
The configuration is parsed by Spring and Ignite has nothing to do with it. I believe there are two possible reasons:
Incorrect file path. Note that if the file is on the classpath, the location should be classpath:ignite.properties.
Incorrect property name.

access a property within a custom PropertyPlaceholderConfigurer

We are on Spring 4.2.5 version. There is a need to have a custom implementation of PropertyPlaceholderConfigurer basically to have data decrypted before using them. This works fine. However I further need to be able to change the crypto mechanism used within this custom implementation, based on a property (read using the normal context:property-placeholder). Is there a way to get this working?
The easiest way to do that is not to have a custom PropertyPlaceholderConfigurer, but a custom DefaultPropertiesPersister. This is configured this way :
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:...</value>
<value>...</value>
</list>
</property>
<property name="propertiesPersister">
<bean class="yourPropertiesPersister"/>
</property>
...
</bean>
Then yourPropertiesPersister needs to extends DefaultPropertiesPersister which makes you implement :
public void load(Properties props, InputStream is) throws IOException {
super.load(props, is);
decrypt(props);
}
#Override
public void load(Properties props, Reader reader) throws IOException {
super.load(props, reader);
decrypt(props);
}
private void decrypt(Properties props) {
// your logic here
}
The call to super.load(...) will load the raw properties (content is not decrypted). Just add the logic to a method decrypt(props), based on the content of some of the properties. Add your decrypted properties to props.
Your use case is covered by the jasypt library, if you don't mind adding one more dependency to your project. What makes it neat is the fact that it integrates seamlessly with Spring and it facilitates further changes in the parameterization of your encryption, i.e. the algorithm used or the location of the master encryption key.
What is cool is that the code in your spring config / class annotations, in which you inject the value corresponding to a certain key in a property file, will look the same, as if you're using plain-text properties.
Here is a small example, as per the tutorial in their website (http://www.jasypt.org/spring31.html):
application.properties => your properties file
datasource.driver=com.mysql.jdbc.Driver
datasource.url=jdbc:mysql://localhost/reportsdb
datasource.username=reportsUser
datasource.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm)
your Spring config (works the same when injecting through annotations)
<!-- -->
<!-- Configuration for encryptor, based on environment variables. -->
<!-- -->
<!-- In this example, the encryption password will be read from an -->
<!-- environment variable called "APP_ENCRYPTION_PASSWORD" which, once -->
<!-- the application has been started, could be safely unset. -->
<!-- -->
<bean id="environmentVariablesConfiguration"
class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
<property name="algorithm" value="PBEWithMD5AndDES" />
<property name="passwordEnvName" value="APP_ENCRYPTION_PASSWORD" />
</bean>
<!-- -->
<!-- The will be the encryptor used for decrypting configuration values. -->
<!-- -->
<bean id="configurationEncryptor"
class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config" ref="environmentVariablesConfiguration" />
</bean>
<!-- -->
<!-- The EncryptablePropertyPlaceholderConfigurer will read the -->
<!-- .properties files and make their values accessible as ${var}. -->
<!-- -->
<!-- Our "configurationEncryptor" bean (which implements -->
<!-- org.jasypt.encryption.StringEncryptor) is set as a constructor arg. -->
<!-- -->
<bean id="propertyConfigurer"
class="org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="configurationEncryptor" />
<property name="locations">
<list>
<value>/WEB-INF/classes/application.properties</value>
</list>
</property>
</bean>
<!-- -->
<!-- Our datasource is configured here, in the usual way. Jasypt's -->
<!-- EncryptedPropertyPlaceholderConfigurer will make sure that the -->
<!-- ${datasource.password} file gets decrypted and the DBCP DataSource -->
<!-- will be correctly initialised. -->
<!-- -->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>${datasource.driver}</value>
</property>
<property name="url">
<value>${datasource.url}</value>
</property>
<property name="username">
<value>${datasource.username}</value>
</property>
<property name="password">
<value>${datasource.password}</value>
</property>
</bean>
Jasypt parses the content of the property files you've provided and decrypts the values enclosed between ENC( and ). You can find additional details in the link provided above, it is truly a working example.
Another interesting feature of jasypt is the fact that it provides a command line tool, that you can use to encrypt the original, plain-text values, with a plethora of algorithms you can choose from. You can find the concise documentation of this tool here: http://www.jasypt.org/cli.html.

Tomcat Context-Params ignored in Spring webapp when using PropertyPlaceholder

I was previously using, the now deprecated, class org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer to load a properties file from the server's filesystem. I had the following bean definied:
<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
<property name="locations" value="${config}"/>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="searchContextAttributes" value="true"/>
<property name="contextOverride" value="false"/>
<property name="ignoreResourceNotFound" value="true"/>
<property name="searchSystemEnvironment" value="false"/>
</bean>
The config is an argument that is passed when starting Tomcat, i.e.
-Dconfig=/path/to/application.properties
For the webapp I also have a context file:
<Context docBase="/path/to/application.war">
<Parameter name="host" value="localhost" override="false"/>
<Parameter name="port" value="8080" override="false"/>
</Context>
If the .properties file, specified by the -Dconfig argument, contains the property that some other bean references then the value from the .properties file is used, otherwise the value from the the context xml file is used.
This allowed me to have a set of default properties deployed with the WAR and if required, I was able to specify a .properties file to override particular values.
Now, I'm updating to use the new property abstractions in Spring 3.1 but I can't seem to figure out what the equivalent approach to this is?
I have the same context file and war deployed in the same way, and I now have the following in the application:
<context:property-placeholder
location="${config}"
system-properties-mode="OVERRIDE"
ignore-resource-not-found="true"
ignore-unresolvable="true"/>
This finds and uses the properties from the properties file, BUT it does not use the values from the context XML file.
How do I get my application to use the context params when using this new property-placeholder?
Thanks.
To summarise the problem is that the Context Parameters from the servlet context file were not being used to resolve placeholders when using the new Property Placeholder namespace introduced in Spring 3.1.
I have figured out a solution, with the following
<context:property-placeholder location="${config}" local-override="true" ignore-resource-not-found="true"/>
I can specify one or more *.properties files on the local filesystem using a JVM arg, eg:
-Dconfig=/path/app.properties
If a placeholder property cannot be resolved after checking the app.properties file then the Servlet Context Parameters are checked.
This allows me to have default values using context params in a the web.xml and where I need to I can override these values by specifying the location of *.properties files using the config JVM arg.
The key to getting it to work this way was to include local-override="true", which is false by default. I'm not fully sure that it makes sense, since the description for that attribute is:
Specifies whether local properties override properties from files. Default
is "false": Properties from files override local defaults.
If the same property key exists in the app.properties and the web.xml the value from the app.properties is used.
Spring uses a default property file unless the user-based property file is defined. If you want to control .properties file, please follow the instructions posted here.
If you want to take advantage of application.properties there are two ways to do it.
<!-- allows for ${} replacement in the spring xml configuration from the
system.properties file on the classpath -->
<util:properties id="appProperties" location="classpath:application.properties"/>
<context:property-placeholder location="classpath:application.properties"/>
util tag lets you to use a Property class to read the properties across your application. For example:
#Autowired
public MyPropertyReader(Properties appProperties) {
String prop1 = appProperties.getProperty("my.address");
String prop2 = appProperties.getProperty("my.version");
}
If you want to use the values within your context file use the context:property-placeholder tag. Then you can use your values as
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory" p:brokerURL="${jms.primary.server}"/>
where for example jms.primary.server=172.168.10.18:6161 in application.properties.

Load jndi resources into context:property-placeholder

I have the following spring config file:
<context:property-placeholder order="2"
ignore-unresolvable="true" ignore-resource-not-found="true"
location="file:///${user.home}/application.properties" />
<context:property-placeholder order="1"
ignore-unresolvable="true" ignore-resource-not-found="true"
location="file:///C:/Services/Tomcat 6.0/cms/application.properties" />
<context:property-placeholder order="3"
location="classpath:com/afrozaar/cms/service/application.properties" />
Notice how they are ordered, some are on the classpath and some are on the file system.
Now to the mix I want to add a properties file loaded via jndi. I was hoping to be able to do
<context:property-placeholder order="2"
ignore-unresolvable="true" ignore-resource-not-found="true"
location="jndi:url/application.properties" />
Unfortunately, this doesn't work, spring doesn't support the jndi prefix... AFAIK.
So, can I do something like this?
And if I can't what's my alternative. I don't want to have to convert my whole configuration to a full bean based property place holder configurer.
Not sure what you really mean with "jndi:url/application.properties". I suppose you wanted to set the path to the property file in a resource entry named "url/application.properties".
You can achieve this with the following snippets:
<bean class="org.springframework.beans.factory.config.PlaceholderConfigurerSupport">
<property name="location">
<bean id="publisherLocal" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="url/application.properties" />
<property name="expectedType" value="java.lang.String" />
</bean>
</property>
</bean>
<context:property-placeholder> has a properties-ref attribute, which can point to the bean of type Properties. So, you can load Properties in your code and declare a <context:property-placeholder> using them.

Resources