Deployment – Spring – Overriding properties when deploying in a multi-server environment

I found myself wanting to have certain property values in my Spring projects differ based on what server the app is being deployed.

For example your company has dev, test, qa, prod boxes etc… But there are certain properties in your app such as default db username and passwords, database name, thread pool configurations, etc… that are specific to the server or environment where the app is running.

The technique presented in this tutorial allows you to place all common and default properties in a properties file and provide overrides based on the hostname of the server where the app is running.

For example you can have a application.myDevBoxHostName.properties that will allow you to load property values associated to your own local environment versus a application.myCompany.com.properties that will load the right set of properties in production servers. Also you can have simply application.properties to load all properties that are common or with default values for all environments that do not override properties

This tutorial is available for download with svn:

svn checkout http://raulrajatutorials.googlecode.com/svn/trunk/ raulrajatutorials-read-only

Comments in the code itself should be self-explanatory if you already have some java + spring experience

And now to the point.

applicationContext.xml

<?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">
 
    <!--
    This service allows loading of properties based on hostname supporting default values in application.properties and allowing
    other servers to override the default property values in their own server specific application._HOST_NAME_.properties
    -->
    <bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="systemPropertiesMode" value="1"/>
        <property name="locations">
            <list>
                <value>/WEB-INF/conf/application.properties</value>
                <!--
                    In deployments servers: /WEB-INF/conf/application._HOST_NAME_.properties will override properties in application.properties.
                    based on the hostname in the deployed server
                -->
                <bean class="com.raulraja.util.deployment.CompositeStringResourceProvider" factory-method="getReplacedResource">
                    <constructor-arg>
                        <bean class="com.raulraja.util.deployment.impl.SpringInjectedServletContextProviderImpl" />
                    </constructor-arg>
                    <constructor-arg value="/WEB-INF/conf/application._HOST_NAME_.properties"/>
                </bean>
            </list>
        </property>
        <property name="ignoreResourceNotFound" value="true"/>
    </bean>
 
    <!-- This is a sample service that will get properties injected and will display its values on initialization -->
    <bean id="sampleService" class="com.raulraja.util.deployment.impl.SampleServiceImpl" init-method="init">
        <property name="firstProperty" value="${first.property.placeholder}" />
        <property name="secondProperty" value="${second.property.placeholder}" />
    </bean>
 
</beans>

application.properties

#In this file live all common properties and default property values for all servers
first.property.placeholder=this value was declared in application.properties
second.property.placeholder=this value was declared in application.properties

application.yourHostNameHere.properties

# This file contains properties overriden for the host name were the app is being deployed
second.property.placeholder=this value is overriden in a specific server config declared in application.properties

CompositeStringResourceProvider.java

package com.raulraja.util.deployment;
 
import org.apache.log4j.Logger;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.context.support.ServletContextResource;
 
import java.net.UnknownHostException;
import java.net.InetAddress;
 
/**
 * A service that provides a resource based on the host name
 */
public class CompositeStringResourceProvider {
 
    private final static Logger log = Logger.getLogger(CompositeStringResourceProvider.class);
 
    private final static String HOSTNAME_PLACEHOLDER = "_HOST_NAME_";
 
	/**
	 * This method is invoked by the container at startup
	 * @param servletContextProvider a servlet context provider
	 * @param baseResource the base resource
	 * @return the resource assigned to the current running server
	 * @throws UnknownHostException if the host is unknown
	 */
    public static Resource getReplacedResource(ServletContextProvider servletContextProvider, String baseResource) throws UnknownHostException {
        InetAddress localhost = InetAddress.getLocalHost();
        baseResource = baseResource.replaceAll(HOSTNAME_PLACEHOLDER, localhost.getHostName());
        Resource resource = null;
        if (servletContextProvider.getServletContext() != null) {
            resource = new ServletContextResource(servletContextProvider.getServletContext(), baseResource);
            if (resource.exists()) {
                log.debug("Loading override for common properties: " + resource.getFilename());
            }
        } else {
            resource = new ClassPathResource(baseResource);
        }
 
        return resource;
    }
 
}

