Spring mvc ResourceBundleMessageSource for different themes - java

I configures my appstrings.properties file which contains strings related to theme used by my application. There are two themes for my application. Both have their own appstrings.properties file located at WEB-INF/strings/theme1/appstrings and WEB-INF/strings/theme2/appstrings. I specified property themeName in config.properties file.
Here is my spring config file:
<context:property-placeholder location="file:///${config.properties}" />
...
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="WEB-INF/strings/theme1/appstrings" />
Right now all my app strings are coming from WEB-INF/strings/theme1/appstrings.properties file. How can I make it dynamic. i.e. when I change themeName propperty to theme2 it should get string from WEB-INF/strings/theme2/appstrings.properties

You need to use a ResourceBundleThemeSource
<!-- resolves localized <theme_name>.properties files in the classpath to
allow for theme support -->
<bean
class="org.springframework.ui.context.support.ResourceBundleThemeSource"
id="themeSource" />
<mvc:interceptors>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
</mvc:interceptors>
See Spring Reference Chapter 15.7 Using Themes
For an running example you can quickly create a small Spring Roo application. It uses the theme support to change the css files.

If config.properties contains a property say: themeName = propertyValue. If you want to use this themeName's value in spring mvc configuration servlet xml file then you can use ${themeName}
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="WEB-INF/strings/${themeName}/appstrings" />
reference

Related

Spring Data Context - lookup placeholder variables from Java map, not properties file

Currently in my data context XML file, it's looking up values to substitute from a application.properties file:
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" lazy-init="default">
<property name="location" value="classpath:application.properties" />
</bean>
<bean id="appleDataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="url" value="${apple.url}" />
</bean>
I'd like to change this from being looked up from the application.properties file, to being read out of a Properties/Map object.
This is because the configuration could come from more than one place (i.e. not just the classpath), and this logic is already implemented in my application.
I've seen MapPropertySource but I think while that can be done when the bean is configured in Java, I'm not sure this logic can be implemented when working with the XML file alone?

Conditionally including beans in XML ArrayList

I was wondering if it's possible to somehow conditionally include spring beans depending on some property.
In my applicationContext.xml I have a list of beans that I setup:
<bean id="server1Config" class="... />
<bean id="server2Config" class="... />
<bean id="server3Config" class="... />
...
Then I include them in a list:
<bean class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="server1Config"/>
<ref bean="server2Config"/>
<ref bean="server3Config"/>
...
</list>
</constructor-arg>
</bean>
I want to conditionally include server1Config, server2Config, server3Config, etc depending on whether ${includeServer1} == true, ${includeServer2} == true etc and if possible, only initialize those beans if they are marked for inclusion.
To clarify, it's a ping service checking if servers are online or not, each bean contains special urls. If I have 5 servers running, I'd like to set in my config includeServer1=true ... includeServer5=true ... includeServer6=false, if I shutdown server2, I'd like to change includeServer2=false before shutting down the server to not get bombarded with SMSe telling me server2 is offline.
As your names refer to different stages or enviroments, spring profiles might be helpful to use. You can define beans like this inside your context.xml
<beans profile="dev">
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
<jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
</jdbc:embedded-database>
</beans>
<beans profile="production">
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>
In the example [1] you see the usage of two profiles called "dev" and "production".
Spring will always load every bean without a profile
Depending on the profiles (yes, you can load multiple profiles at once) all the related beans will be loaded
Loading a profile in Java:
ctx.getEnvironment().setActiveProfiles("dev");
Loading two profiles
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
Loading from CMD Line declaratively:
-Dspring.profiles.active="profile1,profile2"
Usage in web.xml (can be comma-separated)
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>spring.profiles.active</param-name>
<param-value>production</param-value>
</init-param>
</servlet>
#Comment: If you want to do it using properties and you are able to use newer spring elements, annotations etc. please have a look at this tutorial [2] to make it work with properties file as you commented below.
[1] http://spring.io/blog/2011/02/11/spring-framework-3-1-m1-released/
[2] http://kielczewski.eu/2013/11/setting-active-profile-and-property-sources-in-spring-mvc/
This is almost an add-on to #swinkler's answer.
He gave the first part of the solution which is usage of Spring 3.1+ profiles.
The second part would be to use a kind of automatic registration :
<bean class="java.util.ArrayList" id="serverConfigList"/>
<beans profile="server1">
<bean id="server1Config" class="... />
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject"><ref local="serverConfigList"/></property>
<property name="targetMethod"><value>add</value></property>
<property name="arguments"><ref local="server1Config/></property>
</bean>
</beans>
That way you create an empy list and only add relevant configs to it.
Your code shouldn't change based on environment. If your aim is to use different settings for each environment then load them as properties at start up.
Refer this for 'external configuration'
This can be done in Spring framework 3.1 onwards using a built in Spring environment profiles.
Here's a few resources:
http://java.dzone.com/articles/spring-31-environment-profiles
Hope this helps.

Spring Message Not Displaying

