Spring UTF-8 message resource from external jar issue - java

I have a problem with UTF-8 message sources in Spring MVC application. I've tried two implementations of AbstractMessageSource: ResourceBundleMessageSource and ReloadableResourceBundleMessageSource. I have an external jar with i18n messages contained in com.mypackage.i18n package
The configuration for ResourceBundleMessageSource:
<bean id="propertiesMessageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="com.mypackage.i18n.messages" />
<property name="useCodeAsDefaultMessage" value="true" />
</bean>
This configuration loads finds and loads properties, but fails with UTF-8, because this implementation just doesn't support UTF-8.
The configuration for ReloadableResourceBundleMessageSource:
<bean id="propertiesMessageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="com.mypackage.i18n.messages" />
<property name="useCodeAsDefaultMessage" value="true" />
<property name="fileEncodings" value="UTF-8" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
This configuration doesn't find properties. I know that this implementation to have reloadable resources needs properties to be located somewhere in WEB-INF directory and it doesn't restrict resources to be located somewhere else if you don't need reloading of resources.
According to the class java:
Note that the base names set as "basenames" property are treated in a slightly different fashion than the "basenames" property of ResourceBundleMessageSource. It follows the basic ResourceBundle rule of not specifying file extension or language codes, but can refer to any Spring resource location (instead of being restricted to classpath resources). With a "classpath:" prefix, resources can still be loaded from the classpath, but "cacheSeconds" values other than "-1" (caching forever) will not work in this case.
Can someone advice me how to solve the problem: I need to use another approach or somehow modify config of ReloadableResourceBundleMessageSource to find resources from jar?

I've found a solution. Proper ReloadableResourceBundleMessageSource configuration looks like this:
<bean id="propertiesMessageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:com/mypackage/i18n/messages" />
<property name="useCodeAsDefaultMessage" value="false" />
<property name="fileEncodings" value="UTF-8" />
<property name="defaultEncoding" value="UTF-8" />
<property name="cacheSeconds" value="-1"/>
</bean>

Related

Springboot war project with tomcat and external application properties?

How can we provide an external application.properties, datasource.properties file with war project that runs on external tomcat? Is there any way to provide these files path as vm arguments in tomcat configuration. Also is it possible to get the values from these files as #Value annotation if use the above configuration?
Have a PropertySourcesPlaceholderConfigurer
<bean name="propertySourcesPlaceholderConfigurer" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="location" value="file:${conf.dir}/app.properties" />
</bean>
where conf.dir you can pass it through JVM arguments like -Dconf.dir=yourconfigFilePath
and use like the following
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${dataSource.driverClassName}" />
<property name="url" value="${dataSource.url}" />
...
File app.properties
dataSource.driverClassName=org.apache.derby.jdbc.ClientDriver
dataSource.url=jdbc:derby://localhost:1527/dbpath

Creating multiple instances of PropertyPlaceHolderConfigurer - Spring

I have 2 different applications deployed in application server (glassfish). One is a jar file and other is a war application. Both the applications refer to a single properties file (data.properties). To read the properties file, I have created a instance of Springs PropertyPlaceholderConfigurer in respective context files (business-beans.xml and applicationContext.xml). After deploying the applications, I am able to load the properties file in one application while the other web application throws "Could not resolve placeholder 'sw.throttle.enable'
Question -
How to solve the issue?
Is it incorrect load the same properties file at two locations?
Is there a way I load the properties file in one context and in the other bean definition file use the reference of the first one?
SnapShot of business.beans
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="placeholderPrefix" value="${sw." />
<property name="location" value="file:///etc/data.properties" />
<property name="ignoreResourceNotFound" value="true" />
</bean>
Property referenced as below in business.beans
<bean id="mService" class=" com.test.business.mService">
<property name="throttlingEnabled" value="${sw.throttle.enable}"/>
</bean>
Snapshot of applicationContext.xml
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="placeholderPrefix" value="${sw." />
<property name="location" value="file:///etc/data.properties" />
<property name="ignoreResourceNotFound" value="true" />
</bean>
Property referenced as below in applicationContext.xml
<bean id="downloadService" class="com.test.downloadService"
init-method="startUp" destroy-method="shutDown"
p:throttlingEnabled="${sw.throttle.enable}" />
The application containing business.beans deploys well, but the application containing applicationContext.xml throw run time error "could not resolve placeholder sw.throttle.enable"
Note -
Both the applications are deployed in a OsGi Context.
Spring version is 3.0.1
Edit -
The applicationContext.xml has another bean defined as below. Could this be the cause?
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
</bean>
The issue was resolved by setting "ignoreUnresolvablePlaceholders" to "true". Apparently business.beans had nothing to do with the issue
Below is the modified configuration which solved the issue
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="placeholderPrefix" value="${sw." />
<property name="location" value="file:///etc/data.properties" />
<property name="ignoreResourceNotFound" value="true" />
<property name="ignoreUnresolvablePlaceHolders" value="true"
</bean>
Thanks StackOverflow for the answer +1

