tags:

 Sometimes, when we using Spring we need to define beans such as dataSource or taskExecutor and pass its parameters as properties. In our example we will create new ThreadPoolTaskExecutor which will be used as thread pool for our tasks.

 

Basic configuration for such bean is very straight forward:

 

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">

<property name="corePoolSize" value="5" />

<property name="maxPoolSize" value="10" />

<property name="queueCapacity" value="25" />

 

This example creates thread pool with minimum of 5 threads maximum 10 threads and queue capacity of 25.

 

Sometimes (and Spring allows us to do it as “out of the box” functionality)it might be very useful to declare those values explicitly in external properties file. It could be easily achieved by using PropertyPlaceholderConfigurer class

 

Let's see the example:

 

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">

<property name="corePoolSize" value="${corePoolSize}" />

<property name="maxPoolSize" value="${maxPoolSize}" />

<property name="queueCapacity" value="${queueCapacity}" />

</bean>

 

<bean class="corg.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

<property name="location">

<value>pool.properties</value>

</property>

 

or even if we are using Spring version 2.5 or older we can configure it using context namespace

 

<context:property-placeholder location="pool.properties"/>

 

and our pool.properties file looks like this: 

corePoolSize = 5

maxPoolSize = 10

queueCapacity = 25

 

Well. So far so good, but recently, working on external plug-in for Jboss application on one of our customers project, I've had the following challenge:  

 

All properties values are centralized and stored in external database table. So what I needed to do is to fetch all those relevant properties values from database and pass it to ThreadPoolTaskExecutor bean in Spring ApplicationContext.xml.

After reading some documentation and playing with code I've found that PropertyPlaceHolderConfigurer extends abstract class PropertiesLoaderSupport and protected void loadProperties(Properties props) call from super class. Therefore, the trick is very simple. We will extend our class from PropertyPlaceHolderConfigurer and override loadProperties function where properties are retrieved using JdbcTemplate.

 

The code in such case looks like this:

 

public class ThreadPoolPropertyPlaceholderConfigurer extends
		PropertyPlaceholderConfigurer {

           private JdbcTemplate jdbcTemplate;
      private String nameColumn;
      private String valueColumn;
      private String tableName;

	public ThreadPoolPropertyPlaceholderConfigurer(){
		super();
		setPlaceholderPrefix("${");
	}
	
	@Override
	  protected void loadProperties(final Properties props) throws IOException {
	    if (null == props) {
	      throw new IOException("No properties passed by Spring framework - cannot proceed");
	    }
	 String sql = String.format("select %s, %s from %s", nameColumn, valueColumn, propertiesTable);
           log.info("Reading configuration properties from database");
           try {
           jdbcTemplate.query(sql, new RowCallbackHandler() {
      public void processRow(ResultSet rs) throws SQLException {
       String name = rs.getString(nameColumn);
       String value = rs.getString(valueColumn);
               if (null == name || null == value) {
		 throw new SQLException("Configuration database contains empty data. Name='" + name + "' Value='" + value + "'");
		}
              props.setProperty(name, value);
        }
         });
       } catch (Exception e) {
     log.fatal("There is an error in either 'application.properties' or the configuration database.");
     throw new IOException(e);
        }
     if (props.size() == 0) {
    log.fatal("The configuration database could not be reached or does not contain any properties in '" + propertiesTable + "'");
   }	    
	}
  //all setters omitted.
}  

<bean id="threadPoolProperties" class="com.vanilla.ThreadPoolPropertyPlaceHolderConfigurer">

     <property name="nameColumn" value="name" />

     <property name="valueColumn" value="value" />

     <property name="tableName" value="someTableName" />

     <property name="jdbcTemplate" value="someJdbcTemplate" />

</bean>

As the parameters to this bean we pass the following properties:

 

* ignoreUnresolvablePlaceholders – whether we will swallow exception on unknown placeholder.

* nameColumn – column name for the properties key values:

* valueColumn – values for those keys.

* TableName – table where all these properties stored. 

 

Let's declare our ThreadPoolTaskExecutor:

 

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">

    <property name="corePoolSize" value="${corePoolSize}" />

    <property name="maxPoolSize" value="${maxPoolSize}" />

    <property name="queueCapacity" value="${queueCapacity}" />

</bean>