1 /**
2 * Copyright 2005-2006 the original author or authors.
3 *
4 * Licensed under the Gnu General Pubic License, Version 2.0 (the
5 * "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.opensource.org/licenses/gpl-license.php
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the Gnu General Public License for more details.
14 */
15 package org.figure8.join.core.persistence;
16
17 import org.figure8.join.core.InfrastructureException;
18 import org.figure8.join.util.LogUtil;
19
20 import org.apache.commons.logging.Log;
21 import org.springframework.orm.hibernate.HibernateCallback;
22 import net.sf.hibernate.Session;
23 import net.sf.hibernate.Hibernate;
24 import net.sf.hibernate.SessionFactory;
25 import net.sf.hibernate.HibernateException;
26 import net.sf.hibernate.collection.PersistentCollection;
27 import net.sf.hibernate.engine.SessionFactoryImplementor;
28 import net.sf.hibernate.metadata.ClassMetadata;
29 import net.sf.hibernate.persister.Joinable;
30 import net.sf.hibernate.type.Type;
31 import net.sf.hibernate.type.EntityType;
32 import net.sf.hibernate.type.AssociationType;
33 import net.sf.hibernate.type.PersistentCollectionType;
34
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.List;
38 import java.util.Arrays;
39 import java.util.HashSet;
40 import java.util.HashMap;
41 import java.util.Iterator;
42 import java.util.ArrayList;
43 import java.util.Collection;
44 /**
45 * This is a generic implementation of <code>HibernateObjectDao</code>
46 * that uses <code>java.lang.Object</code> as its persistent class.
47 * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
48 * @version $Revision: 1.2 $
49 */
50 public class GenericHibernateObjectDao extends HibernateObjectDao{
51
52
53
54 /** Get a commons logger */
55 private static final Log log = LogUtil.getLog(GenericHibernateObjectDao.class);
56
57
58
59
60 /** Creates a new instance of GenericHibernateObjectDao */
61 public GenericHibernateObjectDao(){
62 }
63
64
65
66
67 /**
68 * Find all entity objects associated with this Dao. Because this dao
69 * implementation is generic : this means all the persitent objects !
70 * @return A List of EntityObjects
71 */
72 public List findAll(){
73 try{
74
75 return (List)getHibernateTemplate().execute(new HibernateCallback(){
76 public Object doInHibernate(Session session) throws HibernateException{
77 return PersistentObjectsLoader.loadPersistentObjects(session);
78 }
79 });
80 }
81 catch(Exception e){
82 log.error("Exception in findAll()!", e);
83 throw new InfrastructureException(e);
84 }
85 }
86
87
88
89
90 /**
91 * Get the persistent class associated to this Dao.
92 * @return The class of the persistent object
93 */
94 public Class getPersistentClass(){
95 return (java.lang.Object.class);
96 }
97
98
99
100
101 /** @return The collection implementation corresponding to Hiberante collection type */
102 private static Collection getCollectionImplementation(Object collection){
103 Collection associatedRows = null;
104 if (collection instanceof Set)
105 associatedRows = new HashSet();
106 else if (collection instanceof List)
107 associatedRows = new ArrayList();
108 return associatedRows;
109 }
110
111 /** @return Find and initialize other side of bidirectionnal association */
112 private static Object findCollectionInAssociatedObject(SessionFactoryImplementor sessionFactoryImplementor,
113 String referencedColumns[], ClassMetadata referencedClassMetaData, Object referencedObject, Class clazz) throws HibernateException{
114
115 Type types[] = referencedClassMetaData.getPropertyTypes();
116 String propertyNames[] = referencedClassMetaData.getPropertyNames();
117
118
119 for (int i=0; i<types.length; i++){
120 Type type = types[i];
121 if (!type.isAssociationType())
122 continue;
123
124 AssociationType associationType = (AssociationType)type;
125 Class associatedClass = associationType.getAssociatedClass(sessionFactoryImplementor);
126 Class associationTypeClass = associationType.getReturnedClass();
127 String referencedColumnsOfAssociation[] = associationType.getReferencedColumns(sessionFactoryImplementor);
128
129 boolean sameColumns = Arrays.equals(referencedColumns, referencedColumnsOfAssociation);
130 if (!sameColumns || !associatedClass.isAssignableFrom(clazz))
131 continue;
132
133 Object associatedObject = referencedClassMetaData.getPropertyValue(referencedObject, propertyNames[i]);
134 if (associatedObject instanceof PersistentCollection)
135 if (Set.class.isAssignableFrom(associationTypeClass))
136 associatedObject = new HashSet();
137 else if (List.class.isAssignableFrom(associationTypeClass))
138 associatedObject = new ArrayList();
139
140 referencedClassMetaData.setPropertyValue(referencedObject, propertyNames[i], associatedObject);
141 return associatedObject;
142 }
143
144 return null;
145 }
146
147
148
149
150 /** Class representing a composite key */
151 private static final class Key{
152 Object key1 = null;
153 Object key2 = null;
154 /** Creates a new 2 member keys */
155 public Key(Object key1, Object key2){
156 this.key1 = key1;
157 this.key2 = key2;
158 }
159 /** @return Hashcode of this composite key */
160 public int hashCode(){
161 return (29 * key1.hashCode() + key2.hashCode());
162 }
163 /** @return Whether objects is equal to key */
164 public boolean equals(Object obj){
165 Key theOtherObj = (Key)obj;
166 return key1.equals(theOtherObj.key1) && key2.equals(theOtherObj.key2);
167 }
168 }
169
170 /** Inner class for loading all persistent objects */
171 public static class PersistentObjectsLoader{
172 /**
173 * Load the persistent objects from given <code>Session</code>
174 * @throws HibernateException if session or session factory access fails
175 */
176 public static List loadPersistentObjects(Session session) throws HibernateException{
177
178 List objects = new ArrayList();
179 Map objectsMap = new HashMap();
180 SessionFactory sessionFactory = session.getSessionFactory();
181 SessionFactoryImplementor sessionFactoryImplementor = (SessionFactoryImplementor)sessionFactory;
182
183
184 Map metadata = sessionFactory.getAllClassMetadata();
185 Set metadataEntries = metadata.entrySet();
186 for (Iterator entries = metadataEntries.iterator(); entries.hasNext();){
187 Map.Entry entry = (Map.Entry)entries.next();
188 Class clazz = (Class)entry.getKey();
189 try{
190
191 clazz.newInstance();
192 log.debug("Loading all entities from class: " + clazz.getName());
193 List list = session.find("from " + clazz.getName());
194 objects.addAll(list);
195
196 for (int i=0; i<list.size(); i++){
197 Object obj = list.get(i);
198 ClassMetadata metaData = sessionFactory.getClassMetadata(clazz);
199 Object objClazz = metaData.getMappedClass();
200 Object objId = metaData.getIdentifier(obj);
201 objectsMap.put(new Key(objClazz, objId), obj);
202 }
203 }
204 catch (InstantiationException e){
205
206 log.warn("InstanciationException while loading all persistent objects: " + e.getMessage());
207 }
208 catch (IllegalAccessException e){
209
210 log.warn("IllegalAccessException while loading all persistent objects: " + e.getMessage());
211 }
212 }
213
214
215 for (int i=0; i<objects.size(); i++){
216 Object obj = objects.get(i);
217 Class clazz = Hibernate.getClass(obj);
218 ClassMetadata metaData = sessionFactory.getClassMetadata(clazz);
219 Type types[] = metaData.getPropertyTypes();
220 String propertyNames[] = metaData.getPropertyNames();
221
222 for (int j=0; j<types.length; j++){
223 Type type = types[j];
224 String propertyName = propertyNames[j];
225
226 if (type.isPersistentCollectionType()){
227 PersistentCollectionType collectionType = (PersistentCollectionType)type;
228 Joinable joinable = collectionType.getJoinable(sessionFactoryImplementor);
229
230 if (joinable.isManyToMany())
231 continue;
232
233 Object col = metaData.getPropertyValue(obj, propertyName);
234 if (col instanceof PersistentCollection){
235 Collection collection = getCollectionImplementation(col);
236 metaData.setPropertyValue(obj, propertyName, collection);
237 }
238 continue;
239 }
240
241 if (!type.isAssociationType() || type.isPersistentCollectionType())
242 continue;
243
244
245 EntityType entityType = (EntityType)type;
246 Class associatedClass = entityType.getAssociatedClass();
247 ClassMetadata associatedClassMetaData = (ClassMetadata)metadata.get(associatedClass);
248 Object associatedObject = metaData.getPropertyValue(obj, propertyName);
249 if (associatedObject == null)
250 continue;
251
252 Class associatedObjectClazz = associatedClassMetaData.getMappedClass();
253 Object associatedObjectId = associatedClassMetaData.getIdentifier(associatedObject);
254
255 Object fullyLoadedAssociatedObject = objectsMap.get(new Key(associatedObjectClazz, associatedObjectId));
256 if (fullyLoadedAssociatedObject != null){
257 associatedObject = fullyLoadedAssociatedObject;
258 metaData.setPropertyValue(obj, propertyName, associatedObject);
259 }
260
261 String referencedColumns[] = entityType.getReferencedColumns(sessionFactoryImplementor);
262 Object associatedObjectInAssociatedObject = findCollectionInAssociatedObject(sessionFactoryImplementor, referencedColumns, associatedClassMetaData, associatedObject, clazz);
263 if (associatedObjectInAssociatedObject != null && (associatedObjectInAssociatedObject instanceof Collection))
264 ((Collection)associatedObjectInAssociatedObject).add(obj);
265 }
266 }
267 return objects;
268 }
269 }
270 }