ServletContextProvider.java

package com.raulraja.util.deployment;
 
import javax.servlet.ServletContext;
 
/**
 * Provides a servlet context
 */
public interface ServletContextProvider {
 
	/**
	 * @return the servlet context
	 */
    ServletContext getServletContext();
 
}

SpringInjectedServletContextProviderImpl.java

package com.raulraja.util.deployment.impl;
 
 
import com.raulraja.util.deployment.ServletContextProvider;
import org.springframework.web.context.ServletContextAware;
 
import javax.servlet.ServletContext;
 
/**
 * Spring based impl of the ServletContextProvider
 */
public class SpringInjectedServletContextProviderImpl implements ServletContextProvider, ServletContextAware {
 
	/**
	 * the servlet context
	 */
    private ServletContext servletContext;
 
	/**
	 * @return the servlet context
	 */
    public ServletContext getServletContext() {
        return servletContext;
    }
 
	/**
	 * sets the servlet context, invoked by the container at startup since this service implements ServletContextAware 
	 * @param servletContext the servlet context
	 */
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }
}

SampleServiceImpl.java

package com.raulraja.util.deployment.impl;
 
import org.apache.log4j.Logger;
 
/**
 * Demonstrates how values of properties are injected based on a specific hostname config
 */
public class SampleServiceImpl {
 
	private final static Logger log = Logger.getLogger(SampleServiceImpl.class);
 
	/**
	 * the first prperty
	 */
	private String firstProperty;
 
	/**
	 * the second property
	 */
	private String secondProperty;
 
	/**
	 * service initialization method
	 */
	public void init() {
		log.debug("first property: " + firstProperty);
		log.debug("second property: " + secondProperty);
	}
 
	/**
	 * sets the first property
	 * @param firstProperty the first property
	 */
	public void setFirstProperty(String firstProperty) {
		this.firstProperty = firstProperty;
	}
 
	/**
	 * sets the second property
	 * @param secondProperty the second property
	 */
	public void setSecondProperty(String secondProperty) {
		this.secondProperty = secondProperty;
	}
}

Now notice that my local machine hostname is raul-raja-martinezs-macbook.local

Before application.raul-raja-martinezs-macbook.local.properties existed:

06/13 17:49:52 WARN org.springframework.beans.factory.config.PropertyPlaceholderConfigurer – Could not load properties from ServletContext resource [/WEB-INF/conf/application.raul-raja-martinezs-macbook.local.properties]: Could not open ServletContext resource [/WEB-INF/conf/application.raul-raja-martinezs-macbook.local.properties]
06/13 18:00:47 DEBUG com.raulraja.util.deployment.impl.SampleServiceImpl – first property: this value was declared in application.properties
06/13 18:00:47 DEBUG com.raulraja.util.deployment.impl.SampleServiceImpl - second property: this value was declared in application.properties

After application.raul-raja-martinezs-macbook.local.properties existed:

06/13 18:03:52 DEBUG com.raulraja.util.deployment.CompositeStringResourceProvider – Loading override for common properties: application.raul-raja-martinezs-macbook.local.properties
06/13 18:03:52 DEBUG com.raulraja.util.deployment.impl.SampleServiceImpl – first property: this value was declared in application.properties
06/13 18:03:52 DEBUG com.raulraja.util.deployment.impl.SampleServiceImpl – second property: this value is overriden in a specific server config declared in application.properties

AOP – Spring – Hibernate Sessions for background threads / jobs

Getting your persistence access right when working with background jobs in Spring can be tricky. Most people rely on the Open Session In View pattern using Filters or Interceptors that act on the regular app server threads and close and open sessions for each request.

This technique is not available when you need access to your persistence context from a Quartz Scheduled Job or a TimerTask. The purpose of this tutorials is to show you how you can use Spring AOP proxies to wire a hibernate interceptor that gives you access to the persistence context and it takes cares of closing and opening the sessions for you.

