KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > roller > business > hibernate > HibernatePersistenceStrategy


1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. The ASF licenses this file to You
4 * under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License. For additional information regarding
15 * copyright in this work, please see the NOTICE file in the top level
16 * directory of this distribution.
17 */

18 /*
19  * Created on Mar 7, 2003
20  */

21 package org.apache.roller.business.hibernate;
22
23 import java.util.Iterator JavaDoc;
24 import java.util.LinkedList JavaDoc;
25 import java.util.List JavaDoc;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.hibernate.HibernateException;
29 import org.hibernate.Session;
30 import org.hibernate.SessionFactory;
31 import org.hibernate.Transaction;
32 import org.hibernate.cfg.Configuration;
33 import org.apache.roller.RollerException;
34 import org.apache.roller.pojos.Assoc;
35 import org.apache.roller.pojos.HierarchicalPersistentObject;
36 import org.apache.roller.pojos.PersistentObject;
37
38
39 /**
40  * Base class for Hibernate persistence implementation.
41  *
42  * This class serves as a helper/util class for all of the Hibernate
43  * manager implementations by providing a set of basic persistence methods
44  * that can be easily reused.
45  *
46  */

47 public class HibernatePersistenceStrategy {
48     
49     static final long serialVersionUID = 2561090040518169098L;
50     
51     private static SessionFactory sessionFactory = null;
52     
53     private static Log log = LogFactory.getLog(HibernatePersistenceStrategy.class);
54     
55     
56     /**
57      * Construct using Hibernate Session Factory.
58      */

59     public HibernatePersistenceStrategy() throws Exception JavaDoc {
60         
61         log.debug("Initializing Hibernate SessionFactory");
62         
63         Configuration config = new Configuration();
64         config.configure("/hibernate.cfg.xml");
65         this.sessionFactory = config.buildSessionFactory();
66         
67     }
68
69     
70     /**
71      * Get persistence session on current thread.
72      *
73      * This will open a new Session if one is not already open, otherwise
74      * it will return the already open Session.
75      */

76     protected Session getSession() {
77         
78         log.debug("Opening Hibernate Session");
79         
80         // get Hibernate Session and make sure we are in a transaction
81
// this will join existing Session/Transaction if they exist
82
Session session = sessionFactory.getCurrentSession();
83         session.beginTransaction();
84         
85         return session;
86     }
87     
88     
89     protected void flush() throws RollerException {
90         
91         Session session = getSession();
92         try {
93             session.getTransaction().commit();
94         } catch(Throwable JavaDoc t) {
95             // uh oh ... failed persisting, gotta release
96
release();
97         }
98     }
99     
100     
101     /**
102      * Release database session, rollback any uncommitted changes.
103      *
104      * IMPORTANT: we don't want to open a transaction and force the use of a
105      * jdbc connection just to close the session and do a rollback, so this
106      * method must be sensitive about how the release is triggered.
107      *
108      * In particular we don't want to use our custom getSession() method which
109      * automatically begins a transaction. Instead we get a Session and check
110      * if there is already an active transaction that needs to be rolled back.
111      * If not then we can close the Session without ever getting a jdbc
112      * connection, which is important for scalability.
113      */

114     protected void release() {
115         
116         try {
117             Session session = sessionFactory.getCurrentSession();
118             
119             if(session != null && session.isOpen()) {
120                 
121                 log.debug("Closing Hibernate Session");
122                 
123                 try {
124                     Transaction tx = session.getTransaction();
125                     
126                     if(tx != null && tx.isActive()) {
127                         log.debug("Forcing rollback on active transaction");
128                         tx.rollback();
129                     }
130                 } catch(Throwable JavaDoc t) {
131                     log.error("ERROR doing Hibernate rollback", t);
132                 } finally {
133                     if(session.isOpen()) {
134                         session.close();
135                     }
136                 }
137             }
138         } catch(Throwable JavaDoc t) {
139             log.error("ERROR closing Hibernate Session", t);
140         }
141     }
142
143     
144     /**
145      * Retrieve object. We return null if the object is not found.
146      */

147     protected PersistentObject load(String JavaDoc id, Class JavaDoc clazz) throws RollerException {
148         
149         if(id == null || clazz == null) {
150             throw new RollerException("Cannot load objects when value is null");
151         }
152         
153         return (PersistentObject) getSession().get(clazz, id);
154     }
155     
156     
157     /**
158      * Store object.
159      */

160     protected void store(PersistentObject obj) throws HibernateException {
161         
162         if(obj == null) {
163             throw new HibernateException("Cannot save null object");
164         }
165         
166         Session session = getSession();
167         
168         // TODO BACKEND: this is wacky, we should double check logic here
169

170         // TODO BACKEND: better to use session.saveOrUpdate() here, if possible
171
if ( obj.getId() == null || obj.getId().trim().equals("") ) {
172             // Object has never been written to database, so save it.
173
// This makes obj into a persistent instance.
174
session.save(obj);
175         }
176         
177         /*
178          * technically we shouldn't have any reason to support the saving
179          * of detached objects, so at some point we should re-evaluate this.
180          *
181          * objects should be re-attached before being saved again. it would
182          * be more appropriate to reject these kinds of saves because they are
183          * not really safe.
184          *
185          * NOTE: this may be coming from the way we use formbeans on the UI.
186          * we very commonly repopulate all data in a pojo (including id) from
187          * form data rather than properly loading the object from a Session
188          * then modifying its properties.
189          */

190         if ( !session.contains(obj) ) {
191             
192             log.debug("storing detached object: "+obj.toString());
193             
194             // Object has been written to database, but instance passed in
195
// is not a persistent instance, so must be loaded into session.
196
PersistentObject vo =
197                     (PersistentObject)session.load(obj.getClass(),obj.getId());
198             vo.setData(obj);
199             obj = vo;
200         }
201         
202     }
203     
204     
205     /**
206      * Remove object.
207      *
208      * TODO BACKEND: force the use of remove(Object) moving forward.
209      */

210     protected void remove(String JavaDoc id, Class JavaDoc clazz) throws HibernateException {
211         
212         if(id == null || clazz == null) {
213             throw new HibernateException("Cannot remove object when values are null");
214         }
215         
216         Session session = getSession();
217         
218         PersistentObject obj = (PersistentObject) session.load(clazz,id);
219         session.delete(obj);
220     }
221     
222     
223     /**
224      * Remove object.
225      */

226     protected void remove(PersistentObject obj) throws HibernateException {
227         
228         if(obj == null) {
229             throw new HibernateException("Cannot remove null object");
230         }
231         
232         // TODO BACKEND: can hibernate take care of this check for us?
233
// what happens if object does not use id?
234
// can't remove transient objects
235
if (obj.getId() != null) {
236             
237             getSession().delete(obj);
238         }
239     }
240     
241     
242     /**
243      * Store hierarchical object.
244      *
245      * NOTE: if the object has proper cascade setting then is all this necessary?
246      */

247     protected void store(HierarchicalPersistentObject obj)
248             throws HibernateException, RollerException {
249         
250         if(obj == null) {
251             throw new HibernateException("Cannot save null object");
252         }
253         
254         log.debug("Storing hierarchical object "+obj);
255         
256         Session session = getSession();
257         
258         HierarchicalPersistentObject mNewParent = obj.getNewParent();
259         boolean fresh = (obj.getId() == null || "".equals(obj.getId()));
260         
261         if (fresh) {
262             // Object has never been written to database, so save it.
263
// This makes obj into a persistent instance.
264
session.save(obj);
265         }
266  
267         if(!session.contains(obj)) {
268             
269             // Object has been written to database, but instance passed in
270
// is not a persistent instance, so must be loaded into session.
271
HierarchicalPersistentObject vo =
272                     (HierarchicalPersistentObject)session.load(obj.getClass(),obj.getId());
273             vo.setData(obj);
274             obj = vo;
275         }
276         
277         if (fresh) {
278             // Every fresh cat needs a parent assoc
279
Assoc parentAssoc = obj.createAssoc(
280                     obj, mNewParent, Assoc.PARENT);
281             this.store(parentAssoc);
282         } else if (null != mNewParent) {
283             // New parent must be added to parentAssoc
284
Assoc parentAssoc = obj.getParentAssoc();
285             if(parentAssoc == null)
286                 log.error("parent assoc is null");
287             parentAssoc.setAncestor(mNewParent);
288             this.store(parentAssoc);
289         }
290         
291         // Clear out existing grandparent associations
292
Iterator JavaDoc ancestors = obj.getAncestorAssocs().iterator();
293         while (ancestors.hasNext()) {
294             Assoc assoc = (Assoc)ancestors.next();
295             if (assoc.getRelation().equals(Assoc.GRANDPARENT)) {
296                 this.remove(assoc);
297             }
298         }
299         
300         // Walk parent assocations, creating new grandparent associations
301
int count = 0;
302         Assoc currentAssoc = obj.getParentAssoc();
303         while (null != currentAssoc.getAncestor()) {
304             if (count > 0) {
305                 Assoc assoc = obj.createAssoc(obj,
306                         currentAssoc.getAncestor(),
307                         Assoc.GRANDPARENT);
308                 this.store(assoc);
309             }
310             currentAssoc = currentAssoc.getAncestor().getParentAssoc();
311             count++;
312         }
313         
314         Iterator JavaDoc children = obj.getChildAssocs().iterator();
315         while (children.hasNext()) {
316             Assoc assoc = (Assoc) children.next();
317             
318             // resetting parent will cause reset of ancestors links
319
assoc.getObject().setParent(obj);
320             
321             // recursively...
322
this.store(assoc.getObject());
323         }
324         
325         // Clear new parent now that new parent has been saved
326
mNewParent = null;
327     }
328     
329     
330     /**
331      * Store assoc.
332      */

333     protected void store(Assoc assoc) throws HibernateException {
334         
335         if(assoc == null) {
336             throw new HibernateException("Cannot save null object");
337         }
338         
339         getSession().saveOrUpdate(assoc);
340     }
341     
342     
343     /**
344      * Remove hierarchical object.
345      *
346      * NOTE: if the object has proper cascade setting then is all this necessary?
347      */

348     protected void remove(HierarchicalPersistentObject obj) throws RollerException {
349         
350         if(obj == null) {
351             throw new RollerException("Cannot remove null object");
352         }
353         
354         log.debug("Removing hierarchical object "+obj.getId());
355         
356         // loop to remove all descendents and associations
357
List JavaDoc toRemove = new LinkedList JavaDoc();
358         List JavaDoc assocs = obj.getAllDescendentAssocs();
359         for (int i=assocs.size()-1; i>=0; i--) {
360             Assoc assoc = (Assoc)assocs.get(i);
361             HierarchicalPersistentObject hpo = assoc.getObject();
362             
363             // remove my descendent's parent and grandparent associations
364
Iterator JavaDoc ancestors = hpo.getAncestorAssocs().iterator();
365             while (ancestors.hasNext()) {
366                 Assoc dassoc = (Assoc)ancestors.next();
367                 this.remove(dassoc);
368             }
369             
370             // remove decendent association and descendents
371
//assoc.remove();
372
toRemove.add(hpo);
373         }
374         Iterator JavaDoc removeIterator = toRemove.iterator();
375         while (removeIterator.hasNext()) {
376             PersistentObject po = (PersistentObject) removeIterator.next();
377             getSession().delete(po);
378         }
379         
380         // loop to remove my own parent and grandparent associations
381
Iterator JavaDoc ancestors = obj.getAncestorAssocs().iterator();
382         while (ancestors.hasNext()) {
383             Assoc assoc = (Assoc)ancestors.next();
384             this.remove(assoc);
385         }
386         
387         getSession().delete(obj);
388     }
389     
390     
391     /**
392      * Remove assoc.
393      */

394     protected void remove(Assoc assoc) throws HibernateException {
395         
396         if(assoc == null) {
397             throw new HibernateException("Cannot save null object");
398         }
399         
400         getSession().delete(assoc);
401     }
402     
403 }
404
Popular Tags