Merge branch 'maint-0.3' into work
[smart-dao.git] / smart-hibernate-abstract-dao / src / main / java / com / smartitengineering / dao / impl / hibernate / AbstractDAO.java
blob70adf0748c9a3bbd41d210c120cede1bc4958c10
1 /*
2 * This is a common dao with basic CRUD operations and is not limited to any
3 * persistent layer implementation
4 *
5 * Copyright (C) 2008 Imran M Yousuf (imyousuf@smartitengineering.com)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 package com.smartitengineering.dao.impl.hibernate;
21 import com.smartitengineering.dao.common.queryparam.BasicCompoundQueryParameter;
22 import com.smartitengineering.dao.common.queryparam.BiOperandQueryParameter;
23 import com.smartitengineering.dao.common.queryparam.CompositionQueryParameter;
24 import com.smartitengineering.dao.common.queryparam.OperatorType;
25 import com.smartitengineering.dao.common.queryparam.QueryParameter;
26 import com.smartitengineering.dao.common.queryparam.QueryParameterCastHelper;
27 import com.smartitengineering.dao.common.queryparam.QueryParameterWithOperator;
28 import com.smartitengineering.dao.common.queryparam.QueryParameterWithPropertyName;
29 import com.smartitengineering.dao.common.queryparam.QueryParameterWithValue;
30 import com.smartitengineering.dao.common.queryparam.SimpleNameValueQueryParameter;
31 import com.smartitengineering.dao.common.queryparam.ValueOnlyQueryParameter;
32 import com.smartitengineering.domain.PersistentDTO;
33 import java.io.Serializable;
34 import java.util.Collection;
35 import java.util.Hashtable;
36 import java.util.List;
38 import java.util.Map;
39 import java.util.WeakHashMap;
40 import org.hibernate.Criteria;
41 import org.hibernate.FetchMode;
42 import org.hibernate.Session;
43 import org.hibernate.criterion.AggregateProjection;
44 import org.hibernate.criterion.Conjunction;
45 import org.hibernate.criterion.CountProjection;
46 import org.hibernate.criterion.Criterion;
47 import org.hibernate.criterion.Disjunction;
48 import org.hibernate.criterion.Expression;
49 import org.hibernate.criterion.Junction;
50 import org.hibernate.criterion.MatchMode;
51 import org.hibernate.criterion.Order;
52 import org.hibernate.criterion.Projection;
53 import org.hibernate.criterion.ProjectionList;
54 import org.hibernate.criterion.Projections;
55 import org.hibernate.criterion.PropertyProjection;
56 import org.hibernate.criterion.Restrictions;
57 import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
59 public abstract class AbstractDAO<Template extends PersistentDTO>
60 extends HibernateDaoSupport
61 implements Serializable {
63 private Map<Criteria, ProjectionList> projections =
64 new WeakHashMap<Criteria, ProjectionList>();
66 protected void createEntity(Template... entities) {
67 if (entities == null) {
68 throw new IllegalArgumentException();
70 Session session;
71 boolean customSession = false;
72 try {
73 session = getSessionFactory().getCurrentSession();
75 catch (Exception ex) {
76 session = getSessionFactory().openSession();
77 customSession = true;
79 try {
80 for (Template entity : entities) {
81 session.save(entity);
84 finally {
85 if (session != null) {
86 session.flush();
87 if (customSession && session.isOpen()) {
88 session.close();
94 protected void updateEntity(Template... entities) {
95 if (entities == null) {
96 throw new IllegalArgumentException();
98 Session session;
99 boolean customSession = false;
100 try {
101 session = getSessionFactory().getCurrentSession();
103 catch (Exception ex) {
104 session = getSessionFactory().openSession();
105 customSession = true;
107 try {
108 for (Template entity : entities) {
109 session.update(entity);
112 finally {
113 if (session != null) {
114 session.flush();
115 if (customSession && session.isOpen()) {
116 session.close();
122 protected void deleteEntity(Template... entities) {
123 if (entities == null) {
124 throw new IllegalArgumentException();
126 Session session;
127 boolean customSession = false;
128 try {
129 session = getSessionFactory().getCurrentSession();
131 catch (Exception ex) {
132 session = getSessionFactory().openSession();
133 customSession = true;
135 try {
136 for (Template entity : entities) {
137 session.delete(entity);
140 finally {
141 if (session != null) {
142 session.flush();
143 if (customSession && session.isOpen()) {
144 session.close();
150 protected Template readSingle(Class entityClass,
151 Hashtable<String, QueryParameter> parameter) {
152 return readSingle(entityClass, parameter.values().toArray(
153 new QueryParameter[0]));
156 protected Object readOther(Class entityClass,
157 Hashtable<String, QueryParameter> parameter) {
158 return readOther(entityClass, parameter.values().toArray(
159 new QueryParameter[0]));
162 protected List<? extends Object> readOtherList(Class entityClass,
163 Hashtable<String, QueryParameter> parameter) {
164 return readOtherList(entityClass, parameter.values().toArray(
165 new QueryParameter[0]));
168 protected List<Template> readList(Class entityClass,
169 Hashtable<String, QueryParameter> parameter) {
170 return readList(entityClass, parameter.values().toArray(
171 new QueryParameter[0]));
174 protected Template readSingle(Class entityClass,
175 List<QueryParameter> parameter) {
176 return readSingle(entityClass, parameter.toArray(new QueryParameter[0]));
179 protected <OtherTemplate extends Object> OtherTemplate readOther(
180 Class entityClass,
181 List<QueryParameter> parameter) {
182 return this.<OtherTemplate>readOther(entityClass, parameter.toArray(new QueryParameter[0]));
185 protected <OtherTemplate extends Object> List<OtherTemplate> readOtherList(
186 Class entityClass,
187 List<QueryParameter> parameter) {
188 return readOtherList(entityClass, parameter.toArray(
189 new QueryParameter[0]));
192 protected List<Template> readList(Class entityClass,
193 List<QueryParameter> parameter) {
194 return readList(entityClass, parameter.toArray(new QueryParameter[0]));
197 protected Template readSingle(Class entityClass,
198 QueryParameter... parameter) {
199 Session session;
200 boolean customSession = false;
201 try {
202 session = getSessionFactory().getCurrentSession();
204 catch (Exception ex) {
205 session = getSessionFactory().openSession();
206 customSession = true;
208 try {
209 Criteria criteria = simpleSearchCriteria(session, entityClass,
210 parameter);
211 return (Template) criteria.uniqueResult();
213 catch (Exception e) {
214 throw new IllegalArgumentException(e);
216 finally {
217 if (session != null) {
218 if (customSession && session.isOpen()) {
219 session.close();
225 protected <OtherTemplate extends Object> OtherTemplate readOther(
226 Class entityClass,
227 QueryParameter... parameter) {
228 Session session;
229 boolean customSession = false;
230 try {
231 session = getSessionFactory().getCurrentSession();
233 catch (Exception ex) {
234 session = getSessionFactory().openSession();
235 customSession = true;
237 try {
238 Criteria criteria = simpleSearchCriteria(session, entityClass,
239 parameter);
240 return (OtherTemplate) criteria.uniqueResult();
242 catch (Exception e) {
243 throw new IllegalArgumentException(e);
245 finally {
246 if (session != null) {
247 if (customSession && session.isOpen()) {
248 session.close();
254 protected <OtherTemplate extends Object> List<OtherTemplate> readOtherList(
255 Class entityClass,
256 QueryParameter... parameter) {
257 Session session;
258 boolean customSession = false;
259 try {
260 session = getSessionFactory().getCurrentSession();
262 catch (Exception ex) {
263 session = getSessionFactory().openSession();
264 customSession = true;
266 try {
267 Criteria criteria = simpleSearchCriteria(session, entityClass,
268 parameter);
269 return criteria.list();
271 catch (Exception e) {
272 throw new IllegalArgumentException(e);
274 finally {
275 if (session != null) {
276 if (customSession && session.isOpen()) {
277 session.close();
283 protected List<Template> readList(Class entityClass,
284 QueryParameter... parameter) {
285 Session session;
286 boolean customSession = false;
287 try {
288 session = getSessionFactory().getCurrentSession();
290 catch (Exception ex) {
291 session = getSessionFactory().openSession();
292 customSession = true;
294 try {
295 Criteria criteria = simpleSearchCriteria(session, entityClass,
296 parameter);
297 return criteria.list();
299 catch (Exception e) {
300 throw new IllegalArgumentException(e);
302 finally {
303 if (session != null) {
304 if (customSession && session.isOpen()) {
305 session.close();
311 protected Criteria simpleSearchCriteria(Session session,
312 Class queryClass,
313 QueryParameter... parameter) {
314 Criteria criteria = session.createCriteria(queryClass);
315 for (QueryParameter param : parameter) {
316 if (!param.isInitialized()) {
317 continue;
319 String propertyName = getPropertyName(param);
320 processCriteria(criteria, propertyName, param);
322 return criteria;
325 @SuppressWarnings("unchecked")
326 private void processCriteria(Criteria criteria,
327 String element,
328 QueryParameter parameter) {
329 switch (parameter.getParameterType()) {
330 case PARAMETER_TYPE_PROPERTY: {
331 criteria.add(getCriterion(element, parameter));
332 return;
334 case PARAMETER_TYPE_ORDER_BY: {
335 final Order order;
336 SimpleNameValueQueryParameter<com.smartitengineering.dao.common.queryparam.Order> queryParameter =
337 QueryParameterCastHelper.SIMPLE_PARAM_HELPER.cast(parameter);
338 com.smartitengineering.dao.common.queryparam.Order requestedOrder =
339 queryParameter.getValue();
340 switch (requestedOrder) {
341 case ASC: {
342 order = Order.asc(element);
343 break;
345 case DESC: {
346 order = Order.desc(element);
347 break;
349 default: {
350 order = null;
351 break;
354 if (order != null) {
355 criteria.addOrder(order);
357 return;
359 case PARAMETER_TYPE_MAX_RESULT: {
360 ValueOnlyQueryParameter<Integer> queryParameter =
361 QueryParameterCastHelper.VALUE_PARAM_HELPER.cast(parameter);
362 criteria.setMaxResults(queryParameter.getValue());
363 return;
365 case PARAMETER_TYPE_FIRST_RESULT: {
366 ValueOnlyQueryParameter<Integer> queryParameter =
367 QueryParameterCastHelper.VALUE_PARAM_HELPER.cast(parameter);
368 criteria.setFirstResult(queryParameter.getValue());
369 return;
371 case PARAMETER_TYPE_DISJUNCTION: {
372 processDisjunction(criteria, parameter);
373 return;
375 case PARAMETER_TYPE_CONJUNCTION: {
376 processConjunction(criteria, parameter);
377 return;
379 case PARAMETER_TYPE_NESTED_PROPERTY: {
380 processNestedParameter(criteria, element, parameter);
381 return;
383 case PARAMETER_TYPE_COUNT: {
384 final Projection countProjection = Projections.count(element);
385 setProjection(criteria, countProjection);
386 return;
388 case PARAMETER_TYPE_ROW_COUNT: {
389 final Projection rowCount = Projections.rowCount();
390 setProjection(criteria, rowCount);
391 return;
393 case PARAMETER_TYPE_SUM: {
394 final AggregateProjection sum = Projections.sum(element);
395 setProjection(criteria, sum);
396 return;
398 case PARAMETER_TYPE_MAX: {
399 final AggregateProjection max = Projections.max(element);
400 setProjection(criteria, max);
401 return;
403 case PARAMETER_TYPE_MIN: {
404 final AggregateProjection min = Projections.min(element);
405 setProjection(criteria, min);
406 return;
408 case PARAMETER_TYPE_AVG: {
409 final AggregateProjection avg = Projections.avg(element);
410 setProjection(criteria, avg);
411 return;
413 case PARAMETER_TYPE_GROUP_BY: {
414 final PropertyProjection groupProperty =
415 Projections.groupProperty(element);
416 setProjection(criteria, groupProperty);
417 return;
419 case PARAMETER_TYPE_COUNT_DISTINCT: {
420 final CountProjection countDistinct =
421 Projections.countDistinct(element);
422 setProjection(criteria, countDistinct);
423 return;
425 case PARAMETER_TYPE_DISTINCT_PROP: {
426 final Projection distinct =
427 Projections.distinct(Projections.property(element));
428 setProjection(criteria, distinct);
429 return;
431 case PARAMETER_TYPE_UNIT_PROP: {
432 final PropertyProjection property =
433 Projections.property(element);
434 setProjection(criteria, property);
435 return;
440 @SuppressWarnings("unchecked")
441 private void processNestedParameter(Criteria criteria,
442 String element,
443 QueryParameter parameter) {
444 FetchMode mode;
445 CompositionQueryParameter queryParameter =
446 QueryParameterCastHelper.COMPOSITION_PARAM_FOR_NESTED_TYPE.cast(
447 parameter);
448 switch (queryParameter.getFetchMode()) {
449 case EAGER:
450 mode = FetchMode.EAGER;
451 break;
452 case SELECT:
453 mode = FetchMode.SELECT;
454 break;
455 case JOIN:
456 mode = FetchMode.JOIN;
457 break;
458 case LAZY:
459 mode = FetchMode.LAZY;
460 break;
461 default:
462 case DEFAULT:
463 mode = FetchMode.DEFAULT;
464 break;
466 criteria.setFetchMode(element, ((mode == null) ? FetchMode.JOIN : mode));
467 Collection<QueryParameter> nestedParameters = queryParameter.
468 getNestedParameters();
469 if (nestedParameters == null || nestedParameters.size() <= 0) {
470 return;
472 Criteria nestedCriteria = criteria.createCriteria(element);
473 for (QueryParameter nestedQueryParameter : nestedParameters) {
474 if (!nestedQueryParameter.isInitialized()) {
475 continue;
477 processCriteria(nestedCriteria,
478 getPropertyName(nestedQueryParameter), nestedQueryParameter);
482 @SuppressWarnings("unchecked")
483 private void processCriterion(Junction criterion,
484 String element,
485 QueryParameter parameter) {
486 switch (parameter.getParameterType()) {
487 case PARAMETER_TYPE_PROPERTY: {
488 criterion.add(getCriterion(element, parameter));
489 return;
491 case PARAMETER_TYPE_CONJUNCTION: {
492 processConjunction(criterion, parameter);
493 break;
495 case PARAMETER_TYPE_DISJUNCTION: {
496 processDisjunction(criterion, parameter);
497 break;
503 @SuppressWarnings("unchecked")
504 private void processDisjunction(Criteria criteria,
505 QueryParameter parameter) {
506 Disjunction disjunction = Expression.disjunction();
507 workOnNestedParams(parameter, disjunction);
508 criteria.add(disjunction);
511 @SuppressWarnings("unchecked")
512 private void processConjunction(Criteria criteria,
513 QueryParameter parameter) {
514 Conjunction conjunction = Expression.conjunction();
515 workOnNestedParams(parameter, conjunction);
516 criteria.add(conjunction);
519 @SuppressWarnings("unchecked")
520 private void processDisjunction(Junction junction,
521 QueryParameter parameter) {
522 Disjunction disjunction = Expression.disjunction();
523 workOnNestedParams(parameter, disjunction);
524 junction.add(disjunction);
527 @SuppressWarnings("unchecked")
528 private void processConjunction(Junction junction,
529 QueryParameter parameter) {
530 Conjunction conjunction = Expression.conjunction();
531 workOnNestedParams(parameter, conjunction);
532 junction.add(conjunction);
535 private Criterion getCriterion(String element,
536 QueryParameter queryParamemter) {
537 OperatorType operator = getOperator(queryParamemter);
538 Object parameter = getValue(queryParamemter);
539 switch (operator) {
540 case OPERATOR_EQUAL: {
541 return Expression.eq(element, parameter);
543 case OPERATOR_LESSER: {
544 return Expression.lt(element, parameter);
546 case OPERATOR_LESSER_EQUAL: {
547 return Expression.le(element, parameter);
549 case OPERATOR_GREATER: {
550 return Expression.gt(element, parameter);
552 case OPERATOR_GREATER_EQUAL: {
553 return Expression.ge(element, parameter);
555 case OPERATOR_NOT_EQUAL: {
556 return Expression.ne(element, parameter);
558 case OPERATOR_IS_NULL: {
559 return Expression.isNull(element);
561 case OPERATOR_IS_NOT_NULL: {
562 return Expression.isNotNull(element);
564 case OPERATOR_IS_EMPTY: {
565 return Expression.isEmpty(element);
567 case OPERATOR_IS_NOT_EMPTY: {
568 return Expression.isNotEmpty(element);
570 case OPERATOR_STRING_LIKE: {
571 MatchMode hibernateMatchMode;
572 com.smartitengineering.dao.common.queryparam.MatchMode matchMode =
573 getMatchMode(queryParamemter);
574 if (matchMode == null) {
575 matchMode =
576 com.smartitengineering.dao.common.queryparam.MatchMode.EXACT;
578 switch (matchMode) {
579 case END:
580 hibernateMatchMode = MatchMode.END;
581 break;
582 case EXACT:
583 hibernateMatchMode = MatchMode.EXACT;
584 break;
585 case START:
586 hibernateMatchMode = MatchMode.START;
587 break;
588 default:
589 case ANYWHERE:
590 hibernateMatchMode = MatchMode.ANYWHERE;
591 break;
593 return Expression.like(element, parameter.toString(),
594 hibernateMatchMode);
596 case OPERATOR_BETWEEN: {
597 parameter = getFirstParameter(queryParamemter);
598 Object parameter2 = getSecondParameter(queryParamemter);
599 return Expression.between(element, parameter, parameter2);
601 case OPERATOR_IS_IN: {
602 Collection inCollectin =
603 QueryParameterCastHelper.MULTI_OPERAND_PARAM_HELPER.cast(
604 queryParamemter).getValues();
605 return Restrictions.in(element, inCollectin);
607 case OPERATOR_IS_NOT_IN: {
608 Collection inCollectin =
609 QueryParameterCastHelper.MULTI_OPERAND_PARAM_HELPER.cast(
610 queryParamemter).getValues();
611 return Restrictions.not(Restrictions.in(element, inCollectin));
614 return null;
617 private String getPropertyName(
618 QueryParameter param) {
619 final String propertyName;
621 if (param instanceof QueryParameterWithPropertyName) {
622 propertyName =
623 ((QueryParameterWithPropertyName) param).getPropertyName();
625 else {
626 propertyName = "";
629 return propertyName;
632 private void setProjection(Criteria criteria,
633 final Projection projection) {
634 ProjectionList currentProjections = projections.get(
635 criteria);
636 if (currentProjections == null) {
637 currentProjections = Projections.projectionList();
638 projections.put(criteria, currentProjections);
639 criteria.setProjection(currentProjections);
642 currentProjections.add(projection);
645 private void workOnNestedParams(QueryParameter parameter,
646 Junction criterion) {
647 BasicCompoundQueryParameter queryParameter =
648 QueryParameterCastHelper.BASIC_COMPOUND_PARAM_HELPER.cast(parameter);
649 Collection<QueryParameter> nestedParameters =
650 queryParameter.getNestedParameters();
651 for (QueryParameter nestedParam : nestedParameters) {
652 if (!nestedParam.isInitialized()) {
653 continue;
655 processCriterion(criterion, getPropertyName(nestedParam),
656 nestedParam);
661 private OperatorType getOperator(QueryParameter queryParamemter) {
662 if (QueryParameterCastHelper.BASIC_COMPOUND_PARAM_HELPER.isWithOperator(
663 queryParamemter)) {
664 QueryParameterWithOperator parameterWithOperator =
665 QueryParameterCastHelper.BI_OPERAND_PARAM_HELPER.
666 castToOperatorParam(
667 queryParamemter);
668 return parameterWithOperator.getOperatorType();
670 else {
671 return null;
675 private Object getValue(QueryParameter queryParamemter) {
676 Object value;
677 if (queryParamemter instanceof QueryParameterWithValue) {
678 value = ((QueryParameterWithValue) queryParamemter).getValue();
680 else {
681 value = null;
683 if (value == null) {
684 value = "";
686 return value;
689 private Object getSecondParameter(QueryParameter queryParamemter) {
690 if (queryParamemter instanceof BiOperandQueryParameter) {
691 return QueryParameterCastHelper.BI_OPERAND_PARAM_HELPER.cast(
692 queryParamemter).getSecondValue();
694 else {
695 return "";
699 private Object getFirstParameter(QueryParameter queryParamemter) {
700 if (queryParamemter instanceof BiOperandQueryParameter) {
701 return QueryParameterCastHelper.BI_OPERAND_PARAM_HELPER.cast(
702 queryParamemter).getFirstValue();
704 else {
705 return "";
709 private com.smartitengineering.dao.common.queryparam.MatchMode getMatchMode(
710 QueryParameter queryParamemter) {
711 return QueryParameterCastHelper.STRING_PARAM_HELPER.cast(queryParamemter).
712 getMatchMode();