Switching between jms providers - spring

I would like to do a SPRING (3.2.1) setup where I can switch the underlying JMS provider depending on the environment you are in e.g. dev, test, prod. I am no expert but have come across #Profile annotation of Spring. I don't really know how to use it. So what I need to do is in DEV environment I want to use ActiveMQ and in PRODUCTION I want to use IBM MQ. Is this possible? If so, would appreciate it if you could provide some config or code to do this. Thanks in advance.

http://static.springsource.org/spring-framework/docs/3.2.1.RELEASE/spring-framework-reference/html/new-in-3.1.html#new-in-3.1-bean-definition-profiles
For XML config, see this blog... http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/
See this blog about #Profile: http://blog.springsource.com/2011/02/14/spring-3-1-m1-introducing-profile/ for using profiles with #Configuration.
It boils down to this...
When using XML configuration, simply add <beans/> elements at the end of your spring config files...
<beans ...>
<bean... />
<beans profile="DEV">
<bean ... // my ActiveMQ config .../>
</beans?
<beans profile="default">
<bean ... // my IBM (or JNDI) config .../>
<beans/>
</beans>
Then run in dev with -Dspring-profiles-active=DEV.
Similarly #Profile can be added to #Configuration classes to limit their use to particular active profiles.

Related

Disable integration flow - Spring integration

I need to implement a spring integration flow for error queues handling. The flow needs to be activated based on configuration property as the error queues are not setup for lower environments like DEV.
How can I activate/enable integration flow based on spring configuration property?
my integration flow looks like this:
<bean id="error.jms" class="com.xxx.backend.integration.jms.MyMessageListener">
<property name="destinationName" value="#{queueConfig.getError().queueName()}"/>
<property name="errorHandler" ref="ErrorHandler"/>
</bean>
<intjms:message-driven-channel-adapter id="errorAdapter"
container="error.jms"
auto-startup="${xxx.backend.jmsAdaptor.autoStart}"
role="systemEndpoint"
channel="error.channel"/>
It sounds more like you need to make yourself familiar with Spring's Bean Definition Profiles.
So, what you would need is something like this for your config:
<beans profile="production">
<bean id="error.jms" class="com.xxx.backend.integration.jms.MyMessageListener">
...
</bean>
<intjms:message-driven-channel-adapter id="errorAdapter"
...
channel="error.channel"/>
</beans>
Then you just need to activate it when you start the app in the production., e.g. -Dspring.profiles.active=production.

Spring application should start even database is not available at startup

I have an old spring application which uses jee:jndi-lookup for datasource. This application running on Tomcat 8.
<jee:jndi-lookup id="datasource" jndi-name="java:/comp/env/jdbc/Tomcat8Database" destroy-method="close" expected-type="javax.sql.DataSource" lookup-on-startup="false"/>
The database may be sometime down at startup of the application, but as I also tried to lazy-init spring beans it did not helped as what it seems like that JNDI lookup in spring happened on Startup always or its not in spring controls as Server provide Pooling over connections.
Any idea or code example will be helpful.
According to spring javadoc, For a lazy lookup, a proxy interface needs to be specified.
Proxy interface specify the proxy interface to use for the JNDI object.
Typically used in conjunction with "lookupOnStartup"=false and/or "cache"=false. Needs to be specified because the actual JNDI object type is not known in advance in case of a lazy lookup.
Try:
<jee:jndi-lookup id="datasource" jndi-name="java:/comp/env/jdbc/Tomcat8Database" destroy-method="close" expected-type="javax.sql.DataSource" lookup-on-startup="false" proxy-interface="javax.sql.DataSource"/>

how can I configure RedisHttpSessionConfigure to fallback if redis is not online

I'm using spring-session + redis as documented here:
http://docs.spring.io/spring-session/docs/current/reference/html5/guides/httpsession-xml.html
How can I configure RedisHttpSessionConfigure such that for local development, redis is not needed and the application will simply default to the container session handling?
Generally this isn't recommended because you are differing your development environment from your production environment. It should be quite trivial to point your dev machine to a Redis instance.
If you need to support it, you can use Spring profiles. For example, with XML you can use something like:
<beans profile="dev">
<bean id="springSessionRepositoryFilter" class="org.springframework.web.filter.CharacterEncodingFilter"/>
</beans>
<beans profile="production">
<context:annotation-config/>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
<bean class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"/>
</beans>
The key is to ensure that your dev environment also has a Bean that implements Filter named springSessionRepositoryFilter. In this example, I used CharacterEncodingFilter which should do nothing since the encoding property is not set but feel free to replace with whatever you like.
The next thing you will need to do is activate your environments. For example, you can use
-Dspring.profiles.active="production"

Spring more than one profile and ${spring.profiles.active}

