Changing spring property value dynamically on from DB after server startup - java

I have configured to load all my properties from DB.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="beanName" value="databaseConfiguration"/>
</bean>
<bean id="commonsConfigurationFactoryBean" class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
<constructor-arg ref="databaseConfiguration" />
</bean>
<bean id="autobotDataSource" class="com.commons.dao.AdminDataSource"/>
<bean id="databaseConfiguration" class="org.apache.commons.configuration.DatabaseConfiguration">
<constructor-arg type="javax.sql.DataSource" ref="autobotDataSource" />
<constructor-arg name="table" value="testdb.properties" /><!-- configuration table name -->
<constructor-arg name="keyColumn" value="prop_key" /><!-- key column -->
<constructor-arg name="valueColumn" value="key_value" /><!-- value column -->
</bean>
And I have imported that in my properties.
I am able to get the value in bean using #Value annotation. But if I update a value in DB it is not getting reflected in my application with out restart is there a way to dynamically update the value.

Related

org.springframework.beans.NotWritablePropertyException. Invalid property <blah> is not writable or has an invalid setter method

I have the requirement to remove all passwords and encryption keys from the source code of my project. I'm struggling to get this to work in my spring-servlet.xml file.
This worked before I tried making the change:
the database username, encrypted password, URL and driver were defined in a file jdbc_server.properties as a classpath resource.
the encryption/decryption key was passed on start-up as -DENCRYPTION_PASSWORD=
I want to move the jdbc_server_properties file to the filesystem and include the key in the file.
This is my last (of at least 25) attempt at getting this to work.
<bean id="propertyConfigurer" class="org.jasypt.spring4.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="standardEncryptor" />
<property name="jdbcUsername" value="JDBC_USERNAME" />
<property name="jdbcPassword" value="JDBC_PASSWORD" />
<property name="jdbcUrl" value="JDBC_URL" />
<property name="jdbcDriver" value="JDBC_DRIVER" />
<property name="locations">
<list>
<value>file:///${USERPROFILE}/credentials/jdbc_server.properties</value>
</list>
</property>
</bean>
<bean id="standardEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config" ref="environmentVariablesConfiguration" />
</bean>
<bean id="environmentVariablesConfiguration" class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
<property name="algorithm" value="PBEWithMD5AndDES" />
<property name="passwordSysPropertyName" value="ENCRYPTION_PASSWORD" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="${jdbcDriver}" p:url="${jdbcUrl}"
p:username="${jdbcUsername}" p:password="${jdbcPassword}">
</bean>
Using the above configuration, I get a NotWritablePropertyException exception. I've seen tons of posts on this issue but not where both the properties and encryption key are in a file on the filesystem.
When this was working and the properties were read from a file in the classpath, there were no getters/setters for jdbcUsername (or the other properties) so I don't know why it's failing in this way now.
I tried adding the getters and setters (as String) to my BaseDaoImpl class but I still get the same error so if I'm supposed to add them, I'm not sure where they go.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'propertyConfigurer' defined in ServletContext resource [/WEB-INF/spring-servlet.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'jdbcUsername' of bean class [org.jasypt.spring4.properties.EncryptablePropertyPlaceholderConfigurer]: Bean property 'jdbcUsername' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1568)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1276)
at ...
That is probably because jdbcUsername is not a property of EncryptablePropertyPlaceholderConfigurer.
Please, try something like this (just remove the jdbc* properties from the EncryptablePropertyPlaceholderConfigurer configuration, and use it directly in your dataSource bean):
<bean id="propertyConfigurer" class="org.jasypt.spring4.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="standardEncryptor" />
<property name="locations">
<list>
<value>file:///${USERPROFILE}/credentials/jdbc_server.properties</value>
</list>
</property>
</bean>
<bean id="standardEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config" ref="environmentVariablesConfiguration" />
</bean>
<bean id="environmentVariablesConfiguration" class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
<property name="algorithm" value="PBEWithMD5AndDES" />
<property name="passwordSysPropertyName" value="ENCRYPTION_PASSWORD" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="${JDBC_DRIVER}" p:url="${JDBC_URL}"
p:username="${JDBC_USERNAME}" p:password="${JDBC_PASSWORD}">
</bean>
Assuming your jdbc_server.properties file contains the required information:
JDBC_USERNAME=ENC(...)
JDBC_PASSWORD=ENC(...)
JDBC_URL=ENC(...)
JDBC_DRIVER=your.jdbc.driver

How to use Spring cache Manager with redis 1.6.2.RELEASE