Loading Bean property values from context.xml

Currently we are loading our JDBC source values from properties file as per following:
<context:property-placeholder location="classpath:master.properties" ignore-unresolvable="true" />
<bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource"
destroy-method="close">
<property name="driverClass" value="${database.driver}" />
<property name="jdbcUrl" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
<property name="idleConnectionTestPeriod" value="60" />
<property name="idleMaxAge" value="240" />
<property name="maxConnectionsPerPartition" value="2" />
<property name="minConnectionsPerPartition" value="2" />
<property name="partitionCount" value="3" />
<property name="acquireIncrement" value="10" />
<property name="statementsCacheSize" value="50" />
<property name="releaseHelperThreads" value="3" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"
scope="singleton">
<property name="targetDataSource">
<ref local="mainDataSource" />
</property>
</bean>
This seg. works fine with classpath based app.properties file and get rid of app.properties.
We would like to load this values from context.xml (either placed in META-INF or $CATALINA_HOME/conf/context.xml). It will help us load proper values at prod/staging servers.
Will appreciate any help or alternate method/suggestions. (If similar question is already answered, please share the link)
Thanks!
As Alan Hay mentioned you could externalize the datasource configuration into Tomcat's own context.xml and then have Spring do a JNDI lookup to retrieve it. This is an approach that I've commonly used on some of the projects I've worked on.
The pieces you need to put in place to achieve would be:
1. Add the datasource configuration to $CATALINA_HOME/conf/context.xml
<GlobalNamingResources>
<Resource type="javax.sql.DataSource"
name="dsName"
factory="com.jolbox.bonecp.BoneCPDataSource"
driverClassName="your.driver.classname"
jdbcUrl="your:driver:url"
username="username"
password="password"
idleMaxAge="240"
idleConnectionTestPeriod="60"
partitionCount="3"
acquireIncrement="10"
maxConnectionsPerPartition="2"
minConnectionsPerPartition="2"
statementsCacheSize="50"
releaseHelperThreads="3" />
</GlobalNamingResources>
2. Add a resource link in the application's META-INF/context.xml
<Context path="/YourApp">
<ResourceLink description="Datasource for YourApp"
global="jdbc/dsName"
name="jdbc/dsName"
type="javax.sql.DataSource" />
</Context>
3. Modify the Spring config to lookup the datasource in JNDI
<beans xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/jee classpath:/org/springframework/ejb/config/spring-jee-3.0.xsd">
<jee:jndi-lookup id="dataSource"
jndi-name="java:comp/env/jdbc/dsName" />
4. Move the driver and datasource jars
Since the datasource configuration is now container managed, you should place the database driver and datasource jars into $CATALINA_HOME/lib so they are available to Tomcat when it creates the datasource. These jars should no longer need to reside in the WEB-INF/lib of your application.
The way I do it, I have default properties file in my classpath, and I have one properties file that I use to override those default (development) properties:
in my spring file:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/>
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
<value>classpath:camel.properties</value>
<value>classpath:email.properties</value>
<value>${external_config}</value>
</list>
</property>
</bean>
In development, I use the properties file in the classpath.
On the different envionment, staging, integration, production we start the application with the following parameter:
-Dexternal_config=file:c:/staging.properties
That way I have the same build for all environments and can choose the location of my overriding properties file.
So, ${external_config} is a place holder for a configuration file that depends on the environment.
Spring looks for an environment variable named external_config, that variable should point to a configuration file. If the file is not found, Spring ignores it with ignoreResourceNotFound = true;
Spring 3.1 introduced support for environment specific profiles. Define some profiles, associate them with some properties files e.g. test.properties, live.properties and set an environment variable on server start -Dspring.profiles.active=Test. Clean and simple.
http://spring.io/blog/2011/02/11/spring-framework-3-1-m1-released/
Other option as hinted at above is to shift to a container managed Connection Pool looked up via JNDI i.e define a JNDI datasource named xyz the same on each server and then:

