/*******************************************************************************
* Gisgraphy Project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*
* Copyright 2008 Gisgraphy project
* David Masclet <davidmasclet@gisgraphy.com>
*
*
*******************************************************************************/
package com.gisgraphy.dao.spring;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* <p>
* Adds Hibernate persistent class definitions to an existing Spring Session
* Factory bean, possibly defined within a separate Spring configuration file in
* a seprate jar file. By using this extension factory developers can add
* persistent classes to an AppFuse application without modifying any of the
* existing AppFuse Spring configuration or jar distribution files.
* <p>
* As an example consider the following Spring bean configuration:
*
* <pre>
* <bean class="com.gisgraphy.dao.spring.HibernateExtensionPostProcessor">
* <property name="mappingResources">
* <list>
* <value>com/gisgraphy/model/Foo.hbm.xml</value>
* </list>
* </property>
* <property name="annotatedClasses">
* <list>
* <value>com.gisgraphy.model.Bar</value>
* </list>
* </property>
* </bean>
* </pre>
*
* <p>
* The snippet will add two persistent classes to an existing Session Factory
* bean called "sessionFactory". Note that the extension can handle
* both annotated classes and the more traditional .hbm.xml files. Assuming that
* these persistent classes are packaged in a jar called extension.jar which
* contains the Spring configuration file applicationContext-dao.xml at the root
* level, then the standard AppFuse configuration will automatically pick up the
* new Spring configuration file and the new persistent classes will be added to
* the list already defined for the session factory bean configured within the
* standard appfuse-hibernate.jar file. And all this without needing to touch
* the original AppFuse configuration files!
*
* @author Michael Horwitz
*/
public class HibernateExtensionPostProcessor implements
BeanFactoryPostProcessor {
private String sessionFactoryBeanName = "sessionFactory";
@SuppressWarnings("unchecked")
private List mappingResources;
@SuppressWarnings("unchecked")
private List annotatedClasses;
@SuppressWarnings("unchecked")
private List configLocations;
private Properties hibernateProperties;
/**
* Adds the annotated classes and the mapping resources to the existing
* Session Factory configuration.
*
* @param configurableListableBeanFactory
* the good ol' bean factory
*/
@SuppressWarnings("unchecked")
public void postProcessBeanFactory(
ConfigurableListableBeanFactory configurableListableBeanFactory) {
if (configurableListableBeanFactory
.containsBean(sessionFactoryBeanName)) {
BeanDefinition sessionFactoryBeanDefinition = configurableListableBeanFactory
.getBeanDefinition(sessionFactoryBeanName);
MutablePropertyValues propertyValues = sessionFactoryBeanDefinition
.getPropertyValues();
if (mappingResources != null) {
// do we have existing resourses?
PropertyValue propertyValue = propertyValues
.getPropertyValue("mappingResources");
if (propertyValue == null) {
propertyValue = new PropertyValue("mappingResources",
new ArrayList());
propertyValues.addPropertyValue(propertyValue);
}
// value is expected to be a list.
List existingMappingResources = (List) propertyValue.getValue();
existingMappingResources.addAll(mappingResources);
}
if (annotatedClasses != null) {
// do we have existing resources?
PropertyValue propertyValue = propertyValues
.getPropertyValue("annotatedClasses");
if (propertyValue == null) {
propertyValue = new PropertyValue("annotatedClasses",
new ArrayList());
propertyValues.addPropertyValue(propertyValue);
}
// value is expected to be a list.
List existingMappingResources = (List) propertyValue.getValue();
existingMappingResources.addAll(annotatedClasses);
}
if (configLocations != null) {
PropertyValue propertyValue = propertyValues
.getPropertyValue("configLocations");
if (propertyValue == null) {
propertyValue = new PropertyValue("configLocations",
new ArrayList());
propertyValues.addPropertyValue(propertyValue);
}
List existingConfigLocations = (List) propertyValue.getValue();
existingConfigLocations.addAll(configLocations);
}
if (hibernateProperties != null) {
PropertyValue propertyValue = propertyValues
.getPropertyValue("hibernateProperties");
if (propertyValue == null) {
propertyValue = new PropertyValue("hibernateProperties",
new Properties());
propertyValues.addPropertyValue(propertyValue);
}
Properties existingHibernateProperties = (Properties) propertyValue
.getValue();
existingHibernateProperties.putAll(hibernateProperties);
}
} else {
throw new NoSuchBeanDefinitionException(
"No bean named ["
+ sessionFactoryBeanName
+ "] exists within the bean factory. "
+ "Cannot post process session factory to add Hibernate resource definitions.");
}
}
/**
* Set the name of the SessionFactory bean. By default this post processor
* looks for a bean of name "sessionFactory"
*
* @param sessionFactoryBeanName
* The name of the session factory bean.
*/
public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
this.sessionFactoryBeanName = sessionFactoryBeanName;
}
/**
* Set the list of mapping resources (.hbm.xml files) to be added to the
* session factory.
*
* @param mappingResources
* The list of mapping resources.
*/
@SuppressWarnings("unchecked")
public void setMappingResources(List mappingResources) {
this.mappingResources = mappingResources;
}
/**
* The list of annotated classes to add to the session factory.
*
* @param annotatedClasses
* The list of annotated classes that need to be added.
*/
@SuppressWarnings("unchecked")
public void setAnnotatedClasses(List annotatedClasses) {
this.annotatedClasses = annotatedClasses;
}
/**
* The list of configuration locations (i.e. classpath:hibernate.cfg.xml) to
* add to the session factory
*
* @param configLocations
* The list of configuration locations that need to be added.
*/
@SuppressWarnings("unchecked")
public void setConfigLocations(List configLocations) {
this.configLocations = configLocations;
}
/**
* Hibernate properties to add to the session factory.
*
* @param hibernateProperties
* The list of additional properties.
*/
public void setHibernateProperties(Properties hibernateProperties) {
this.hibernateProperties = hibernateProperties;
}
}