faebe061e4eabdc54bbcc9934b5e3950fb52a728
[mir.git] / source / org / codecoop / mir / core / dao / hibernate / AbstractDAO.java
1 /*
2  * Copyright (C) 2001, 2002, 2003, 2004 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30 package org.codecoop.mir.core.dao.hibernate;
31
32 import java.io.Serializable;
33 import java.math.BigDecimal;
34 import java.sql.Timestamp;
35 import java.util.Calendar;
36 import java.util.Date;
37 import java.util.Iterator;
38 import java.util.List;
39
40 import net.sf.hibernate.Criteria;
41 import net.sf.hibernate.HibernateException;
42 import net.sf.hibernate.Query;
43 import net.sf.hibernate.Session;
44 import net.sf.hibernate.SessionFactory;
45 import net.sf.hibernate.Transaction;
46 import net.sf.hibernate.expression.Criterion;
47 import net.sf.hibernate.expression.Example;
48 import net.sf.hibernate.expression.Expression;
49 import net.sf.hibernate.expression.Order;
50
51 import org.codecoop.mir.core.dao.DatabaseFailure;
52 import org.codecoop.mir.core.dao.IDAO;
53 import org.codecoop.mir.core.dao.IQueryCriteria;
54
55 /**
56  * AbstractDAO
57  * @author idefix
58  * @version $Id: AbstractDAO.java,v 1.1 2004/11/06 16:20:48 idfx Exp $
59  */
60 public abstract class AbstractDAO implements IDAO {
61   
62   private static SessionFactory sessionFactory;
63
64   /**
65    * Return the specific Object class that will be used for class-specific
66    * implementation of this DAO.
67    * @return the reference Class
68    * 
69    */
70   protected abstract Class getReferenceClass();
71
72   /**
73    * Execute a query. 
74    * @param query a query expressed in Hibernate's query language
75    * @return a distinct list of instances (or arrays of instances)
76    */
77   public List find(String query) throws DatabaseFailure {
78     System.out.println(query);
79     try {
80       List list = find(query, HibernateSessionManager.getSession());
81       for (Iterator iter = list.iterator(); iter.hasNext();) {
82         initializeCollections(iter.next());
83       }
84       return list;
85     } catch (HibernateException e) {
86       throw new DatabaseFailure(e);
87     }
88   }
89   
90   protected List find(Criteria c) throws DatabaseFailure {
91     try {
92       List returnList;
93       returnList = c.list();    
94       for (Iterator iter = returnList.iterator(); iter.hasNext();) {
95         initializeCollections(iter.next());
96       }
97       return returnList;
98     } catch (Throwable e) {
99       throw new DatabaseFailure(e);
100     }
101   }
102   
103   public List find(int limit, int offset) throws DatabaseFailure {
104     return find(limit, offset, null, null);
105   }
106   
107   public List find(int limit, int offset, Object example) throws DatabaseFailure {
108     Example ex = Example.create(example);
109     ex.excludeZeroes();
110     ex.excludeNone();
111     ex.ignoreCase();
112     return find(limit, offset, ex, null);    
113   }
114   
115   protected List find(int limit, int offset, Criterion crit, Order order) 
116         throws DatabaseFailure {
117     try {
118       Session s = HibernateSessionManager.getSession();
119       Criteria c = s.createCriteria(getReferenceClass());
120       if(crit != null){
121         c.add(crit);  
122       }
123       if(order != null){
124         c.addOrder(order);  
125       }
126       c.setFirstResult(offset);
127       c.setMaxResults(limit);
128       return find(c);
129     } catch (Throwable e) {
130       throw new DatabaseFailure(e);
131     }
132   }
133   
134   /**
135    * @see org.codecoop.mir.core.dao.IArticleDAO#findById(java.lang.Integer)
136    */
137   protected Object findById(Integer id) throws DatabaseFailure{
138     try {
139       Session s = HibernateSessionManager.getSession();
140       Criteria c = s.createCriteria(getReferenceClass());
141       c.add(Expression.eq("id", id));
142       return find(c).get(0);
143     } catch (Throwable e) {
144       throw new DatabaseFailure(e);
145     }
146   }
147
148   /**
149    * Perform a find but use the session given instead of creating a new one.
150    * @param query a query expressed in Hibernate's query language
151    * @s the Session to use
152    */
153   protected List find(String query, Session s) throws HibernateException {
154     return s.find(query);
155   }
156
157   /**
158    * Return all objects related to the implementation of this DAO with no filter.
159    */
160   public List findAll() throws DatabaseFailure {
161     try {
162       return findAll(HibernateSessionManager.getSession());
163     } catch (Throwable e) {
164       throw new DatabaseFailure(e);
165     }
166   }
167
168   /**
169    * Return all objects related to the implementation of this DAO with no filter.
170    * Use the session given.
171    * @param s the Session
172    */
173   protected List findAll(Session s) throws DatabaseFailure {
174     try {
175       Criteria crit = s.createCriteria(getReferenceClass());
176       return find(crit);
177     } catch (Throwable e) {
178       throw new DatabaseFailure(e);
179     }
180   }
181   
182   
183
184   public List find(IQueryCriteria criteria) throws DatabaseFailure {
185     if(criteria instanceof QueryCriteria){
186       QueryCriteria c = (QueryCriteria)criteria;
187       return find(c.criteria());
188     }
189     throw new DatabaseFailure("No applicable implementation of IQueryCriteria");
190   }
191   
192   /**
193    * Obtain an instance of Query for a named query string defined in the mapping file.
194    * @param name the name of a query defined externally 
195    * @return Query
196    */
197   protected List getNamedQuery(String name) throws DatabaseFailure {
198     try {
199       return getNamedQuery(name, HibernateSessionManager.getSession());
200     } catch (Exception e) {
201       throw new DatabaseFailure(e);
202     }
203   }
204
205   /**
206    * Obtain an instance of Query for a named query string defined in the mapping file.
207    * Use the session given.
208    * @param name the name of a query defined externally 
209    * @param s the Session
210    * @return Query
211    */
212   protected List getNamedQuery(String name, Session s) throws HibernateException {
213     Query q = s.getNamedQuery(name);
214     return q.list();
215   }
216
217   /**
218    * Obtain an instance of Query for a named query string defined in the mapping file.
219    * Use the parameters given.
220    * @param name the name of a query defined externally 
221    * @param params the parameter array
222    * @return Query
223    */
224   protected List getNamedQuery(String name, Serializable[] params)
225     throws DatabaseFailure {
226     try {
227       return getNamedQuery(name, params, HibernateSessionManager.getSession());
228     } catch (Exception e) {
229       throw new DatabaseFailure(e);
230     }
231   }
232
233   /**
234    * Obtain an instance of Query for a named query string defined in the mapping file.
235    * Use the parameters given and the Session given.
236    * @param name the name of a query defined externally 
237    * @param params the parameter array
238    * @s the Session
239    * @return Query
240    */
241   protected List getNamedQuery(String name, Serializable[] params, Session s)
242     throws HibernateException {
243     Query q = s.getNamedQuery(name);
244     for (int i = 0; i < params.length; i++) {
245       setParameterValue(q, i, params[i]);
246     }
247     return q.list();
248   }
249
250   /**
251    * Convenience method to set paramers in the query given based on the actual object type in passed in as the value.
252    * You may need to add more functionaly to this as desired (or not use this at all).
253    * @param query the Query to set
254    * @param position the ordinal position of the current parameter within the query
255    * @param value the object to set as the parameter
256    */
257   protected void setParameterValue(Query query, int position, Object value) {
258     if (null == value) {
259       return;
260     } else if (value instanceof Boolean) {
261       query.setBoolean(position, ((Boolean) value).booleanValue());
262     } else if (value instanceof String) {
263       query.setString(position, (String) value);
264     } else if (value instanceof Integer) {
265       query.setInteger(position, ((Integer) value).intValue());
266     } else if (value instanceof Long) {
267       query.setLong(position, ((Long) value).longValue());
268     } else if (value instanceof Float) {
269       query.setFloat(position, ((Float) value).floatValue());
270     } else if (value instanceof Double) {
271       query.setDouble(position, ((Double) value).doubleValue());
272     } else if (value instanceof BigDecimal) {
273       query.setBigDecimal(position, (BigDecimal) value);
274     } else if (value instanceof Byte) {
275       query.setByte(position, ((Byte) value).byteValue());
276     } else if (value instanceof Calendar) {
277       query.setCalendar(position, (Calendar) value);
278     } else if (value instanceof Character) {
279       query.setCharacter(position, ((Character) value).charValue());
280     } else if (value instanceof Timestamp) {
281       query.setTimestamp(position, (Timestamp) value);
282     } else if (value instanceof Date) {
283       query.setDate(position, (Date) value);
284     } else if (value instanceof Short) {
285       query.setShort(position, ((Short) value).shortValue());
286     }
287   }
288
289   /**
290    * Used by the base DAO classes but here for your modification
291    * Load object matching the given key and return it.
292    */
293   protected Object load(Class refClass, Serializable key) throws DatabaseFailure {
294     try {
295       return load(refClass, key, HibernateSessionManager.getSession());
296     } catch (Exception e) {
297       throw new DatabaseFailure(e);
298     }
299   }
300
301   /**
302    * Used by the base DAO classes but here for your modification
303    * Load object matching the given key and return it.
304    */
305   protected Object load(Class refClass, Serializable key, Session s) 
306     throws DatabaseFailure {
307     try {
308       return s.load(refClass, key);
309     } catch (HibernateException e) {
310       throw new DatabaseFailure(e);
311     }
312   }
313
314   /**
315    * Used by the base DAO classes but here for your modification
316    * Persist the given transient instance, first assigning a generated identifier. 
317    * (Or using the current value of the identifier property if the assigned generator is used.) 
318    */
319   public Serializable save(Object obj) throws DatabaseFailure {
320     try {
321       return save(obj, HibernateSessionManager.getSession());
322     } catch (Throwable e) {
323       throw new DatabaseFailure(e);
324     }
325   }
326
327   /**
328    * Used by the base DAO classes but here for your modification
329    * Persist the given transient instance, first assigning a generated identifier. 
330    * (Or using the current value of the identifier property if the assigned generator is used.) 
331    */
332   protected Serializable save(Object obj, Session s) throws HibernateException {
333     Serializable key = null;
334     Transaction transaction = s.beginTransaction();
335     try {
336       key = s.save(obj);
337       transaction.commit();
338     } catch (HibernateException e) {
339       if(transaction != null){
340         transaction.rollback();
341       }
342     }
343     return key;
344   }
345
346   /**
347    * Used by the base DAO classes but here for your modification
348    * Either save() or update() the given instance, depending upon the value of its
349    * identifier property.
350    */
351   public void saveOrUpdate(Object obj) throws DatabaseFailure {
352     saveOrUpdate(obj, HibernateSessionManager.getSession());
353   }
354
355   /**
356    * Used by the base DAO classes but here for your modification
357    * Either save() or update() the given instance, depending upon the value of its
358    * identifier property.
359    */
360   protected void saveOrUpdate(Object obj, Session s) throws DatabaseFailure {
361     try {
362       s.saveOrUpdate(obj);
363     } catch (Throwable e) {
364       throw new DatabaseFailure(e);
365     }
366   }
367
368   /**
369    * Used by the base DAO classes but here for your modification
370    * Update the persistent state associated with the given identifier. An exception is thrown if there is a persistent
371    * instance with the same identifier in the current session.
372    * @param obj a transient instance containing updated state
373    * @throws 
374    */
375   public void update(Object obj) throws DatabaseFailure {
376     try {
377       update(obj, HibernateSessionManager.getSession());
378     } catch (Throwable e) {
379       throw new DatabaseFailure(e);
380     } 
381   }
382
383   /**
384    * Used by the base DAO classes but here for your modification
385    * Update the persistent state associated with the given identifier. An exception is thrown if there is a persistent
386    * instance with the same identifier in the current session.
387    * @param obj a transient instance containing updated state
388    * @param s the Session
389    */
390   protected void update(Object obj, Session s) throws DatabaseFailure {
391     try {
392       s.update(obj);
393     } catch (HibernateException e) {
394       throw new DatabaseFailure(e);
395     }
396   }
397
398   /**
399    * Used by the base DAO classes but here for your modification
400    * Remove a persistent instance from the datastore. The argument may be an instance associated with the receiving
401    * Session or a transient instance with an identifier associated with existing persistent state. 
402    */
403   public void delete(Object obj) throws DatabaseFailure {
404     delete(obj, HibernateSessionManager.getSession());
405   }
406
407   /**
408    * Used by the base DAO classes but here for your modification
409    * Remove a persistent instance from the datastore. The argument may be an instance associated with the receiving
410    * Session or a transient instance with an identifier associated with existing persistent state. 
411    */
412   protected void delete(Object obj, Session s) throws DatabaseFailure {
413     try {
414       s.delete(obj);
415     } catch (HibernateException e) {
416       throw new DatabaseFailure(e);
417     }
418   }
419
420   /**
421    * Used by the base DAO classes but here for your modification
422    * Re-read the state of the given instance from the underlying database. It is inadvisable to use this to implement
423    * long-running sessions that span many business tasks. This method is, however, useful in certain special circumstances.
424    */
425   protected void refresh(Object obj, Session s) throws DatabaseFailure {
426     try {
427       s.refresh(obj);
428     } catch (HibernateException e) {
429       throw new DatabaseFailure(e);
430     }
431   }
432   
433   protected abstract void initializeCollections(Object o) throws DatabaseFailure;
434 }