I am using Camel-HTTP4 2.10.4 component for calling remote REST services from my application. This communication requires SSL configuration. I successfully tested my configuration with hard coded values for resource and password.
Now I need to configure the same using camel's Property-Placeholder. I am using nested properties in spring configuration. ex:
${${env:${default.fallback.env}}.path.to.keystore}
I followed Using PropertyPlaceholder and defined
<bean id="bridgePropertyPlaceholder" class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer">
<property name="locations">
<list>
<ref bean="confgPath1" />
<ref bean="configPath2" />
</list>
</property>
</bean>
and sslContextParameters as follows
<camel:sslContextParameters id="sslContextParameters">
<camel:trustManagers>
<camel:keyStore resource="{{{{default.fallback.env}}.keystore.file}}"
password="{{{{default.fallback.env}}.keystore.password}}" />
</camel:trustManagers>
<camel:keyManagers keyPassword="{{{{default.fallback.env}}.keystore.password}}">
<camel:keyStore resource="{{{{default.fallback.env}}.keystore.file}}"
password="{{{{default.fallback.env}}.keystore.password}}" />
</camel:keyManagers>
<camel:clientParameters>
<camel:cipherSuitesFilter>
<camel:include>.*</camel:include>
</camel:cipherSuitesFilter>
</camel:clientParameters>
</camel:sslContextParameters>
My application loads spring context successfully at start up. But after hitting the endpoint I am getting Error:
Failed to resolve endpoint <<My remote service URL>> due to: Error parsing property value: {{{{default.fallback.env}}.keystore.password}}.
I am able to use Camel's property placeholder for simple properties. For ex
{{default.fallback.env}}
But, when I try to use nested properties it is giving me above specified Error. Help me find out the proper way to solve this.
Current camel property component doesn't support the nested properties, so I just fill a JIRA for it.
As Camel property doesn't support the nested properties in the first place, you can define just define the property file like this, and set the environment from the system property and use {{someproperty}} to reference the properties.
someproperty={{{{environment}}.someproperty}}
# LOCAL SERVER
junit.someproperty=junit
# LOCAL SERVER
local.someproperty=local
# TEST
test.someproperty=test
# PROD
prod.someproperty=prod
I just used the Spring way to create Camel SSL configuration:
<bean id="sslContextParameters" class="org.apache.camel.util.jsse.SSLContextParameters">
<property name="keyManagers">
<bean class="org.apache.camel.util.jsse.KeyManagersParameters">
<property name="keyPassword" value="${dsi.key.password}" />
<property name="keyStore">
<bean class="org.apache.camel.util.jsse.KeyStoreParameters">
<property name="resource" value="${dsi.keystore.file}" />
<property name="type" value="JKS" />
<property name="password" value="${dsi.keystore.password}" />
<property name="camelContext" ref="camelContext" />
</bean>
</property>
<property name="camelContext" ref="camelContext" />
</bean>
</property>
<property name="camelContext" ref="camelContext" />
</bean>
I believe with Spring's property resolver you can achieve more and you do not need to use the custom bridge resolver.
Related
I am moving our config properties from a properties file to a database using apache commons DatabaseConfiguration. Works fine. However, it obviously needs database definition, and I want to load that with a jndi datasource name that is itself a property. So I want to keep a property file with that property and one or two others, that would load first and get used by the database configuration.
I have tried about a million permutations and I can't seem to get it to work. If I hardcode the jndi name in the spring config, it works, but whether I include both in the same property configurator or separate ones, whether I use the order property or not...nothing seems to work.
Here's one of my iterations that didn't work:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/WEB-INF/esp.properties" />
<property name="order" value="10" />
</bean>
<bean id="propertyConfigurer2" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="order" value="20" />
<property name="properties" ref="dbConfigFactory" />
</bean>
dbConfigFactory there is the factory that includes the databaseconfiguration bean. Does anyone know how to do this?
Here is the situation:
The xml configuration looks as follows:
<bean id="ppConfig1"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:c:\test\env.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true" />
</bean>
<bean id="string" class="java.lang.String" depends-on="ppConfig1">
<constructor-arg value="${env.app.type}"/>
</bean>
<bean id="ppConfig2"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" depends-on="string">
<property name="locations">
<list>
<value>file:c:\test\#{string}.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="false" />
</bean>
As is evident, I want load a specific property file (e.g. app1.properties) based on the value of key env.app.type in C:\test\env.properties.
The code to load/test the above config looks as follows:
ApplicationContext context = new ClassPathXmlApplicationContext(
"SpringBeans.xml");
String ss = (String)context.getBean("string");
System.out.println(ss);
This seems not working. It failing with following error:
Exception in thread "main"
org.springframework.beans.factory.BeanInitializationException: Could
not load properties; nested exception is
java.io.FileNotFoundException: C:\test\${env.app.type}.properties (The
system cannot find the file specified) at
org.springframework.beans.factory.config.PropertyResourceConfigurer.postProcessBeanFactory(PropertyResourceConfigurer.java:87)
The file c:\test\env.properties looks as follows
env.app.type=app1
One interesting observation is that when I comment out the ppConfig2, everything works fine and correct value of env.app.type is printed. I am open to any other suggestion to get around this. My basic requirement is to select the property file at run time based on the property specified in env.properties. (I am using spring 3.1.0)
You need something like this:
<context:component-scan base-package="com.foo.bar" />
<context:property-placeholder location="file:c:/test/${env.app.type}.properties" />
<bean id="service" class="com.foo.bar.ExampleService">
<property name="foo" value="${foo}" />
</bean>
package com.foo.bar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Configuration
#PropertySource("file:c:/test/env.properties")
public class SpringConfig{
}
And "foo" value comes from app1.properties file. Basically, one file is being loaded with #PropertySource, the other with the regular property placeholder.
I think you are trying to do things that Spring does not like. The normal order for bean initialization is :
fully construct bean post processors
construct other beans
init other beans
As long as those 3 passes are cleanly separated, all will be ok, but you have a post processor bean (ppConfig2) depending on a simple bean (string).
IMHO, you should avoid such construct if possible. Even if it works now, you are under the risk of problem arising at any modification of you application context because you are allready on the edge.
Could it be acceptable to use environment variables or system properties to avoid that a bean post-processor depends on another bean post-processor ? If yes, you would'nt be bothered by ppConfig1 and simply have :
<bean id="ppConfig2"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" depends-on="string">
<property name="locations">
<list>
<value>file:c:\test\${configured_env}.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="false" />
</bean>
If environment variables or system properties are not an option, you could use programmatic configuration as suggested by Andrei Stefan.
You can do this with util:properties:
<util:properties id="envProperties" location="env.properties"/>
<util:properties id="properties" location="#{envProperties.getProperty('env.app.type')}.properties"/>
<context:property-placeholder properties-ref="envProperties" ignore-unresolvable="true" ignore-resource-not-found="true"/>
<context:property-placeholder properties-ref="properties" ignore-unresolvable="true"/>
BTW there's a bug in Spring that prevents Spring EL from being evaluated inside location attribute in context:property-placeholder.
I want to know if beans in my application context are binded dynamically. Specifically, if I have
<bean id="mySpringRemoteService"
class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceInterface"
value="foo.bar.services.mySpringRemoteService" />
<property name="serviceUrl" value="${spring.remote.service.url}"/>
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:some.properties"/>
</bean>
if i change the property for the service url in my properties file, will retrieving the bean later reflect this change?
Well, I think it is easy for you to have a try yourself.
The answer is No (Unless behavior of Spring changed in 3.x )
I believe you have to implement runtime update behavior for config files. Take a look in Apache Commons Configurations.
<bean id="Mybean" class="Bean">
<property name="config" ref="dev"/>
</bean>
<bean id="dev" class="Dev">
<property name="x" ref="Dev1">
<property name="y" ref="Dev2">
<property name="z" ref="Dev3">
</bean>
<bean id="stag" class="Dev">
<property name="x" ref="Stag1">
<property name="y" ref="Stag2">
<property name="z" ref="Stag3">
</bean>
In the above scenario, the config property in the bean MyBean change from environment to environment. At the time of dev, reference of config change to dev. And in staging, the reference change to stag. The problem comes at the time of checked in the spring file. We have to analyze everytime the reference of config before checked in. If the reference of config with the value of dev checked in, we might have to explain a lot of questions.
Is there any solution to solve to make it automate?
Note: Spring version is 2.0.1
Use the PropertyPlaceholderConfigurer from Spring, and remove an unused bean :
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>env.properties</value>
</property>
</bean>
<bean id="Mybean" class="Bean">
<property name="config" ref="config"/>
</bean>
<bean id="config" class="Config">
<property name="x" ref="${x}">
<property name="y" ref="${y}">
<property name="z" ref="${z}">
</bean>
and the env.properties file contains the following properties :
x=Dev1
y=Dev2
z=Dev3
or
x=Stag1
y=Stag2
z=Stag3
setup up the placeholder bean by specfiy, let spring know you want the placeholder
set up the config for the "my bean" by using the "${env}"
for example:
<beans>
<bean id="configBean" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location"><value>env.properties</value></property>
</bean>
<bean id="Mybean" class="Bean">
<property name="config" ref="${env}"/>
</bean>
</beans>
and you need the add the env = dev key-value to the env.properties file
Assuming you meant Spring 3.1, rather than Spring 2.1 (which doesn't exist), then you can use the new "Environment Profiles" feature that was introduced in 3.1. This allows you to define a set of beans for each of your environments, and then select the "active" one at runtime.
See this SpringSource Blog Entry for examples.
You can do it using PropertyPlaceholderConfigurer or using #Profile
Also See
is-there-any-way-to-enable-or-disable-the-spring-bean-definition-in-applicationc
PropertyPlaceholderConfigurer example
PropertyPlaceholderConfigurer is the answer, yet I would imagine that you would like this to happen without the need to stay updating your properties file for each environment.
My suggestion would therefore be as follows
Use PropertyPlaceholderConfigurer, but do not create a properties file
By default, PropertyPlaceholderConfigurer first tries to find a value in a properties file, but if that fails, it will look for one in system properties
So all you need to do is to define both beans the same way that you are doing it, i.e. dev and stag.. which is a fine approach since you're clearly showing the different configurations... it would help if you also added some alias to show clearly the setting you want to use.
Next, pass in a system property defining what mode you are in... and ideally explicitly set PropertyPlaceholderConfigurer to use System properties.
So.. your config would look something like this
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
systemPropertiesMode="2"/>
<bean id="Mybean" class="Bean">
<property name="config" ref="${launch.mode}"/>
</bean>
<bean id="dev" name="dev_mode" class="Dev">
<property name="x" ref="Dev1">
<property name="y" ref="Dev2">
<property name="z" ref="Dev3">
</bean>
<bean id="stag" name="staging_mode" class="Dev">
<property name="x" ref="Stag1">
<property name="y" ref="Stag2">
<property name="z" ref="Stag3">
</bean>
You can then pass in the property upon startup in the following fashion
-D<property-name>=<value>
So in this case you'd use
-Dlaunch.mode=dev_mode
Or
-Dlaunch.mode=staging_mode
And you won't need to touch any of the configuration files.
Just a further note on systemPropertiesMode, accepted values are the following:
0 - never look in system properties
1 - use system properties as a fallback (i.e. if not found in properties files)
2 - system properties always override (the mode i'm suggesting)
Hope it helps :)
Note: This recommendation is only applicable to Spring < 3.1, since from 3.1 onward, the recommended approach is to use #Profile
Spring provides a mechanism called property placeholders. This way you can set certain properties in a database/properties file and spring will fill them in on startup.
The class to use for this is located here.
My project includes older un-annotated controllers together with newer annotation-based controllers.
I am using the latest Spring jars (3.0.5) and in my dispatcher-servlet.xml there's <mvc:annotation-driven />.
The problem is that <mvc:annotation-driven /> causes the request mapping (through the name property of the controller beans in the dispatcher-servlet.xml) to my un-annotated controllers not to work... each time I direct the request to an un-annotated controller I am getting an error message such as:
org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [/some_path/some_page.htm] in DispatcherServlet with name 'dispatcher'
How can I keep the un-annotated controllers as they are but tell spring to recognize their (old style) mapping?
I am looking for solutions with minimum change to the Java code of the controllers that I already have.
Thanks!
When you add <mvc:annotation-driven /> to your config, it replaces the default set of handler mappings and handler adapters, and those defaults were the ones that handled the old-style controllers.
You have 2 options. First thing to try is to remove <mvc:annotation-driven />. You can still use annotated controllers without this. It does add extra features like Jackson JSON support, but if you don't need those extra features, then you don't need it. So try your app without <mvc:annotation-driven /> and see if it still works.
Failing that, you can reinstate the mappings and adapters for your old controllers. You didn't say how your controllers used to have their URLs mapped, but try adding these to your config:
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.handler.ControllerClassNameHandlerMapping"/>
If you used SimpleUrlHandlerMapping, then that should be working already.
You also need to add the HandlerAdapter back in:
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
Don't just add these in blindly. Try them individually, and see what the minimal set is to get your old controllers working alongside the new ones.
I found that by exploding the mvc:annotation-driven into it's actual replacement, it was easier to figure out.
<mvc:annotation-driven /> explodes to this:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="0" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="validator" ref="validator" />
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
</list>
</property>
</bean>
<!-- Configures a validator for spring to use -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="messageInterpolator">
<bean class="com.eps.web.spring.validation.SpringMessageSourceMessageInterpolator" />
</property>
</bean>
<bean id="conversion-service" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
Once the magic was gone, I got this error trying to load an "Old" controller:
javax.servlet.ServletException: No adapter for handler [org.springframework.web.servlet.mvc.ParameterizableViewController#
From that point, I added
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
And all my old controllers worked.