Conditionally including beans in XML ArrayList - java

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.

Related

Restlet Framework and Spring - Global filter

I'm having a problem with RESTlet Framework configuration with Spring. I want to have one global filter for all requests and responses. I guess I can use Filter class and it's methods beforeHandle, afterHandle and setNext like this:
Filter.beforeHandle() -> Router -> Filter.afterHandle()
The problem is, that I'm using Spring configured RESTlet and I don't know if the regular Filter will work correctly with SpringRouter from org.restlet.ext.spring package. My current restlet configuration is as follows:
<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 id="root" class="org.restlet.ext.spring.SpringRouter">
<property name="attachments">
<map>
<entry key="/login">
<bean class="org.restlet.ext.spring.SpringFinder">
<lookup-method name="create"
bean="loginResource" />
</bean>
</entry>
</map>
</property>
</bean>
</beans>
I'm thinking about adding a bean with id root and class that extends class Filter, and pass to it as property next a bean with id router (which currently is called root). What do you think about this solution?
Mixing Restlet classes from the Spring extension with other one shouldn't be an issue. Spring* classes only provide additional configurability.

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.

Can one Spring PropertyPlaceholderConfigurer configure another one?

I have a PropertyPlaceholderConfigurer like this:
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath:assuredlabor/margarita-${runningMode}.properties</value>
</list>
</property>
</bean>
I would like to be able to specify my running mode in web.xml like this:
<context-param>
<param-name>runningMode</param-name>
<param-value>production</param-value>
</context-param>
So I put this bean ABOVE the 'main' property bean I described above:
<bean id="servletPropertyPlaceholderConfigurer" class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
</bean>
But that doesn't seem to work.
Is this possible with Spring? I am using version 2.5 right now.
I found this similar question:
PropertyPlaceholderConfigurer with Tomcat & ContextLoaderListener
But there is no discussion of the ServletContextPropertyPlaceholderConfigurer, so I think it is a legitimate question.
You can't do this in spring 2, without some custom coding I don't think, since one property placeholder cannot configure another.
You need to use spring 3 to get this out of the box. To accomplish this, you have to create a bean that somehow has the value you want, and use spring-el to reference that spring when setting up your property placeholder. There's a special bean for getting individual servlet context parameters as show below:
<bean id="runningMode" class="org.springframework.web.context.support.ServletContextAttributeFactoryBean">
<property name="attributeName" value="runningMode" />
</bean>
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath:assuredlabor/margarita-#{runningMode}.properties</value>
</list>
</property>
</bean>
And then you can just refer to any of the properties in the normal ${} syntax
From the source code:
Subclass of PropertyPlaceholderConfigurer that resolves placeholders as ServletContext init parameters (that is, web.xml context-param entries).
Can be combined with "locations" and/or "properties" values in addition to web.xml context-params. Alternatively, can be defined without local properties, to resolve all placeholders as web.xml context-params (or JVM system properties).
If a placeholder could not be resolved against the provided local properties within the application, this configurer will fall back to ServletContext parameters. Can also be configured to let ServletContext init parameters override local properties (contextOverride=true).
Optionally supports searching for ServletContext attributes: If turned on, an otherwise unresolvable placeholder will matched against the corresponding ServletContext attribute, using its stringified value if found. This can be used to feed dynamic values into Spring's placeholder resolution.
If not running within a WebApplicationContext (or any other context that is able to satisfy the ServletContextAware callback), this class will behave like the default PropertyPlaceholderConfigurer. This allows for keeping ServletContextPropertyPlaceholderConfigurer definitions in test suites.
As I understand it, that implies that you can use just a single configurer:
<bean id="propertyPlaceholderConfigurer" class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath:assuredlabor/margarita-${runningMode}.properties</value>
</list>
</property>
</bean>

Is there a built-in Spring environment variable for the web context root?

I'm using Spring Web Services to expose a service as a web service. In my spring configuration xml file, I have a bean which is an instance of DefaultWsdl11Definition. One of the properties that needs to be set is the locationUri. This needs to be a fully qualified Uri, but I don't want to have to change this value when the application gets promoted from dev to uat and to production. Spring knows what the web application context root is, so is there a variable that I can specify in my configuration file to access it?
Something like:
<bean id="myWebServices"
class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
<property name="schemaCollection">
<bean
class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection">
<property name="xsds" ref="xsdList"/>
<property name="inline" value="true" />
</bean>
</property>
<property name="portTypeName" value="myWebServices" />
<property name="locationUri" value="${webContextRoot}/webServices" />
</bean>
With Spring 3.0, you should be able to access the servlet context through the servletContext bean in the web application context:
<property name="locationUri" value="#{servletContext.contextPath}/webServices" />
If you're using pre-Spring-EL (before 3.0), you should be able to do
<bean name="servletContextBean" class="org.springframework.web.context.support.ServletContextFactoryBean" />
<bean name="contextPath" factory-bean="servletContextBean" factory-method="getContextPath" />
<bean name="locationUri" factory-bean="contextPath" factory-method="concat">
<constructor-arg value="/webServices" />
</bean>
and inside your myWebservices bean
<property name="locationUri" ref="locationUri" />
EDIT:
I don't think getting the server name and port from the ServletContext, as depending on the setup the web container may not know the hostname (i.e. a HTTP server may be in front of the web container, e.g. tomcat may be behind an Apache web server or depending on the Websphere configuration).
However, the following may be part of a solution to get the hostname. With Spring 3.0, you could do the following:
<property name="host"
class="java.net.InetAddress"
factory-method="getLocalHost"/>
<property name="locationUri"
value="http://#{host.canonicalHostName}:8080/#{servletContext.contextPath}/webServices" />
I had a similar problem that you described, I use property files to do this
ws_dev.properties
ws_prod.properties
I configured my property file like this, The deployment property is java vm argument like
-Ddeployment=dev
<context:property-placeholder location="ws_${deployment}.properties"/>
May be late, but may some other need a solution too:
set property in servlet:
web.xml
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/spring-ws-context.xml</param-value>
</init-param>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
The bean declaration in spring-ws-context.xml:
<bean id="WebService"
class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition"
p:portTypeName="App" p:locationUri="/WebServices" p:requestSuffix="Request"
p:responseSuffix="Response">
<property name="schema">
<bean class="org.springframework.xml.xsd.SimpleXsdSchema" p:xsd="classpath:/requestTypes.xsd" />
</property>
</bean>
You can add ApplicationContextAware interface to your bean, cast it to WebApplicationContext and then get ServletContext. Also see class org.springframework.web.context.ContextLoader

Spring security 2.0.5. custom login form. Cannot see errors in language other than English

I've got my Spring Security custom login form working. It displays errors if the user has input bad credentials, or is expired, etc.
Looking inside spring-security-core-2.0.5.RELEASE.jar, I notice the following files in the org.springframework.security package:
messages.properties
messages_cs_CZ.properties
messages_de.properties
messages_fr.properties
...etc...
and notice that they have the localised versions of the strings.
Setting my browser's preferred language to French doesn't make the French version of the string appear. What am I missing?
PUK
Fixed it:
In my applicationContext.xml I include the Spring Security messages by adding another basename:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>com.myapp.web.my_messages</value>
<value>org.springframework.security.messages</value>
</list>
</property>
</bean>
In my web.xml I added another listener:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

Categories

Resources