We are using Spring Cache Manager with spring-data-redis 1.5.2. These days we want to upgrade spring-data-redis to latest release i.e:1.6.2.RELEASE.
For some weird reason everything works good with 1.5.2 but when upgrading to 1.6.2 we get
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'cacheManager' defined in ServletContext
resource [/WEB-INF/spring-cache.xml]: Unsatisfied dependency
expressed through constructor argument with index 0 of type
[org.springframework.data.redis.core.RedisOperations]: Ambiguous
constructor argument types - did you specify the correct bean
references as constructor arguments?
This message seems like a mistake as redisTemplate is RedisTemplate which implements RedisOperations.
Any idea how to solve it?
P.S
note that when removing the cache configuration the 1.6.2 version seems to work good. So the issue is with the cache.
Configuration
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-redis.xml
/WEB-INF/spring-cache.xml
</param-value>
</context-param>
spring-redis.xml
<context:annotation-config />
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" />
<bean
class="org.springframework.security.web.session.HttpSessionEventPublisher" />
<!-- end of seesion managment configuration -->
<bean id="redisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="port" value="${app.redis.port}" />
<property name="hostName" value="${app.redis.hostname}" />
<property name="password" value="${app.redis.password}" />
<property name="usePool" value="true" />
</bean>
<!-- for publishing string over redis channels -->
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="redisConnectionFactory" />
</bean>
<!-- for storing object into redis key,value -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="redisConnectionFactory" />
</bean>
spring-cache.xml
<!-- This file must load after spring-redis.xml -->
<cache:annotation-driven />
<!-- declare Redis Cache Manager -->
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"
c:template-ref="redisTemplate" />
</beans>
It seems the reason for this bug is that RedisCacheManager has two constructors. Both of them has RedisOperations as parameter. Forsome reason Spring couldnot understand its related to the first constructor and not to the second one. a work around is mention constructor-arg index
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg index="0" ref="redisTemplate"></constructor-arg>
</bean>
While upgrading from Spring Data Redis 1.5.2.RELEASE to 1.6.2.RELEASE, we need to use the below config for RedisCacheManager. Previous releases were using redis-template-ref instead of redis-operations-ref.
<beans:bean id='cacheManager'
class='org.springframework.data.redis.cache.RedisCacheManager'
c:redis-operations-ref='redisTemplate'>
</beans:bean>
This is an old question, but for those who reach this page.
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager" factory-method="create" c:connection-factory-ref="jedisConnectionFactory" p:transaction-aware="true" />
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnectionFactory" />
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${cache.redis.host}" p:port="${cache.redis.port}" p:use-pool="true">
<constructor-arg ref="jedisPoolConfig"></constructor-arg>
</bean>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" p:maxTotal="${cache.redis.pool.maxTotal}" p:maxIdle="${cache.redis.pool.maxIdle}" p:maxWaitMillis="${cache.redis.pool.maxWaitMillis}" p:testOnBorrow="true" />

Two beans with same name in different contexts

I have the following beans in my contexs:
<!-- Context 1 -->
<beans profile="ldap">
<bean id="activeDirectoryAuthProvider" class="com.production.ActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
</beans>
<!-- Context 2 -->
<bean id="activeDirectoryAuthProvider" class="com.test.TestActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
My goal is to use the first bean only for production version another one for test purposes.
Namely when I start test based on production context I expect that production bean would be replaced by test bean with needed configuration.
But unfortunately when I tried to create two beans with same name only production bean is created and another one is ignored. Another thing that I noticed that when I tried to change test bean name to: activeDirectoryAuthProvider1 then both beans are successfully created. Can anyone explain why it happen and suggest possible solution how it can be bypassed?
You need to use different contexts for development and production. In each context you define only the relevant bean (i.e. only 1 bean with a certain name). If you use maven you can put the test/development context under src/test/resources and the production context under src/main/resources
If you do not use maven there are other approaches. You can find an example here: http://mrhaki.blogspot.it/2009/02/use-spring-configurator-to-support.html
Take a look at Spring Profiles you can have one for test and one for prod.
<beans profile="test">
<!-- Context 1 -->
<bean id="activeDirectoryAuthProvider" class="com.production.ActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
</beans>
<beans profile="prod">
<!-- Context 2 -->
<bean id="activeDirectoryAuthProvider" class="com.test.TestActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="${ldap.login.provider.domain}"/>
<constructor-arg value="${ldap.login.provider.url}" />
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
</beans>
You can set the active profile in a various ways. Check the docs.

What is this error in spring mvc integrated via memcache

