View Javadoc
1   /*******************************************************************************
2    *   Gisgraphy Project 
3    * 
4    *   This library is free software; you can redistribute it and/or
5    *   modify it under the terms of the GNU Lesser General Public
6    *   License as published by the Free Software Foundation; either
7    *   version 2.1 of the License, or (at your option) any later version.
8    * 
9    *   This library is distributed in the hope that it will be useful,
10   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   *   Lesser General Public License for more details.
13   * 
14   *   You should have received a copy of the GNU Lesser General Public
15   *   License along with this library; if not, write to the Free Software
16   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
17   * 
18   *  Copyright 2008  Gisgraphy project 
19   *  David Masclet <davidmasclet@gisgraphy.com>
20   *  
21   *  
22   *******************************************************************************/
23  package com.gisgraphy.dao.spring;
24  
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.Properties;
28  
29  import org.springframework.beans.MutablePropertyValues;
30  import org.springframework.beans.PropertyValue;
31  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
32  import org.springframework.beans.factory.config.BeanDefinition;
33  import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
34  import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
35  
36  /**
37   * <p>
38   * Adds Hibernate persistent class definitions to an existing Spring Session
39   * Factory bean, possibly defined within a separate Spring configuration file in
40   * a seprate jar file. By using this extension factory developers can add
41   * persistent classes to an AppFuse application without modifying any of the
42   * existing AppFuse Spring configuration or jar distribution files.
43   * <p>
44   * As an example consider the following Spring bean configuration:
45   * 
46   * <pre>
47   * &lt;bean class=&quot;com.gisgraphy.dao.spring.HibernateExtensionPostProcessor&quot;&gt;
48   *     &lt;property name=&quot;mappingResources&quot;&gt;
49   *         &lt;list&gt;
50   *             &lt;value&gt;com/gisgraphy/model/Foo.hbm.xml&lt;/value&gt;
51   *         &lt;/list&gt;
52   *     &lt;/property&gt;
53   *     &lt;property name=&quot;annotatedClasses&quot;&gt;
54   *         &lt;list&gt;
55   *             &lt;value&gt;com.gisgraphy.model.Bar&lt;/value&gt;
56   *         &lt;/list&gt;
57   *     &lt;/property&gt;
58   * &lt;/bean&gt;
59   * </pre>
60   * 
61   * <p>
62   * The snippet will add two persistent classes to an existing Session Factory
63   * bean called &quot;sessionFactory&quot;. Note that the extension can handle
64   * both annotated classes and the more traditional .hbm.xml files. Assuming that
65   * these persistent classes are packaged in a jar called extension.jar which
66   * contains the Spring configuration file applicationContext-dao.xml at the root
67   * level, then the standard AppFuse configuration will automatically pick up the
68   * new Spring configuration file and the new persistent classes will be added to
69   * the list already defined for the session factory bean configured within the
70   * standard appfuse-hibernate.jar file. And all this without needing to touch
71   * the original AppFuse configuration files!
72   * 
73   * @author Michael Horwitz
74   */
75  public class HibernateExtensionPostProcessor implements
76  	BeanFactoryPostProcessor {
77      private String sessionFactoryBeanName = "sessionFactory";
78  
79      @SuppressWarnings("unchecked")
80      private List mappingResources;
81  
82      @SuppressWarnings("unchecked")
83      private List annotatedClasses;
84  
85      @SuppressWarnings("unchecked")
86      private List configLocations;
87  
88      private Properties hibernateProperties;
89  
90      /**
91       * Adds the annotated classes and the mapping resources to the existing
92       * Session Factory configuration.
93       * 
94       * @param configurableListableBeanFactory
95       *                the good ol' bean factory
96       */
97      @SuppressWarnings("unchecked")
98      public void postProcessBeanFactory(
99  	    ConfigurableListableBeanFactory configurableListableBeanFactory) {
100 	if (configurableListableBeanFactory
101 		.containsBean(sessionFactoryBeanName)) {
102 	    BeanDefinition sessionFactoryBeanDefinition = configurableListableBeanFactory
103 		    .getBeanDefinition(sessionFactoryBeanName);
104 	    MutablePropertyValues propertyValues = sessionFactoryBeanDefinition
105 		    .getPropertyValues();
106 
107 	    if (mappingResources != null) {
108 		// do we have existing resourses?
109 		PropertyValue propertyValue = propertyValues
110 			.getPropertyValue("mappingResources");
111 
112 		if (propertyValue == null) {
113 		    propertyValue = new PropertyValue("mappingResources",
114 			    new ArrayList());
115 		    propertyValues.addPropertyValue(propertyValue);
116 		}
117 
118 		// value is expected to be a list.
119 		List existingMappingResources = (List) propertyValue.getValue();
120 		existingMappingResources.addAll(mappingResources);
121 	    }
122 
123 	    if (annotatedClasses != null) {
124 		// do we have existing resources?
125 		PropertyValue propertyValue = propertyValues
126 			.getPropertyValue("annotatedClasses");
127 
128 		if (propertyValue == null) {
129 		    propertyValue = new PropertyValue("annotatedClasses",
130 			    new ArrayList());
131 		    propertyValues.addPropertyValue(propertyValue);
132 		}
133 
134 		// value is expected to be a list.
135 		List existingMappingResources = (List) propertyValue.getValue();
136 		existingMappingResources.addAll(annotatedClasses);
137 	    }
138 
139 	    if (configLocations != null) {
140 		PropertyValue propertyValue = propertyValues
141 			.getPropertyValue("configLocations");
142 		if (propertyValue == null) {
143 		    propertyValue = new PropertyValue("configLocations",
144 			    new ArrayList());
145 		    propertyValues.addPropertyValue(propertyValue);
146 		}
147 		List existingConfigLocations = (List) propertyValue.getValue();
148 		existingConfigLocations.addAll(configLocations);
149 	    }
150 
151 	    if (hibernateProperties != null) {
152 		PropertyValue propertyValue = propertyValues
153 			.getPropertyValue("hibernateProperties");
154 		if (propertyValue == null) {
155 		    propertyValue = new PropertyValue("hibernateProperties",
156 			    new Properties());
157 		    propertyValues.addPropertyValue(propertyValue);
158 		}
159 		Properties existingHibernateProperties = (Properties) propertyValue
160 			.getValue();
161 		existingHibernateProperties.putAll(hibernateProperties);
162 	    }
163 	} else {
164 	    throw new NoSuchBeanDefinitionException(
165 		    "No bean named ["
166 			    + sessionFactoryBeanName
167 			    + "] exists within the bean factory. "
168 			    + "Cannot post process session factory to add Hibernate resource definitions.");
169 	}
170     }
171 
172     /**
173      * Set the name of the SessionFactory bean. By default this post processor
174      * looks for a bean of name &quot;sessionFactory&quot;
175      * 
176      * @param sessionFactoryBeanName
177      *                The name of the session factory bean.
178      */
179     public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
180 	this.sessionFactoryBeanName = sessionFactoryBeanName;
181     }
182 
183     /**
184      * Set the list of mapping resources (.hbm.xml files) to be added to the
185      * session factory.
186      * 
187      * @param mappingResources
188      *                The list of mapping resources.
189      */
190     @SuppressWarnings("unchecked")
191     public void setMappingResources(List mappingResources) {
192 	this.mappingResources = mappingResources;
193     }
194 
195     /**
196      * The list of annotated classes to add to the session factory.
197      * 
198      * @param annotatedClasses
199      *                The list of annotated classes that need to be added.
200      */
201     @SuppressWarnings("unchecked")
202     public void setAnnotatedClasses(List annotatedClasses) {
203 	this.annotatedClasses = annotatedClasses;
204     }
205 
206     /**
207      * The list of configuration locations (i.e. classpath:hibernate.cfg.xml) to
208      * add to the session factory
209      * 
210      * @param configLocations
211      *                The list of configuration locations that need to be added.
212      */
213     @SuppressWarnings("unchecked")
214     public void setConfigLocations(List configLocations) {
215 	this.configLocations = configLocations;
216     }
217 
218     /**
219      * Hibernate properties to add to the session factory.
220      * 
221      * @param hibernateProperties
222      *                The list of additional properties.
223      */
224     public void setHibernateProperties(Properties hibernateProperties) {
225 	this.hibernateProperties = hibernateProperties;
226     }
227 }