This tutorial is available for download with svn:

svn checkout http://raulrajatutorials.googlecode.com/svn/trunk/ raulrajatutorials-read-only

Comments in the code itself should be self-explanatory if you already have some java + spring experience

And now to the point.

ApplicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 
 
    <!-- The datasource -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
			<property name="driverClass" value="org.postgresql.Driver" />
			<property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/tutorials?autoReconnect=true" />
			<property name="user" value="tutorials" />
			<property name="password" value="tutorials" />
	</bean>
 
    <!-- The hibernate session factory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="configLocations">
            <list>
                <value>WEB-INF/conf/hibernate.cfg.xml</value>
            </list>
        </property>
        <property name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
        <property name="dataSource">
            <ref bean="dataSource"/>
        </property>
    </bean>
 
    <!-- The Hibernate interceptor, which takes care of opening and closing hibernate session around method calls. -->
    <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate3.HibernateInterceptor">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
    </bean>
 
    <!-- The quartz scheduler in charge of running background jobs -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" destroy-method="destroy">
        <property name="triggers">
            <list>
               <ref bean="testBackgroundJobTrigger"/>
            </list>
        </property>
        <property name="quartzProperties">
            <props>
                <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
                <prop key="org.quartz.threadPool.threadCount">20</prop>
                <prop key="org.quartz.threadPool.threadPriority">2</prop>
            </props>
        </property>
    </bean>
 
    <!-- A trigger bean with config info on how to run the background job -->
    <bean id="testBackgroundJobTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
        <property name="jobDetail" ref="testBackgroundJobDetail"/>
        <property name="startDelay" value="10000"/>
        <property name="repeatInterval" value="10000" />
    </bean>
 
    <!-- The actual background job impl that we're going to run -->
    <bean id="testBackgroundJob" class="com.raulraja.util.jobs.impl.TestBackgroundJobImpl" autowire="autodetect" />
 
    <!-- A proxy with the hibernate interceptor wired in so it can access the persistent context -->
    <bean id="testBackgroundJobProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target">
            <ref bean="testBackgroundJob"/>
        </property>
        <property name="proxyInterfaces">
            <value>java.lang.Runnable</value>
        </property>
        <property name="interceptorNames">
            <value>hibernateInterceptor</value>
        </property>
    </bean>
 
    <!-- Detail info about the job -->
    <bean id="testBackgroundJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="testBackgroundJobProxy"/>
        <property name="targetMethod" value="run"/>
        <property name="concurrent" value="false"/>
    </bean>
 
</beans>

TestBackgroundJobImpl.java

package com.raulraja.util.jobs.impl;
 
import org.apache.log4j.Logger;
 
/**
 * Test job that runs on the background
 */
public class TestBackgroundJobImpl implements Runnable {
 
	private final static Logger logger = Logger.getLogger(TestBackgroundJobImpl.class);
 
	/**
	 * Do something in the background
	 */
	public void run() {
		logger.debug("doing something in the background");
	}
}

Output


06/13 15:05:00 DEBUG org.springframework.orm.hibernate3.SessionFactoryUtils - Opening Hibernate Session
06/13 15:05:00 DEBUG com.raulraja.util.jobs.impl.TestBackgroundJobImpl - doing something in the background
06/13 15:05:00 DEBUG org.springframework.orm.hibernate3.HibernateInterceptor - Eagerly flushing Hibernate session
06/13 15:05:00 DEBUG org.springframework.orm.hibernate3.SessionFactoryUtils - Closing Hibernate Session

Amores que matan – 1966 Mustang

This 66 Mustang is pocking a hole on my pocket. Lots of money spent since I bought it a couple of years ago.
The beauty next to it reminds me every day that I deserve it for buying a 43 years old car.
Pero como dice mi prima Irene, Antes muerto que sencillo!!!

cimg1846

cimg1847

cimg1853

AOP – Spring – Intercepting method calls using annotations