I want to use simple-spring-memcached to cache data. so using this https://code.google.com/p/simple-spring-memcached/wiki/Getting_Started for my purpose.
i add in my dispatcher-servlet.xml
<aop:aspectj-autoproxy />
<import resource="simplesm-context.xml" />
<bean name="cacheManager" class="com.google.code.ssm.spring.SSMCacheManager">
<property name="caches">
<set>
<bean class="com.google.code.ssm.spring.SSMCache">
<constructor-arg name="cache" index="0" ref="defaultCache"/>
<!-- 5 minutes -->
<constructor-arg name="expiration" index="1" value="0"/>
<!-- #CacheEvict(..., "allEntries" = true) doesn't work -->
<constructor-arg name="allowClear" index="2" value="false"/>
</bean>
</set>
</property>
</bean>
<bean name="defaultCache" class="com.google.code.ssm.CacheFactory">
<property name="cacheName" value="defaultCache"/>
<property name="cacheClientFactory">
<bean name="cacheClientFactory" class="com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl"/>
</property>
<property name="addressProvider">
<bean class="com.google.code.ssm.config.DefaultAddressProvider">
<property name="address" value="127.0.0.1:11211"/>
</bean>
</property>
<property name="configuration">
<bean class="com.google.code.ssm.providers.CacheConfiguration">
<property name="consistentHashing" value="true"/>
</bean>
</property>
</bean>
i also add simple-spring-memcached-3.5.0.jar and spymemcache.jar,spymemcache-provider.jar to lib folder. but when i run my project occur this exception:
Cannot find class **[net.nelz.simplesm.config.MemcachedClientFactory]** for bean with name 'memcachedClientFactory' defined in ServletContext resource [/WEB-INF/simplesm-context.xml]; nested exception is java.lang.ClassNotFoundException: net.nelz.simplesm.config.MemcachedClientFactory
you must add lib for this class.
It seams that you have also an old version of Simple Spring Memcached on your classpath. The class net.nelz.simplesm.config.MemcachedClientFactory is no longer available in 3.x. Check your classpath and remove all Simple Spring Memcached artifacts older than 3.5.0.

Embedding HornetQ in Spring

I am trying to evaluate HornetQ and the possibility of embedding it in a spring application. To start with a simple setup I am just trying to initialize it as follows. I didn't find much documentation about how to do this, apart from the fact that 'you can'.
I am using Spring 3 and HornetQ 2.1.1GA
My Spring configuration looks like this, however if theres a simpler cleaner configuration it would be better. I want the minimalistic approach first and then build on it.:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="mbeanServer" class="java.lang.management.ManagementFactory" factory-method="getPlatformMBeanServer" />
<bean name="fileConfiguration" class="org.hornetq.core.config.impl.FileConfiguration" init-method="start" destroy-method="stop" />
<bean name="hornetQSecurityManagerImpl" class="org.hornetq.spi.core.security.HornetQSecurityManagerImpl" />
<!-- The core server -->
<bean name="hornetQServerImpl" class="org.hornetq.core.server.impl.HornetQServerImpl">
<constructor-arg ref="fileConfiguration" />
<constructor-arg ref="mbeanServer" />
<constructor-arg ref="hornetQSecurityManagerImpl" />
</bean>
<!-- The JMS server -->
<bean name="jmsServerManagerImpl" class="org.hornetq.jms.server.impl.JMSServerManagerImpl" init-method="start" destroy-method="stop" >
<constructor-arg ref="hornetQServerImpl" />
</bean>
<bean name="connectionFactory" class="org.hornetq.jms.client.HornetQConnectionFactory" >
<constructor-arg>
<bean class="org.hornetq.api.core.TransportConfiguration">
<constructor-arg value="org.hornetq.integration.transports.netty.NettyConnectorFactory" />
<constructor-arg>
<map key-type="java.lang.String" value-type="java.lang.Object">
<entry key="port" value="5445"></entry>
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
<bean name="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"></property>
</bean>
</beans>
With this config I am getting the error:
SEVERE: Unable to deploy node [queue: null] DLQ
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
...
29-Dec-2010 18:16:34 org.hornetq.core.logging.impl.JULLogDelegate error
SEVERE: Unable to deploy node [queue: null] ExpiryQueue
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
...
9-Dec-2010 18:16:34 org.hornetq.core.logging.impl.JULLogDelegate error
SEVERE: Unable to deploy node [queue: null] ExampleQueue
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:325)
Its must be something obvious related to JNDI, but I would appreciate the proper minimalistic configuration to start with and then expand on it afterwards. The HornetQ configuration files are the default ones that come with the distribution (default queues, default users etc.)
You need to define the JMS queues you want to add to the server, and specify an empty list of JNDI bindings for each queue. To do this, add a JMSConfigurationImpl to your JMSServerManagerImpl bean definition. For example, if you need to define a queue called "testqueue":
<bean id="hornetQJmsConfig" class="org.hornetq.jms.server.config.impl.JMSConfigurationImpl">
<constructor-arg index="0">
<list/>
</constructor-arg>
<!-- Queue configurations -->
<constructor-arg index="1">
<list>
<bean class="org.hornetq.jms.server.config.impl.JMSQueueConfigurationImpl">
<!-- Name -->
<constructor-arg index="0" value="testqueue"/>
<!-- Selector -->
<constructor-arg index="1"><null/></constructor-arg>
<!-- Durable queue -->
<constructor-arg index="2" value="true"/>
<!-- JNDI bindings, empty list for none -->
<constructor-arg index="3"><list/></constructor-arg>
</bean>
</list>
</constructor-arg>
<!-- Topic configurations -->
<constructor-arg index="2">
<list/>
</constructor-arg>
</bean>
Since the second and third constructor args take a list of queue and topic configurations, you can add as many queues and topics as you like. For more than one or two, it's probably best to create a Spring template object.

Categories

Resources