View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2010 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
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. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  package ch.elca.el4j.services.persistence.jpa.dao;
18  
19  import java.io.Serializable;
20  import java.util.Collection;
21  import java.util.List;
22  
23  import javax.persistence.EntityManager;
24  import javax.persistence.EntityManagerFactory;
25  import javax.persistence.PersistenceException;
26  import javax.persistence.TypedQuery;
27  import javax.persistence.criteria.CriteriaQuery;
28  
29  import org.springframework.dao.DataAccessException;
30  import org.springframework.dao.DataRetrievalFailureException;
31  import org.springframework.dao.OptimisticLockingFailureException;
32  import org.springframework.orm.hibernate3.HibernateTemplate;
33  import org.springframework.orm.jpa.JpaCallback;
34  import org.springframework.orm.jpa.JpaOptimisticLockingFailureException;
35  import org.springframework.orm.jpa.JpaTemplate;
36  import org.springframework.util.Assert;
37  
38  import ch.elca.el4j.services.monitoring.notification.PersistenceNotificationHelper;
39  import ch.elca.el4j.services.search.QueryObject;
40  import ch.elca.el4j.util.codingsupport.Reject;
41  
42  /**
43   * This is a convenience class for the Jpa template.
44   *  Features:
45   *   <ul>
46   *      <li> improved paging support: allows to specify id of 1st element of a
47   *            query
48   *      <li> methods that signal an error if no element is found
49   *            (they use the <em>Strong</em> suffixes)
50   *   </ul>
51   *
52   * @svnLink $Revision: 4253 $;$Date: 2010-12-21 11:08:04 +0100 (Di, 21. Dez 2010) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/hibernate/src/main/java/ch/elca/el4j/services/persistence/jpa/dao/ConvenienceJpaTemplate.java $
53   *
54   * @author Simon Stelling (SST)
55   */
56  public class ConvenienceJpaTemplate extends JpaTemplate {
57  	
58  	/**
59  	 * Constructor.
60  	 * @param emf EntityManagerFactory used to create EntityManager
61  	 */
62  	public ConvenienceJpaTemplate(EntityManagerFactory emf) {
63  		super(emf);
64  	}
65  
66  	/**
67  	 * Merges the given persistent instance in a strong way: does the
68  	 * same as the <code>saveOrUpdate(Object)</code> method, but throws a more
69  	 * specific <code>OptimisticLockingFailureException</code> in the case of
70  	 * an optimistic locking failure.
71  	 *
72  	 * @see HibernateTemplate#saveOrUpdate(Object)
73  	 * @param entity
74  	 *            the persistent entity to save or update
75  	 * @param objectName
76  	 *            Name of the persistent object type.
77  	 * @throws DataAccessException
78  	 *             in case of Hibernate errors
79  	 * @throws OptimisticLockingFailureException
80  	 *             in case optimistic locking fails
81  	 * @return the merged entity
82  	 */
83  	public Object mergeStrong(Object entity, final String objectName)
84  		throws DataAccessException, OptimisticLockingFailureException {
85  		
86  		Reject.ifNull(entity);
87  		Reject.ifEmpty(objectName, "The name of the persistent object type "
88  			+ "must not be empty.");
89  		try {
90  			return merge(entity);
91  		} catch (JpaOptimisticLockingFailureException holfe) {
92  			String message = "The current " + objectName + " was modified or"
93  				+ " deleted in the meantime.";
94  			PersistenceNotificationHelper.notifyOptimisticLockingFailure(
95  				message, objectName, holfe);
96  			throw holfe;
97  		}
98  	}
99  	
100 	//// paging support /////
101 	
102 	/**
103 	 * for paging: what is the id of the first result to return?
104 	 *  NO_CONSTRAINT means we do not constrain anything
105 	 */
106 	int m_firstResult = QueryObject.NO_CONSTRAINT;
107 	
108 	/**
109 	 * Gets the id of the first result to return.
110 	 * @return The id of the first result to return.
111 	 */
112 	public int getFirstResult() {
113 		return m_firstResult;
114 	}
115 
116 	/**
117 	 * Sets the id of the first result to return.
118 	 * @param firstResult The id of the first result to return.
119 	 */
120 	public void setFirstResult(int firstResult) {
121 		m_firstResult = firstResult;
122 	}
123 
124 	/**
125 	 * Finds entities matching the given criteria query.
126 	 * @param <T> the entity type
127 	 * @param criteria the criteria query to run against the database
128 	 * @return the list of found objects, which may be empty.
129 	 */
130 	public <T> List<T> findByCriteria(final CriteriaQuery<T> criteria) {
131 		Assert.notNull(criteria, "CriteriaQuery must not be null");
132 		return execute(new JpaCallback<List<T>>() {
133 
134 			@Override
135 			public List<T> doInJpa(EntityManager em) throws PersistenceException {
136 				return em.createQuery(criteria).getResultList();
137 			}
138 		});
139 	}
140 	
141 	/**
142 	 * Finds entities matching the given criteria query, with paging support.
143 	 * @param <T> the entity type
144 	 * @param criteria the criteria query to run against the database
145 	 * @param firstResult the index of the first row to return
146 	 * @param maxResults the maximum number of rows to return
147 	 * @return the list of found objects, which may be empty.
148 	 */
149 	public <T> List<T> findByCriteria(final CriteriaQuery<T> criteria, final int firstResult, final int maxResults) {
150 		Assert.notNull(criteria, "CriteriaQuery must not be null");
151 		return execute(new JpaCallback<List<T>>() {
152 
153 			@Override
154 			public List<T> doInJpa(EntityManager em) throws PersistenceException {
155 				TypedQuery<T> query = em.createQuery(criteria);
156 				query.setFirstResult(firstResult);
157 				query.setMaxResults(maxResults);
158 				return query.getResultList();
159 			}
160 		});
161 
162 	}
163 	
164 	/**
165 	 * Retrieves the persistent instance given by its identifier in a strong
166 	 * way: does the same as the <code>find(Class, java.io.Serializable)</code>
167 	 * method, but throws a <code>DataRetrievalException</code> instead of
168 	 * <code>null</code> if the persistent instance could not be found.
169 	 *
170 	 * @param <T> entity type
171 	 * @param entityClass
172 	 *            The class of the object which should be returned.
173 	 * @param id
174 	 *            An identifier of the persistent instance
175 	 * @param objectName
176 	 *            Name of the persistent object type.
177 	 * @return the persistent instance
178 	 * @throws org.springframework.dao.DataAccessException
179 	 *             in case of Jpa persistence exceptions
180 	 * @throws org.springframework.dao.DataRetrievalFailureException
181 	 *             in case the persistent instance is null
182 	 */
183 	public <T> T findByIdStrong(Class<T> entityClass, Serializable id, final String objectName)
184 		throws DataAccessException, DataRetrievalFailureException {
185 
186 		Reject.ifNull(id, "The identifier must not be null.");
187 		Reject.ifEmpty(objectName, "The name of the persistent object type "
188 			+ "must not be empty.");
189 		
190 		T result = find(entityClass, id);
191 		
192 		if (result == null || !(entityClass.isInstance(result))) {
193 			PersistenceNotificationHelper.notifyObjectRetrievalFailure(entityClass, id, objectName);
194 		}
195 		return result;
196 	}
197 	
198 	/**
199 	 * Retrieves the persistent instance given by its identifier in a strong
200 	 * way: does the same as the <code>getReference(Class, java.io.Serializable)</code>
201 	 * method, but throws a <code>DataRetrievalException</code> instead of
202 	 * <code>null</code> if the persistent instance could not be found.
203 	 *
204 	 * @param <T> entity type
205 	 * @param entityClass
206 	 *            The class of the object which should be returned.
207 	 * @param id
208 	 *            An identifier of the persistent instance
209 	 * @param objectName
210 	 *            Name of the persistent object type.
211 	 * @return the persistent instance
212 	 * @throws org.springframework.dao.DataAccessException
213 	 *             in case of Jpa persistence exceptions
214 	 * @throws org.springframework.dao.DataRetrievalFailureException
215 	 *             in case the persistent instance is null
216 	 */
217 	public <T> T findByIdStrongLazy(Class<T> entityClass, Serializable id, final String objectName)
218 		throws DataAccessException, DataRetrievalFailureException {
219 
220 		Reject.ifNull(id, "The identifier must not be null.");
221 		Reject.ifEmpty(objectName, "The name of the persistent object type "
222 			+ "must not be empty.");
223 		
224 		T result = getReference(entityClass, id);
225 		
226 		if (result == null || !(entityClass.isInstance(result))) {
227 			PersistenceNotificationHelper.notifyObjectRetrievalFailure(entityClass, id, objectName);
228 		}
229 		return result;
230 	}
231 
232 	/**
233 	 * Removes the persistent instance given by its identifier in a strong way:
234 	 * first, the persistent instance is retrieved with the help of the
235 	 * identifier. If it exists, it will be deleted, otherwise a
236 	 * <code>DataRetrievalFailureException</code> will be thrown.
237 	 *
238 	 * @see JpaTemplate#remove(Object)
239 	 * @param entityClass
240 	 *            The class of the object which should be deleted.
241 	 * @param id
242 	 *            The identifier of the persistent instance to delete
243 	 * @param objectName
244 	 *            Name of the persistent object type.
245 	 * @throws org.springframework.dao.DataRetrievalFailureException
246 	 *             in case the persistent instance to delete is null
247 	 */
248 	public void removeStrong(Class<?> entityClass, Serializable id, final String objectName)
249 		throws DataRetrievalFailureException {
250 		
251 		Reject.ifEmpty(objectName, "The name of the persistent object type "
252 			+ "must not be empty.");
253 		Object toDelete = null;
254 		try {
255 			toDelete = findByIdStrong(entityClass, id, objectName);
256 		} catch (DataRetrievalFailureException e) {
257 			String message = "The current " + objectName + " was "
258 				+ "deleted already!";
259 			PersistenceNotificationHelper.notifyOptimisticLockingFailure(
260 				message, objectName, null);
261 		}
262 		remove(toDelete);
263 	}
264 	
265 	/**
266 	 * removes all entities in the given collection.
267 	 * @param entities the collection of all entities.
268 	 */
269 	public void removeAll(final Collection<?> entities) {
270 		execute(new JpaCallback<Void>() {
271 
272 			@Override
273 			public Void doInJpa(EntityManager em) throws PersistenceException {
274 				for (Object e : entities) {
275 					em.remove(e);
276 				}
277 				return null;
278 			}
279 			
280 		});
281 	}
282 }