In spring 4.1.2.RELEASE, we have 2 active profiles in web.xml
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>Production,Customer1</param-value>
</context-param>
And we want to dynamically load some property files as below:
<util:properties id="accountPolicy"
location="classpath:/configs/${spring.profiles.active}/sample.properties" />
The ${spring.profiles.active} is not working, may be because there are two profiles, I tried some lookups like: ${spring.profiles.active[1]} but no luck !
Any comments
Updated:
It seems that ${spring.profiles.active} is an comma seperated list I try below:
<util:properties id="signConditions"
location="classpath:/configs/#{ {'${spring.profiles.active}'.split(',')}.get(1) }/sample.properties" />
But the error seems that there will be an XML parsser error:
org.springframework.expression.ParseException:
Expression 'classpath:/configs/#{ {'Production,Customer1'.split('' # 19: No ending suffix '}' for expression starting at character 19: #{ {'Production,Customer1'.split('
This did the job:
<util:properties id="signConditions"
location="classpath:/configs/#{environment.getActiveProfiles()[1]}/sample.properties" />
I believe the more proper way is to do something like:
<beans profile="Production">
<!-- some other stuff for Production profile -->
</beans>
<beans profile="Customer1">
<util:properties id="accountPolicy"
location="classpath:/configs/Customer1/sample.properties" />
<!-- some other stuff for Customer1 profile -->
</bean>
Profiles are supposed to be used as Profiles of configurations in app context, instead of like a property for replacement (as what you are doing)
Edit base on my comment:
What you are looking for is not a proper use case of Spring profile feature (at least not now). What you are trying to do is having property place holder work base on a system property. However, activation of profiles can be done through other way. Which means, you can turn on a profile without that spring.profiles.active system property. What you are doing is not reliable.
If it is fine for you to pass in system properties, why not do something like:
Have a profile called Customer, which denote for deployment to customers which will involve account policy (and other stuff)
Pass in a system property, for example, with key = 'customerCode' and value being an identifier for a customer.
By doing so, what you need to do is
<beans profile="Production">
<!-- some other stuff for Production profile -->
</beans>
<beans profile="Customer">
<util:properties id="accountPolicy"
location="classpath:/configs/${customerCode}/sample.properties" />
<!-- some other stuff for Customer1 profile -->
</bean>
and system properties you need for your application should looks like: -Dspring.profiles.active="Production,Customer" -DcustomerCode=Customer1
Then you have proper use of profiles, and no need to duplicate accountPolicy for each customer.

Load different properties for development and deployment

I have a very common use case -- connect to different databases when my program is in development mode, in test mode, or in deployment mode.
The way I am doing it now, is I configure a data source, and pass it ${...} properties via bean:property tag.
However to get the ${...}, i am doing
<context:property-placeholder properties-ref="myProperties" />
and in the bottom of the xml config, I have
<beans profile=test>
<util:properties id=myProperties>
</util>
</beans>
<beans profile=dev,default>
<util:properties id=myProperties>
</beans>
<beans profile=prod>
<util:properties id="myProperties>
</beans>
This seems inefficient, overly verbose, and prone to error. All spring properties tutorials tell me that context:property-placeholder is Environment aware, and Environment is responsible for profiles so how do I simplify this? It is intuitive to me that there is a simpler way, I just can't figure it out.
Really, what I am looking for is to specify profile on context:properties-placeholder, or something like that.
I solved that problem once (a long time before Spring supports profiles): spring property substitution for test and production
nowadays a would still use property files but, but I would select them by profiles. There are a lot of ways to do this:
The simplest one is:
<context:property-placeholder
location="classpath*:META-INF/spring/config-${spring.profiles.active}.properties" />
an other is:
<beans profile="normal">
<context:property-placeholder
location="classpath*:META-INF/spring/config-normal.properties"/>
</beans>
<beans profile="test">
<context:property-placeholder
location="classpath*:META-INF/spring/config-test.properties"/>
</beans>
The first approach has the drawback, that when more than one profile is activated then only the properties for the first profile gets loaded. I am not sure what will happen with the second approach when having more than one profiles.
For the first approach I found this solution, but I have not tested it:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:META-INF/spring/*_${spring.profiles.active}.properties</value>
</list>
</property>
</bean>
While profiles are certainly a solution to that problem I think that this approach opens another big door to issues that you discover only on the target platform.
In my projects I have always externalized the properties and turned as many properties as possible into runtime parameters.
Just imagine having to bundle Jenkins/Sonar/etc again as your platform will not be part of a profile with properties residing in the classpath. I don't think that then these would be successful projects ;)
As for spring you can use the 'file://' protocol in a propertyconfigurer allowing to superseed a "dedault" property coming from the classpath. So you have two configurer tags with an order parameter and other properties. Here's an example:
<jee:jndi-lookup id="configDirectory" jndi-name="configDirectory"
resource-ref="true" default-value="." />
<jee:jndi-lookup id="datasource" jndi-name="jdbc/datasource"
expected-type="javax.sql.DataSource" default-ref="localDatasource" />
<!-- Allows fetching properties from multiple locations: -->
<!-- external definition -> file://${configDirectory}/root-context.properties
-> declared in context.xml -->
<!-- standard web application bundle -> /WEB-INF/spring/root-context.properties -->
<!-- testing -> classpath:root-context.properties -->
<context:property-placeholder location="${configDirectory:.}/context.properties"
order="9" ignore-resource-not-found="true" ignore-unresolvable="true" />
<context:property-placeholder
location="/WEB-INF/spring/context.properties,
classpath:context.properties"
order="10" ignore-resource-not-found="true" ignore-unresolvable="true" />
<context:property-placeholder location="classpath:spring/default.properties"
order="100" />
Like this we are able to build it locally, run our unit and integration tests during maven build, run the build on UAT and if all that is ok copy the build from UAT to PROD without having to modify the war file.
In the properties we define all the parametersthat cannot be changed at runtime, which is essentially the Hibernate parameters plus some others.
All the rest is stored in the database as simple system parameters (key-value pairs). There are a lot of properties that do not need to be fixed. This includes: LDAP, MailSender, folder definitons like tempdir and others.
As the datasource is one of the very first beans to be initiated this works pretty nice in the projects I am running currently, and we are still discovering more properties to be pushed into the database.
Please read:
https://examples.javacodegeeks.com/enterprise-java/spring/load-environment-configurations-and-properties-with-spring-example/
<context:property-placeholder location="
classpath:application.properties,
classpath:application${spring.profiles.active}.properties"
ignore-unresolvable="true"/>
mvn clean install -Dspring.profiles.active="profile_name".

Resources