How to read jBoss configuration files in Spring?

I want to have a project independent configuration file that I can access from different projects. What I'm currently trying (and does not give me good results at all):
<bean id="wroProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="${JBOSS_HOME}/standalone/configuration/wro.properties" />
</bean>
I use Spring 3 and JBoss 7.1. My configuration files are under jboss/standalone/configuration/....properties. Besides that I want to read message files from that same directory with:
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames" value="messages,local" />
<property name="useCodeAsDefaultMessage" value="true" />
</bean>
Currently it looks for messages.properties and local.properties in src folder?
This is the solution I ended up using, which is platform independent and portable:
<bean id="wroProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="file:#{systemProperties['jboss.home.dir']}/standalone/configuration/wro.properties" />
</bean>
The configuration of the message source is identical.
A ResourceBundleMessageSource uses the basenames provided to (and the locale) to build a resource name (ex. message.properties) which is eventually (in the call stack) used by java.util.ResourceBundle.Control#newBundle(...). This resource name is then looked for on the classpath starting at its root (ex. /message.properties).
If you're on an IDE like Eclipse, your classpath very likely starts at src.
If jboss/standalone/configuration/... is on your classpath as well and the properties file are in there, you can change the basenames to
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames" value="jboss/standalone/configuration/messages,jboss/standalone/configuration/local" />
<property name="useCodeAsDefaultMessage" value="true" />
</bean>

How to collect spring properties from multiple files for use on a single bean

I haven't gotten my head wrapped around Spring yet, so correct me if this question doesn't make sense...
I have a PropertyPlaceholderConfigurer
<bean id="rdbmPropertiesPlacholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" lazy-init="false">
<property name="location" value="classpath:/properties/rdbm.properties" />
</bean>
And I have a bean being injected I guess?
<bean id="PortalDb" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${hibernate.connection.driver_class}" />
<property name="url" value="${hibernate.connection.url}" />
<property name="username" value="${hibernate.connection.username}" />
<property name="password" value="${hibernate.connection.password}" />
...
What I want is a second placeholder pointing to a different properties file with the username/password so that I can split up the properties into two different files. Then the database connection information can be separate from the db username/password, and I can source control one and not the other.
I've tried basically copying the rdbmPropertiesPlaceholder with a different id and file and trying to access the properties, but it doesn't work.
This code is from the uPortal open source web portal project.
Using this notation lets you specify multiple files:
<bean id="rdbmPropertiesPlacholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" lazy-init="false">
<property name="locations">
<list>
<value>classpath:/properties/rdbm.properties</value>
<value>classpath:/properties/passwords.properties</value>
</list>
</property>
</bean>
The propertyplaceholderconfigurerer just merges all of these to look like there's only one, so your bean definitions do not know where the properties come from.
The org.springframework.beans.factory.config.PropertyPlaceholderConfigurer can do this (as already answered. What you may want to do is make use of the name spacing so that you can refer to same-named properties from both files without ambiquity. For your example, you can do this:
<bean id="generalPropertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:/properties/general.properties"/>
</bean>
<bean id="db.PropertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:/properties/rdbm.properties" />
<property name="placeholderPrefix" value="$db{" />
<property name="placeholderSuffix" value="}" />
</bean>
In your context files, you can now refer to general properties with ${someproperty}, and refer to rdbm properties with $db{someproperty}.
This will make your context files much cleaner and clearer to the developer.

Categories