View Javadoc

1   // Copyright 2007-2008 Thiago H. de Paula Figueiredo
2   //
3   // Licensed under the Apache License, Version 2.0 (the "License");
4   // you may not use this file except in compliance with the License.
5   // You may obtain a copy of the License at
6   //
7   //     http://www.apache.org/licenses/LICENSE-2.0
8   //
9   // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  
15  package br.com.arsmachina.dao.hibernate;
16  
17  import java.io.Serializable;
18  import java.util.List;
19  
20  import org.hibernate.Criteria;
21  import org.hibernate.LockMode;
22  import org.hibernate.SessionFactory;
23  import org.hibernate.classic.Session;
24  import org.hibernate.criterion.Example;
25  import org.hibernate.criterion.MatchMode;
26  import org.hibernate.criterion.Order;
27  import org.hibernate.criterion.Projections;
28  import org.hibernate.criterion.Restrictions;
29  
30  import br.com.arsmachina.dao.ReadableDAO;
31  import br.com.arsmachina.dao.SortCriterion;
32  
33  /**
34   * {@link ReadableDAO} implementation using Hibernate. All methods use {@link #getSession()} to get
35   * {@link Session}.
36   * 
37   * @author Thiago H. de Paula Figueiredo
38   * @param <T> the entity class related to this DAO.
39   * @param <K> the type of the field that represents the entity class' primary key.
40   */
41  public abstract class ReadableDAOImpl<T, K extends Serializable> extends BaseHibernateDAO<T, K>
42  		implements ReadableDAO<T, K> {
43  
44  	/**
45  	 * A {@link SortCriterion} array with no elements.
46  	 */
47  	final public static SortCriterion[] EMPTY_SORTING_CRITERIA = new SortCriterion[0];
48  
49  	final private String defaultHqlOrderBy = toHqlOrderBy(getDefaultSortCriteria());
50  
51  	/**
52  	 * Returns a HQL <code>order by</code> clause given some {@link SortCriterion}s.
53  	 * 
54  	 * @param sortCriteria {@link SortCriterion} instances.
55  	 * @return a {@link String}.
56  	 */
57  	final public static String toHqlOrderBy(SortCriterion... sortCriteria) {
58  
59  		String string = "";
60  
61  		if (sortCriteria.length > 0) {
62  
63  			StringBuilder builder = new StringBuilder(" ORDER BY ");
64  
65  			for (int i = 0; i < sortCriteria.length - 1; i++) {
66  				builder.append(sortCriteria.toString());
67  				builder.append(", ");
68  			}
69  
70  			builder.append(sortCriteria[sortCriteria.length - 1]);
71  
72  			string = builder.toString();
73  
74  		}
75  
76  		return string;
77  
78  	}
79  
80  	/**
81  	 * Constructor that takes a {@link Class} and a {@link SessionFactory}.
82  	 * 
83  	 * @param clasz a {@link Class}.
84  	 * @param sessionFactory a {@link SessionFactory}. It cannot be null.
85  	 */
86  	@SuppressWarnings("unchecked")
87  	public ReadableDAOImpl(SessionFactory sessionFactory) {
88  		super(null, sessionFactory);
89  	}
90  
91  	/**
92  	 * Constructor that takes a {@link Class} and a {@link SessionFactory}.
93  	 * 
94  	 * @param clasz a {@link Class}.
95  	 * @param sessionFactory a {@link SessionFactory}. It cannot be null.
96  	 */
97  	@SuppressWarnings("unchecked")
98  	public ReadableDAOImpl(Class<T> clasz, SessionFactory sessionFactory) {
99  		super(clasz, sessionFactory);
100 	}
101 
102 	/**
103 	 * @see br.com.arsmachina.dao.ReadableDAO#countAll()
104 	 */
105 	public int countAll() {
106 
107 		final Criteria criteria = createCriteria();
108 
109 		criteria.setProjection(Projections.rowCount());
110 
111 		return (Integer) criteria.uniqueResult();
112 
113 	}
114 
115 	/**
116 	 * Returns all the entity class' objects. They are sorted according to
117 	 * {@link #getDefaultSortCriterions()}.
118 	 * 
119 	 * @see br.com.arsmachina.dao.ReadableDAO#findAll()
120 	 * @see #getDefaultSortCriterions()
121 	 */
122 	@SuppressWarnings("unchecked")
123 	public List<T> findAll() {
124 
125 		Criteria criteria = createCriteria();
126 		addSortCriteria(criteria, getDefaultSortCriteria());
127 		return criteria.list();
128 
129 	}
130 
131 	/**
132 	 * @see br.com.arsmachina.dao.ReadableDAO#findById(java.io.Serializable)
133 	 */
134 	@SuppressWarnings("unchecked")
135 	public T findById(K id) {
136 		return (T) getSession().get(getEntityClass(), id);
137 	}
138 
139 	/**
140 	 * @see br.com.arsmachina.dao.ReadableDAO#findByIds(K[])
141 	 */
142 	@SuppressWarnings("unchecked")
143 	public List<T> findByIds(K... ids) {
144 
145 		Criteria criteria = createCriteria();
146 		criteria.add(Restrictions.in(getPrimaryKeyPropertyName(), ids));
147 		return criteria.list();
148 
149 	}
150 
151 	/**
152 	 * @see br.com.arsmachina.dao.ReadableDAO#findByExample(java.lang.Object)
153 	 */
154 	@SuppressWarnings("unchecked")
155 	public List<T> findByExample(T example) {
156 
157 		Criteria criteria = createCriteria();
158 
159 		if (example != null) {
160 			criteria.add(createExample(example));
161 		}
162 
163 		return criteria.list();
164 
165 	}
166 
167 	/**
168 	 * @see br.com.arsmachina.dao.WriteableDAO#refresh(java.lang.Object)
169 	 */
170 	public void refresh(T object) {
171 		getSession().refresh(object);
172 	}
173 
174 	/**
175 	 * If <code>sortingConstraints</code> is <code>null</code> or empty, this implementation
176 	 * sort the results by the {@link SortCriterion}s returned by
177 	 * {@link #getDefaultSortCriterions()}.
178 	 * 
179 	 * @see br.com.arsmachina.dao.ReadableDAO#findAll(int, int,
180 	 * br.com.arsmachina.dao.SortCriterion[])
181 	 */
182 	@SuppressWarnings("unchecked")
183 	public List<T> findAll(int firstResult, int maximumResults, SortCriterion... sortingConstraints) {
184 
185 		Criteria criteria = createCriteria();
186 		criteria.setFirstResult(firstResult);
187 		criteria.setMaxResults(maximumResults);
188 
189 		if (sortingConstraints == null || sortingConstraints.length == 0) {
190 			sortingConstraints = getDefaultSortCriteria();
191 		}
192 
193 		addSortCriteria(criteria, sortingConstraints);
194 
195 		return criteria.list();
196 
197 	}
198 
199 	/**
200 	 * Reattaches the object to the current {@link org.hibernate.Session} using
201 	 * <code>Session.lock(object, LockMode.NONE)</code> and then returns the object.
202 	 * 
203 	 * @param a <code>T</code>.
204 	 * @return <code>object</code>.
205 	 * @see br.com.arsmachina.dao.ReadableDAO#reattach(java.lang.Object)
206 	 */
207 	public T reattach(T object) {
208 		
209 		getSession().lock(object, LockMode.NONE);
210 		return object;
211 		
212 	}
213 	
214 	/**
215 	 * Adds <code>sortCriteria</code> to a {@link Criteria} instance.
216 	 * 
217 	 * @param criteria a {@link Criteria}. It cannot be null.
218 	 * @param sortCriteria a {@link SortCriterion}<code>...</code>. It cannot be null.
219 	 * @todo Support for property paths, not just property names.
220 	 */
221 	final public void addSortCriteria(Criteria criteria, SortCriterion... sortCriteria) {
222 
223 		assert criteria != null;
224 		
225 		if (sortCriteria == null || sortCriteria.length == 0) {
226 			sortCriteria = getDefaultSortCriteria();
227 		}
228 		
229 		for (SortCriterion sortingConstraint : sortCriteria) {
230 
231 			final String property = sortingConstraint.getProperty();
232 			final boolean ascending = sortingConstraint.isAscending();
233 			final Order order = ascending ? Order.asc(property) : Order.desc(property);
234 			criteria.addOrder(order);
235 
236 		}
237 
238 	}
239 
240 	/**
241 	 * Adds the default sort criteria to a {@link Criteria} instance. This method just does
242 	 * <code>addSortCriteria(criteria, getDefaultSortCriteria());</code>.
243 	 * 
244 	 * @param criteria a {@link Criteria}. It cannot be null.
245 	 */
246 	protected void addSortCriteria(Criteria criteria) {
247 		addSortCriteria(criteria, getDefaultSortCriteria());
248 	}
249 
250 	/**
251 	 * Returns the default {@link SortCriterion}s to be used to sort the objects lists returned by
252 	 * methods like {@link #findAll()} and {@link #findAll(int, int, SortCriterion...)} when no
253 	 * sorting constraints are given. This implementation returns {@link #EMPTY_SORTING_CRITERIA}.
254 	 * 
255 	 * @return a {@link SortCriterion} array. It cannot be <code>null</code>.
256 	 */
257 	public SortCriterion[] getDefaultSortCriteria() {
258 		return EMPTY_SORTING_CRITERIA;
259 	}
260 
261 	/**
262 	 * Creates a {@link Criteria} for this entity class.
263 	 * 
264 	 * @return a {@link Criteria}.
265 	 */
266 	public Criteria createCriteria() {
267 		return getSession().createCriteria(getEntityClass());
268 	}
269 
270 	/**
271 	 * Creates a {@link Criteria} for this entity class with given sort criteria.
272 	 * 
273 	 * @return a {@link Criteria}.
274 	 */
275 	public Criteria createCriteria(SortCriterion ... sortCriteria) {
276 		
277 		Criteria criteria = createCriteria();
278 		addSortCriteria(criteria, sortCriteria);
279 		return criteria;
280 		
281 	}
282 
283 	/**
284 	 * Creates a {@link Criteria} for this entity class with given sort criteria,
285 	 * first result index and maximum number of results. 
286 	 * 
287 	 * @return a {@link Criteria}.
288 	 */
289 	public Criteria createCriteria(int firstIndex, int maximumResults, SortCriterion ... sortCriteria) {
290 		
291 		Criteria criteria = createCriteria(sortCriteria);
292 		criteria.setFirstResult(firstIndex);
293 		criteria.setMaxResults(maximumResults);
294 		return criteria;
295 		
296 	}
297 
298 	/**
299 	 * Used by {@link #findByExample(Object)} to create an {@link Example} instance.
300 	 * 
301 	 * @todo add criteria for property types not handled by Example (primary keys, associations,
302 	 * etc)
303 	 * @return an {@link Example}.
304 	 */
305 	public Example createExample(T entity) {
306 
307 		Example example = Example.create(entity);
308 		example.enableLike(MatchMode.ANYWHERE);
309 		example.excludeZeroes();
310 		example.ignoreCase();
311 
312 		return example;
313 
314 	}
315 
316 	/**
317 	 * Returns the value of the <code>defaultHqlOrderBy</code> property.
318 	 * 
319 	 * @return a {@link String}.
320 	 */
321 	public final String getDefaultHqlOrderBy() {
322 		return defaultHqlOrderBy;
323 	}
324 
325 }