View Javadoc

1   /*
2    * ----------------------------------------------------------------------
3    * Copyright (C) 2009 Enrique Lara (k957@68k.org)
4    *
5    * TinLizard is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU Lesser General Public License
7    * as published by the Free Software Foundation; either version 3.0
8    * of the License, or (at your option) any later version.
9    *
10   * TinLizard 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. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public License
16   * along with TinLizard. If not, see http://www.gnu.org/licenses/.
17   * ----------------------------------------------------------------------
18   */
19  package tinlizard.dao.jpa;
20  
21  import tinlizard.model.CurrentUser;
22  import tinlizard.model.TinLizardConfig;
23  
24  import java.util.Collection;
25  import java.util.Date;
26  import java.util.Iterator;
27  import java.util.List;
28  
29  import javax.persistence.EntityExistsException;
30  import javax.persistence.EntityManager;
31  import javax.persistence.EntityManagerFactory;
32  import javax.persistence.EntityNotFoundException;
33  import javax.persistence.EntityTransaction;
34  import javax.persistence.NoResultException;
35  import javax.persistence.NonUniqueResultException;
36  import javax.persistence.Persistence;
37  import javax.persistence.Query;
38  
39  import org.apache.log4j.Logger;
40  import org.apache.lucene.analysis.standard.StandardAnalyzer;
41  import org.apache.lucene.queryParser.MultiFieldQueryParser;
42  
43  import org.hibernate.search.jpa.FullTextEntityManager;
44  import org.hibernate.search.jpa.Search;
45  
46  /***
47   * Dao to wrap/handle common JPA interactions.
48   */
49  public final class JpaDao {
50      private static JpaDao instance = null;
51      private static final ThreadLocal<EntityManager> THREAD_EM = new ThreadLocal<EntityManager>();
52      private static final Logger LOG = Logger.getLogger(JpaDao.class);
53      private final EntityManagerFactory emf;
54  
55      private JpaDao(final TinLizardConfig initializer) {
56          emf = Persistence.createEntityManagerFactory("TinLizardModel", initializer.getJpaProperties());
57      }
58  
59      public static synchronized void initialize(final TinLizardConfig initializer) {
60          if (instance == null) {
61              instance = new JpaDao(initializer);
62          }
63      }
64  
65      public static JpaDao getInstance() {
66          return instance;
67      }
68  
69      public EntityManager getEm() {
70          EntityManager em = THREAD_EM.get();
71  
72          if (em == null) {
73              em = emf.createEntityManager();
74              THREAD_EM.set(em);
75          }
76  
77          return em;
78      }
79  
80      void closeEm() {
81          EntityManager em = THREAD_EM.get();
82  
83          LOG.trace("closeEm");
84  
85          if (em != null) {
86              THREAD_EM.remove();
87  
88              if (em.isOpen()) {
89                  em.close();
90              }
91          }
92      }
93  
94      @SuppressWarnings("unchecked")
95      public void add(final Persistable obj) {
96          //XXX consider @EntityListeners http://www.javaworld.com/javaworld/jw-01-2008/jw-01-jpa1.html?page=4
97          obj.setCreated(new Date());
98          obj.setCreatedBy(CurrentUser.getUsername());
99  
100         EntityManager em = getEm();
101         EntityTransaction tx = em.getTransaction();
102         tx.begin();
103 
104         try {
105             em.persist(obj);
106 
107             tx.commit();
108         } catch (EntityExistsException e) {
109             handleError(tx, "Add Error", e);
110         } catch (Exception e) {
111             handleError(tx, "Add Error", e);
112         }
113     }
114 
115     @SuppressWarnings("unchecked")
116     public void update(final Persistable obj) {
117         obj.setLastModified(new Date());
118         obj.setLastModifiedBy(CurrentUser.getUsername());
119 
120         EntityManager em = getEm();
121         EntityTransaction tx = em.getTransaction();
122         tx.begin();
123 
124         try {
125             em.merge(obj);
126 
127             tx.commit();
128         } catch (Exception e) {
129             handleError(tx, "Update Error", e);
130         }
131     }
132 
133     public void delete(final Class<?> clazz, final Integer id) {
134         EntityManager em = getEm();
135         EntityTransaction tx = em.getTransaction();
136         tx.begin();
137 
138         try {
139             if (LOG.isDebugEnabled()) {
140                 LOG.debug("delete(" + clazz + ", " + id + ")");
141             }
142 
143             Query query = em.createQuery("delete from " + clazz.getSimpleName() + " o where o.id = :id");
144             query.setParameter("id", id);
145 
146             int deleted = query.executeUpdate();
147 
148             if (LOG.isDebugEnabled()) {
149                 LOG.debug("Deleted " + deleted + ".");
150             }
151 
152             tx.commit();
153         } catch (EntityNotFoundException e) {
154             handleInfo(tx, "Object " + clazz + "#" + id + " did not exist", e);
155         } catch (Exception e) {
156             handleError(tx, "Delete Error", e);
157         }
158     }
159 
160     @SuppressWarnings("unchecked")
161     public void index(final Persistable obj) {
162         EntityManager em = getEm();
163         FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
164         EntityTransaction tx = em.getTransaction();
165         tx.begin();
166 
167         try {
168             fullTextEntityManager.index(obj);
169 
170             tx.commit();
171         } catch (Exception e) {
172             handleError(tx, "Index Error", e);
173         }
174     }
175 
176     @SuppressWarnings("unchecked")
177     public void indexAll(final Class<?extends Persistable> clazz) {
178         EntityManager em = getEm();
179         FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
180         EntityTransaction tx = em.getTransaction();
181         tx.begin();
182 
183         try {
184             fullTextEntityManager.purgeAll(clazz);
185 
186             List objects = em.createQuery("select o from " + clazz.getSimpleName() + " o order by o.name").getResultList();
187 
188             for (Iterator iterator = objects.iterator(); iterator.hasNext();) {
189                 Object object = iterator.next();
190 
191                 fullTextEntityManager.index(object);
192             }
193 
194             tx.commit();
195         } catch (Exception e) {
196             handleError(tx, "IndexAll Error", e);
197         }
198     }
199 
200     public void handleInfo(final EntityTransaction tx, final String msg, final Exception e) {
201         rollbackTransaction(tx);
202         LOG.info(msg, e);
203     }
204 
205     public void handleError(final EntityTransaction tx, final String msg, final Exception e) {
206         rollbackTransaction(tx);
207 
208         closeEm();
209         throw new RuntimeException(msg, e);
210     }
211 
212     private void rollbackTransaction(final EntityTransaction tx) {
213         if (tx.isActive()) {
214             tx.rollback();
215         }
216     }
217 
218     @SuppressWarnings("unchecked")
219     public <T> List<T> findAll(final Class<T> clazz) {
220         List<T> rval = null;
221 
222         EntityManager em = getEm();
223         EntityTransaction tx = em.getTransaction();
224         tx.begin();
225 
226         try {
227             rval = em.createQuery("select o from " + clazz.getSimpleName() + " o order by o.name").getResultList();
228 
229             tx.commit();
230         } catch (Exception e) {
231             handleError(tx, "FindAll Error", e);
232         }
233 
234         return rval;
235     }
236 
237     public <T> T findByPrimaryKey(final Class<T> clazz, final Integer id) {
238         T rval = null;
239         EntityManager em = getEm();
240         EntityTransaction tx = em.getTransaction();
241         tx.begin();
242 
243         try {
244             if (LOG.isDebugEnabled()) {
245                 LOG.debug("findByPrimaryKey(" + clazz + ", " + id + ")");
246             }
247 
248             rval = em.find(clazz, id);
249 
250             tx.commit();
251         } catch (Exception e) {
252             handleError(tx, "FindByPrimaryKey Error", e);
253         }
254 
255         return rval;
256     }
257 
258     public void flush() {
259         EntityManager em = getEm();
260         EntityTransaction tx = em.getTransaction();
261         tx.begin();
262 
263         try {
264             em.flush();
265 
266             tx.commit();
267         } catch (Exception e) {
268             handleError(tx, "Flush Error", e);
269         }
270     }
271 
272     @SuppressWarnings("unchecked")
273     public <T> Collection<T> findByNamedQuery(final Class<T> clazz, final String name, final Object... params) {
274         Collection<T> rval = null;
275 
276         EntityManager em = getEm();
277         EntityTransaction tx = em.getTransaction();
278         tx.begin();
279 
280         try {
281             Query q = getEm().createNamedQuery(name);
282 
283             for (int i = 0; i < params.length; i++) {
284                 q.setParameter(i + 1, params[i]);
285             }
286 
287             rval = q.getResultList();
288             tx.commit();
289         } catch (Exception e) {
290             handleError(tx, "FindByNamedQuery Error", e);
291         }
292 
293         return rval;
294     }
295 
296     @SuppressWarnings("unchecked")
297     public <T> T findSingleByNamedQuery(final Class<T> clazz, final String name, final Object... params) {
298         T rval = null;
299 
300         EntityManager em = getEm();
301         EntityTransaction tx = em.getTransaction();
302         tx.begin();
303 
304         try {
305             Query q = getEm().createNamedQuery(name);
306 
307             for (int i = 0; i < params.length; i++) {
308                 q.setParameter(i + 1, params[i]);
309             }
310 
311             rval = (T) q.getSingleResult();
312 
313             tx.commit();
314         } catch (EntityNotFoundException e) {
315             rollbackTransaction(tx);
316             closeEm();
317         } catch (NoResultException e) {
318             rollbackTransaction(tx);
319             closeEm();
320         } catch (NonUniqueResultException e) {
321             handleError(tx, "FindSingleByNamedQuery Error", e);
322         } catch (Exception e) {
323             handleError(tx, "FindSingleByNamedQuery Error", e);
324         }
325 
326         return rval;
327     }
328 
329     @SuppressWarnings("unchecked")
330     public <T> Collection<T> findByTextSearch(final Class<T> clazz, final String query, final String... fields) {
331         Collection<T> rval = null;
332 
333         EntityManager em = getEm();
334         FullTextEntityManager fullTextEntityManager = org.hibernate.search.jpa.Search.getFullTextEntityManager(em);
335         EntityTransaction tx = em.getTransaction();
336         tx.begin();
337 
338         try {
339             // create native Lucene query    		
340             MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, new StandardAnalyzer());
341             org.apache.lucene.search.Query luceneQuery = parser.parse(query);
342 
343             // wrap Lucene query in a javax.persistence.Query
344             javax.persistence.Query persistenceQuery = fullTextEntityManager.createFullTextQuery(luceneQuery, clazz);
345 
346             // execute search
347             rval = persistenceQuery.getResultList();
348 
349             tx.commit();
350         } catch (Exception e) {
351             handleError(tx, "FindByTextSearch Error", e);
352         }
353 
354         return rval;
355     }
356 }