BeanPostProcessor
Defino una clase que implementa la interface BeanPostProcessor, que provee dos métodos:
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
La clase es DataDistributionServiceBeanPostProcessor:
package ar.com.kamikazesoftware.console.context;
import java.io.File;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.web.context.ServletContextAware;
import ar.com.kamikazesoftware.services.dataDistribution.DataDistributionService;
/**
* {@link BeanPostProcessor} to set the {@link DataDistributionService}'s xmlFilesRootFolder property
* as an absolute path including the servlet container's contexts directory followed by
* the relative path set by the user in the application's resource bundle parameter called "xmlFilesRootFolder".
*
* The bean dataDistributionService has injected the xmlFilesRootFolder parameter taking it from the Spring's
* {@link PropertyPlaceholderConfigurer} configured with the application.properties file as the resource bundle:
*
* <bean id="dataDistributionService"
* class="ar.com.kamikazesoftware.services.dataDistribution.local.LocalDataDistributionService">
* <property name="xmlFilesRootFolder"><value>${xmlFilesRootFolder}</value></property>
* ...
*
*
* So before using the original xmlFilesRootFolder, that can't be useful in such environments like Linux
* because the relative path doesn't get set relative to servlet container's contexts directory,
* this BeanPostProcessor sets the xmlFilesRootFolder concatenating before it the absolute servlet container's contexts directory.
*
* For example, if in application.properties exists this line:
*
* xmlFilesRootFolder=webapps/ROOT/players/
*
* And Tomcat is installed on c:/tools/tomcat
*
* then this BeanPostProcessor sets the DataDistributionService xmlFilesRootFolder property with the value:
*
* c:/tools/tomcat/webapps/ROOT/players
*
* @author EMenendez
*
*/
public class DataDistributionServiceBeanPostProcessor implements BeanPostProcessor, ServletContextAware {
private static final Log log = LogFactory.getLog(DataDistributionServiceBeanPostProcessor.class);
private String containerRootDirectoryPath;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// do nothing before initialization
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// apply only for DataDistributionService
if (bean instanceof DataDistributionService) {
if (log.isDebugEnabled())
log.debug("Executing postProcessAfterInitialization for bean " + beanName);
DataDistributionService dataDistributionService = (DataDistributionService) bean;
// TODO try use reflection to call getter and setter for XmlFilesRootFolder property, and remove getter and setter from the interface DataDistributionService
String relativeControlFileDirectory = dataDistributionService.getXmlFilesRootFolder();
if (log.isDebugEnabled())
log.debug("DataDistributionService's xmlFilesRootFolder from resource bundle (relative path): " + relativeControlFileDirectory);
String absoluteControlFileDirectory = containerRootDirectoryPath + relativeControlFileDirectory;
dataDistributionService.setXmlFilesRootFolder(absoluteControlFileDirectory);
if (log.isDebugEnabled())
log.debug("DataDistributionService's xmlFilesRootFolder set to absolute path: " + absoluteControlFileDirectory);
return dataDistributionService;
} else {
// Do nothing if the processed bean is not DataDistributionService
return bean;
}
}
@Override
public void setServletContext(ServletContext servletContext) {
// get tomcat/webapps/starmount-console/ dir
String contextRootDirectoryPath = servletContext.getRealPath("/");
File contextRootDirectory = new File(contextRootDirectoryPath);
// get tomcat/webapps/ dir
containerRootDirectoryPath = contextRootDirectory.getParent() + System.getProperty("file.separator");
if (log.isDebugEnabled())
log.debug("Initializing DataDistributionServiceBeanPostProcessor. Set containerRootDirectoryPath to: " + containerRootDirectoryPath);
}
}
Application Context
Y en applicationContext.xml de Spring están definidos el bean y su post processor:
<bean id="dataDistributionService"
class="ar.com.kamikazesoftware.services.dataDistribution.local.LocalDataDistributionService">
<property name="xmlFilesRootFolder"><value>${xmlFilesRootFolder}</value></property>
<constructor-arg index="0" ref="SceneDAO" />
</bean>
<bean class="ar.com.kamikazesoftware.console.context.DataDistributionServiceBeanPostProcessor"/>
ServletContextAware
Como DataDistributionServiceBeanPostProcessor implementa también la interface ServletContextAware, cuando Spring inicializa el post processor ejecuta el método:
public void setServletContext(ServletContext servletContext)
que es el que usamos para obtener el path local donde están guardadas las webapps en el servlet container (Tomcat):
// get tomcat/webapps/myapp/ dir
String contextRootDirectoryPath = servletContext.getRealPath("/");
File contextRootDirectory = new File(contextRootDirectoryPath);
// get tomcat/webapps/ dir
containerRootDirectoryPath = contextRootDirectory.getParent();
De esta forma amigos termina este ejemplo de implementación y uso de BeanPostProcessor, ServletContextAware y ServletContext.
Hasta la próxima!