I am trying to do internationalization in Spring-MVC for the first time and I'm having what I assume to be a configuration issue. I have a NLS file that I named NLS_en.properties which I placed in my application's WEB-INF\classes directory. The file contains the following NLS string:
MSG_HELLO = Hello to the Internationalized World
In my application's servlet.xml file I've defined the following beans:
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en" />
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="WEB-INF/classes/NLS"/>
</bean>
In my JSP file I have the following tag:
<p><spring:message code="MSG_HELLO" text="You should not be seeing this text" />
When the JSP displays, of course, the message I see is the one I should not be seeing, so how do I have to configure my application so that I do see my HELLO message?
ResourceBundleMessageSource basename (as opposed to ReloadableResourceBundleMessageSource) refers by default to the classpath, so you should have it like :
<property name="basename" value="NLS" />
Now, depending on how you build, even if configuring correctly the message source, it may have been erased at the time you run the application.
Do not place resources directly into classes (or any target directory in general). If you use maven place it directly into resources. If you dont use any build framework put it in the root of the source directory.

Is it possible to specify a context property placeholder at runtime

I have a standalone jar that uses spring. The config in my spring xml uses placeholders of which I've been replacing when compiling with maven. Example spring config:
<bean id="foo" class="package.Foo">
<property name="host" value="${db.host}" />
</bean>
Instead of replacing ${db.host} using maven I'd like to pass in a properties file at runtime, e.g.
java -jar Application.jar productionDB.properties
This would allow me to switch the db host at runtime by passing in the production db properties file or the testing db properties file.
Is it possible to do this or are there any better ways of achieving the same goal?
You could specify your property file as a System Property, e.g.:
java -jar Application.jar -DappConfig=/path/to/productionDB.properties
Then you should be able to reference that in your application context:
<context:property-placeholder location="file:${appConfig}"/>
<bean id="foo" class="package.Foo">
<property name="host" value="${db.host}" />
</bean>
You could use a PropertyPlaceholderConfigurer to use a .properties file to pass in the required variables.
<bean id="placeholderConfig"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:productionDB.properties</value>
</list>
</property>
</bean>
You can leave your bean declaration as is. The properties will be automatically taken from the productionDB.properties file.
There are a few options:
Set your resources via your container's JNDI and use Spring's <jee:jndi-lookup/>.
Use Spring's <context:property-placeholder location="classpath:/myProps.properties" />. I prefer this short-hand over the "full" bean definition because Spring will automatically use the correct implementation (PropertyPlaceholderConfigurer for Spring < 3.1, or PropertySourcesPlaceholderConfigurer for Spring 3.1+). Using this configuration, you would just drop the myProps.properties at the root of your classpath (${TOMCAT_HOME}/lib for example).
You can pass the values using the context:property-placeholder. So your setup would be something like:
<context:property-placeholder location="file://opt/db.properties"/>
Then when you are wiring up your Foo service, you can use the property names in your config, such as
<bean id="foo" class="package.Foo">
<property name="host" value="${db.host}" />
</bean>
Then just use the different set of files for each environmnet
See the spring docs for more details.

Spring MVC - Is it possible for a jar file to refer to a properties file that is not in the jar file?

I have a spring MVC web application that has the following structure:
myapp
|-META-INF
|-WEB-INF
|-classes
| |-conf
|-application.properties
|-lib
| |-externalApp.jar
| |-conf
| |-applicationContext.xml
|
|-applicationContext.xml
|-myapp-servlet.xml
In myapp/WEB-INF/applicationContext, i imported the applicationContext.xml file that is in the jar file as shown below:
<import resource="classpath:WEB-INF/conf/applicationContext.xml" />
The beans in the imported resource work fine and i can see them in my web application's controller/service classes.
The problem i have is that the
context file in the jar file (i.e. WEB-INF/lib/externalApp.jar/applicationContext.xml) has configuration for loading a properties file. The properties have to be set by the web application so the properties file is in the webapp. The configuration in the jar file's context file looks like this:
I want the above property to load the property file that is in the web application so i set its value to be as shown below:
<bean class="com.myapp.ExternalAppPropertyPlaceholderConfigurer">
<property name="location" value="classpath:conf/application.properties" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
With the above setting, the classes in the jar file that expect these properties to be availbe still cant get access to the properties.
The question i guess is how can i get the properties file that is in WEB-INF/classes/conf/application.properties to be accessible to the objects in the jar file that is located in WEB-INF/lib/externalApp.jar.
Looking at the stack traces i am getting, it looks as though the objects referred in the imported context file are loaded first before the properties are loaded which is not i want.
Thanks.
You can use the classpath*: prefix like this
<bean class="com.myapp.ExternalAppPropertyPlaceholderConfigurer">
<property name="location" value="classpath*:conf/application.properties" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
EDIT
Since your conf/application.properties is in your web app, you must define it in your web-app applicationContext (not in the jar as you do now). And define it before importing the applicationContext of your jar. i.e. put something like this in your web-app applicationContext:
<bean class="com.myapp.ExternalAppPropertyPlaceholderConfigurer">
<property name="location" value="classpath:conf/application.properties" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
<import resource="classpath*:/conf/applicationContext.xml" />
and remove the declaration of the properties from your jar applicationContext.

Categories

Resources