Sometimes when using Spring in your app you want to profile your methods to see how long it takes for a method to complete. If you don’t have access to software like JProfiler you can accomplish this quickly with some AOP magic in Spring.
Notice that what’s important about this tutorial is not actually to profile time for methods calls. The real power is to use your custom annotations following the same pattern for this and other purposes such as Security, Cacheing of method return types, Transaction management, you name it…

This tutorial is available for download with svn:

svn checkout http://raulrajatutorials.googlecode.com/svn/trunk/ raulrajatutorials-read-only

Comments in the code itself should be self-explanatory if you already have some java + spring experience

And now to the point.

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 
    <!-- A Service that performs some work -->
    <bean id="businessService" class="com.raulraja.service.impl.BusinessServiceImpl"/>
 
    <!-- A service interceptor that intercepts other services with methods annotated with @Profile -->
    <bean id="methodTimeProfiler" class="com.raulraja.util.aop.profile.MethodProfiler"/>
    <aop:config>
        <aop:aspect ref="methodTimeProfiler">
            <aop:pointcut id="profiledMethods" expression="@annotation(com.raulraja.util.aop.profile.Profile)"/>
            <aop:around pointcut-ref="profiledMethods" method="profileMethod"/>
        </aop:aspect>
    </aop:config>
 
    <!--
        This handler is actually not required but used for demonstrating the tutorial by invoking
        http://localhost:port/tutorialName
    -->
    <bean id="serviceInvokerHandler" class="com.raulraja.util.handler.impl.ServiceInvokerHandlerImpl" autowire="autodetect" />
 
</beans>

BusinessServiceImpl.java

package com.raulraja.service.impl;
 
import com.raulraja.service.BusinessService;
import com.raulraja.util.aop.profile.Profile;
import org.apache.log4j.Logger;
 
/**
 * This a very important service impl with methods that is doing something slow and needs to be profiled
 */
public class BusinessServiceImpl implements BusinessService {
 
	private final static Logger logger = Logger.getLogger(BusinessServiceImpl.class);
 
	/**
	 * Do some work , by adding the @Profile annotation the interceptor provides advice
	 */
	@Profile
	public void doSomething() {
		logger.debug("nothing done for simplicity");
	}
}

Profile.java

package com.raulraja.util.aop.profile;
 
/**
 * Marker for methods that will be profiled, By placing this annotation on a method spring will proxy the service and
 * call the interceptor that provides advice to the real method call
 */
public @interface Profile {
}

MethodProfiler.java

package com.raulraja.util.aop.profile;
 
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
 
public class MethodProfiler {
 
	private final static Logger logger = Logger.getLogger(MethodProfiler.class);
 
	/**
	 * Intercepts methods that declare com.company.project.util.aop.profiler.Profile and prints out the time it takes to complete
	 * @param pjp proceeding join point
	 * @return the intercepted method returned object
	 * @throws Throwable in case something goes wrong in the actual method call
	 */
	public Object profileMethod(ProceedingJoinPoint pjp) throws Throwable {
		try {
			final boolean DEBUG = logger.isDebugEnabled();
			long start = System.currentTimeMillis();
			// Parse out the first arg
			String arg1 = "";
			Object[] pjpArgs = pjp.getArgs();
			if ((pjpArgs != null) &amp;&amp; (pjpArgs.length &gt; 0) &amp;&amp; (pjpArgs[0] != null)) {
				arg1 = pjpArgs[0].toString();
			}
			String logPrefix = null;
			if (DEBUG) {
				logPrefix = pjp.getSignature().getDeclaringTypeName() + "." + pjp.getSignature().getName() + " " + arg1;
				logger.debug(logPrefix + " START");
			}
			Object retVal = pjp.proceed();
			long end = System.currentTimeMillis();
			long differenceMs = end - start;
			if (DEBUG) {
				logger.debug(logPrefix + " RETURN in " + differenceMs + " ms");
			}
			return retVal;
		}
		catch (Throwable t) {
			logger.error("Interceptor caught error: " + t, t);
			throw t;
		}
	}
}

And here it is actually running…

picture-8