1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package net.smartlab.web;
24
25 import java.io.Serializable;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35
36 import net.smartlab.web.DataAccessObject.SearchInfo.Filter;
37 import net.smartlab.web.bean.ConversionException;
38 import net.smartlab.web.bean.ConverterManager;
39 import net.smartlab.web.config.FactoryConfigurationStrategy;
40 import net.smartlab.web.config.JNDIConfigurationStrategy;
41
42 import org.apache.commons.logging.Log;
43 import org.apache.commons.logging.LogFactory;
44 import org.hibernate.Criteria;
45 import org.hibernate.FetchMode;
46 import org.hibernate.HibernateException;
47 import org.hibernate.Query;
48 import org.hibernate.Session;
49 import org.hibernate.SessionFactory;
50 import org.hibernate.Transaction;
51 import org.hibernate.criterion.Expression;
52 import org.hibernate.criterion.Order;
53 import org.hibernate.criterion.Projections;
54 import org.hibernate.impl.CriteriaImpl;
55 import org.hibernate.impl.SessionImpl;
56 import org.hibernate.metadata.ClassMetadata;
57 import org.hibernate.persister.entity.EntityPersister;
58 import org.hibernate.transform.ResultTransformer;
59
60
61
62
63
64
65
66
67
68
69 public abstract class BusinessObjectFactory implements DataAccessObject {
70
71
72
73
74 protected final Log logger = LogFactory.getLog(this.getClass());
75
76
77
78
79 private static final ThreadLocal sessions = new ThreadLocal();
80
81
82
83
84 private static final ThreadLocal transaction = new ThreadLocal();
85
86
87
88
89
90 protected SessionFactory factory;
91
92
93
94
95 private static FactoryConfigurationStrategy strategy = new JNDIConfigurationStrategy();
96 static {
97 try {
98 String strategy = System.getProperty("smartweb.factory.strategy");
99 if (strategy != null) {
100 BusinessObjectFactory.strategy = (FactoryConfigurationStrategy)Class.forName(strategy).newInstance();
101 } else {
102 LogFactory.getLog(BusinessObjectFactory.class).warn(
103 "No configuration found: falling back to default configuration");
104 }
105 } catch (Exception e) {
106 LogFactory.getLog(BusinessObjectFactory.class).fatal("Error configuring SmartWeb", e);
107 }
108 }
109
110
111
112
113
114
115
116
117 public static void setConfigurationStrategy(FactoryConfigurationStrategy strategy) {
118 BusinessObjectFactory.strategy = strategy;
119 }
120
121
122
123
124
125
126
127 public static void close() throws DAOException {
128 Map sessions = (Map)BusinessObjectFactory.sessions.get();
129 if (sessions != null) {
130 Iterator iterator = sessions.values().iterator();
131 while (iterator.hasNext()) {
132 Session session = (Session)iterator.next();
133 if (session != null && session.isOpen()) {
134 try {
135 session.flush();
136 session.close();
137 } catch (HibernateException he) {
138 throw new DAOException("session.error.close", he);
139 } finally {
140 BusinessObjectFactory.sessions.set(null);
141 }
142 }
143 }
144 }
145 }
146
147
148
149
150
151 public static void flush() throws DAOException {
152 Map sessions = (Map)BusinessObjectFactory.sessions.get();
153 if (sessions != null) {
154 Iterator iterator = sessions.keySet().iterator();
155 while (iterator.hasNext()) {
156 Session session = (Session)sessions.get(iterator.next());
157 if (session != null && session.isOpen()) {
158 try {
159 session.flush();
160 } catch (HibernateException he) {
161 throw new DAOException("session.error.close", he);
162 } finally {
163 BusinessObjectFactory.sessions.set(null);
164 }
165 }
166 }
167 }
168 }
169
170
171
172
173
174
175
176
177
178 protected BusinessObjectFactory() {
179 this.factory = strategy.getSessionFactory(this);
180 }
181
182
183
184
185
186
187
188
189
190
191
192 protected Session current() throws DAOException {
193 if (logger.isDebugEnabled()) {
194 logger.debug("current() - start");
195 }
196 Map sessions = (Map)BusinessObjectFactory.sessions.get();
197 if (sessions == null) {
198 sessions = new HashMap();
199 BusinessObjectFactory.sessions.set(sessions);
200 }
201 try {
202 Session session = (Session)sessions.get(factory);
203 if (session == null) {
204 try {
205 session = factory.openSession();
206 sessions.put(factory, session);
207 } catch (Exception e) {
208 throw new DAOException("session.error.config", e);
209 }
210 }
211 return session;
212 } catch (Exception e) {
213 throw new DAOException("session.error.config.not-found", e);
214 }
215 }
216
217
218
219
220 public Object findByKey(Serializable key) throws DAOException {
221 if (logger.isDebugEnabled()) {
222 logger.debug("findByKey(key = " + key + ") - start");
223 }
224 Serializable convertedKey = this.convertKey(key);
225 if (convertedKey == null) {
226 try {
227 logger.debug("findByKey(key = " + key + ") - new instance");
228 return this.getMappedClass().newInstance();
229 } catch (Exception e) {
230 logger.debug("findByKey(key = " + key + ") - instantiation failed", e);
231 throw new DAOException("session.error.select", e);
232 }
233 } else {
234 Session session = this.current();
235 try {
236 return session.get(this.getMappedClass(), convertedKey);
237 } catch (HibernateException he) {
238 logger.debug("findByKey(key = " + key + ") - deserialization failed", he);
239 throw new UndefinedKeyException(key, this.getMappedClass(), he);
240 }
241 }
242 }
243
244
245
246
247
248
249
250
251 public Object findByKey(Serializable key, String[] fetch) throws DAOException {
252 if (logger.isDebugEnabled()) {
253 logger.debug("findByKey(key = " + key + ", fetch = " + fetch + ") - start");
254 }
255 Serializable convertedKey = this.convertKey(key);
256 if (convertedKey == null) {
257 try {
258 return this.getMappedClass().newInstance();
259 } catch (Exception e) {
260 logger.debug("findByKey(key = " + key + ") - instantiation failed", e);
261 throw new DAOException("session.error.select", e);
262 }
263 } else {
264 Session session = this.current();
265 try {
266 EntityPersister persister = ((SessionImpl)session).getFactory().getEntityPersister(
267 this.getMappedClass().getName());
268 Criteria criteria = session.createCriteria(this.getMappedClass());
269 criteria.add(Expression.eq(persister.getIdentifierPropertyName(), convertedKey));
270 if (fetch != null) {
271 for (int i = 0; i < fetch.length; i++) {
272 criteria.setFetchMode(fetch[i], FetchMode.JOIN);
273 }
274 }
275 return criteria.uniqueResult();
276 } catch (HibernateException he) {
277 logger.debug("findByKey(key = " + key + ", fetch = " + fetch + ") - deserialization failed", he);
278 throw new UndefinedKeyException(key, this.getMappedClass(), he);
279 }
280 }
281 }
282
283
284
285
286 public void remove(Object object) throws DAOException {
287 if (logger.isDebugEnabled()) {
288 logger.debug("remove(object = " + object + ") - start");
289 }
290 try {
291 this.current().delete(object);
292 } catch (HibernateException he) {
293 logger.debug("remove(object = " + object + ") - failed", he);
294 throw new DAOException("session.error.remove", he);
295 }
296 }
297
298
299
300
301 public void update(Object object) throws DAOException {
302 if (logger.isDebugEnabled()) {
303 logger.debug("update(object = " + object + ") - start");
304 }
305 try {
306 this.current().saveOrUpdate(object);
307 } catch (HibernateException he) {
308 logger.debug("update(object = " + object + ") - failed", he);
309 this.current().clear();
310 throw new DAOException("session.error.update", he);
311 }
312 }
313
314
315
316
317 public Collection list(SearchInfo info) throws DAOException {
318 if (logger.isDebugEnabled()) {
319 logger.debug("list(info = " + info + ") - start");
320 }
321 Criteria criteria = this.createCriteria(info);
322 try {
323 return criteria.list();
324 } catch (HibernateException he) {
325 logger.debug("list(info = " + info + ") - failed", he);
326 throw new DAOException("session.error.search", he);
327 }
328 }
329
330
331
332
333
334
335
336
337 public Collection list(SearchInfo info, String[] fetch) throws DAOException {
338 if (logger.isDebugEnabled()) {
339 logger.debug("list(info = " + info + ", fetch = " + fetch + ") - start");
340 }
341 try {
342 Criteria criteria = this.createCriteria(info);
343 for (int i = 0; i < fetch.length; i++) {
344 criteria.setFetchMode(fetch[i], FetchMode.SELECT);
345 }
346 return criteria.list();
347 } catch (HibernateException he) {
348 logger.debug("list(info = " + info + ", fetch = " + fetch + ") - deserialization failed", he);
349 throw new DAOException("session.error.search", he);
350 }
351 }
352
353
354
355
356
357
358
359
360
361
362
363
364
365 public Collection listByKeySet(Set keys, SearchInfo info) throws DAOException {
366 return this.listByKeySet(keys, info, false);
367 }
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385 public Collection listByKeySet(String keyFieldName, Set keys, SearchInfo info) throws DAOException {
386 return this.listByKeySet(keys, info, false);
387 }
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403 public Collection listByKeySet(Set keys, SearchInfo info, boolean exclude) throws DAOException {
404 if (logger.isDebugEnabled()) {
405 logger.debug("list(keys = " + keys + ", info = " + info + ", exclude = " + exclude + ") - start");
406 }
407 Criteria criteria = this.createCriteria(info);
408 String identifier =
409 factory.getClassMetadata(this.getMappedClass()).getIdentifierPropertyName();
410 keys = this.convertKeys(keys);
411 if (identifier != null && !keys.isEmpty()) {
412 if (exclude) {
413 criteria.add(Expression.not(Expression.in(identifier, keys)));
414 } else {
415 criteria.add(Expression.in(identifier, keys));
416 }
417 }
418 try {
419 return criteria.list();
420 } catch (HibernateException he) {
421 throw new DAOException("session.error.search", he);
422 }
423 }
424
425
426
427
428
429
430
431
432
433
434
435 public Collection page(SearchInfo info) throws DAOException {
436 if (logger.isDebugEnabled()) {
437 logger.debug("page(info = " + info + ") - start");
438 }
439 Criteria criteria = this.createCriteria(info);
440 try {
441 return new Paginator(criteria);
442 } catch (HibernateException he) {
443 logger.debug("page(info = " + info + ") - error", he);
444 throw new DAOException("session.error.paging", he);
445 }
446 }
447
448
449
450
451
452
453
454
455 public Collection page(SearchInfo info, String[] fetch) throws DAOException {
456 if (logger.isDebugEnabled()) {
457 logger.debug("page(info = " + info + ", fetch = " + fetch + ") - start");
458 }
459 try {
460 Criteria criteria = this.createCriteria(info);
461 for (int i = 0; i < fetch.length; i++) {
462 criteria.setFetchMode(fetch[i], FetchMode.SELECT);
463 }
464 return new Paginator(criteria);
465 } catch (HibernateException he) {
466 logger.debug("page(info = " + info + ", fetch = " + fetch + ") - deserialization failed", he);
467 throw new DAOException("session.error.paging", he);
468 }
469 }
470
471
472
473
474
475
476 public abstract Class getMappedClass();
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491 public Serializable convertKey(Serializable key) {
492 if (key != null) {
493 if (key instanceof String) {
494 key = ((String)key).trim();
495 if (((String)key).length() == 0 || key.equals("0")) {
496 return null;
497 } else {
498 return new Long((String)key);
499 }
500 } else if (key instanceof Number) {
501 if (((Number)key).longValue() == 0) {
502 return null;
503 } else {
504 return new Long(((Number)key).toString());
505 }
506 }
507 }
508 return key;
509 }
510
511
512
513
514
515
516
517
518
519
520
521 public Set convertKeys(Collection keys) {
522 if (keys == null) {
523 return Collections.EMPTY_SET;
524 }
525 Set converted = new HashSet(keys.size());
526 Iterator iterator = keys.iterator();
527 while (iterator.hasNext()) {
528 converted.add(this.convertKey((Serializable)iterator.next()));
529 }
530 return converted;
531 }
532
533
534
535
536
537
538
539
540
541 public Criteria createCriteria(SearchInfo info) throws DAOException {
542 if (logger.isDebugEnabled()) {
543 logger.debug("createCriteria(info = " + info + ") - start");
544 }
545 Session session = this.current();
546 Criteria criteria = session.createCriteria(this.getMappedClass());
547 if (info != null) {
548 ClassMetadata metadata = session.getSessionFactory().getClassMetadata(this.getMappedClass());
549 ConverterManager converter = ConverterManager.getDefault();
550 if (info.isUnion()) {
551
552 }
553 Iterator filters = info.getFilters().iterator();
554 while (filters.hasNext()) {
555 Filter filter = (Filter)filters.next();
556 if (logger.isTraceEnabled()) {
557 logger.trace("createCriteria(info = " + info + ") - parsing filter `" + filter + "`");
558 }
559 Class type = metadata.getPropertyType(filter.getProperty()).getReturnedClass();
560 try {
561 switch (filter.getCondition()) {
562 case SearchInfo.EQUALS:
563 for (int i = 0; i < filter.getValues().length; i++) {
564 Object value = converter.convert(type, filter.getValue(i), info.getLocale());
565 criteria.add(Expression.eq(filter.getProperty(), value));
566 }
567 break;
568 case SearchInfo.GREATER:
569 for (int i = 0; i < filter.getValues().length; i++) {
570 Object value = converter.convert(type, filter.getValue(i), info.getLocale());
571 criteria.add(Expression.gt(filter.getProperty(), value));
572 }
573 break;
574 case SearchInfo.GREATER_EQUALS:
575 for (int i = 0; i < filter.getValues().length; i++) {
576 Object value = converter.convert(type, filter.getValue(i), info.getLocale());
577 criteria.add(Expression.ge(filter.getProperty(), value));
578 }
579 break;
580 case SearchInfo.LESSER:
581 for (int i = 0; i < filter.getValues().length; i++) {
582 Object value = converter.convert(type, filter.getValue(i), info.getLocale());
583 criteria.add(Expression.lt(filter.getProperty(), value));
584 }
585 break;
586 case SearchInfo.LESSER_EQUALS:
587 for (int i = 0; i < filter.getValues().length; i++) {
588 Object value = converter.convert(type, filter.getValue(i), info.getLocale());
589 criteria.add(Expression.le(filter.getProperty(), value));
590 }
591 break;
592 case SearchInfo.NOT_EQUALS:
593 for (int i = 0; i < filter.getValues().length; i++) {
594 Object value = converter.convert(type, filter.getValue(i), info.getLocale());
595 criteria.add(Expression.ne(filter.getProperty(), value));
596 }
597 break;
598 case SearchInfo.BETWEEN:
599 Object start = converter.convert(type, filter.getValue(0), info.getLocale());
600 Object stop = converter.convert(type, filter.getValue(1), info.getLocale());
601 criteria.add(Expression.between(filter.getProperty(), start, stop));
602 break;
603 case SearchInfo.IN: {
604 Collection values = new ArrayList();
605 for (int i = 0; i < filter.getValues().length; i++) {
606 Object value = converter.convert(type, filter.getValue(i),
607 info.getLocale());
608 if (value != null) {
609 values.add(value);
610 }
611 }
612 if (!values.isEmpty()) {
613 criteria.add(Expression.in(filter.getProperty(), values));
614 }
615 break;
616 }
617 case SearchInfo.NOT_IN: {
618 Collection values = new ArrayList();
619 for (int i = 0; i < filter.getValues().length; i++) {
620 Object value = converter.convert(type, filter.getValue(i),
621 info.getLocale());
622 if (value != null) {
623 values.add(value);
624 }
625 }
626 if (!values.isEmpty()) {
627 criteria.add(Expression.not(Expression.in(filter.getProperty(), values)));
628 }
629 break;
630 }
631 case SearchInfo.LIKE:
632 for (int i = 0; i < filter.getValues().length; i++) {
633 Object value = converter.convert(type, filter.getValue(i), info.getLocale());
634 criteria.add(Expression.like(filter.getProperty(), value));
635 }
636 break;
637 case SearchInfo.ILIKE:
638 for (int i = 0; i < filter.getValues().length; i++) {
639 Object value = converter.convert(type, filter.getValue(i), info.getLocale());
640 criteria.add(Expression.ilike(filter.getProperty(), value));
641 }
642 break;
643 case SearchInfo.NULL:
644 criteria.add(Expression.isNull(filter.getProperty()));
645 break;
646 case SearchInfo.NOT_NULL:
647 criteria.add(Expression.isNotNull(filter.getProperty()));
648 break;
649 }
650 } catch (ConversionException ce) {
651 logger.warn("Unable to convert filter `" + filter + "`", ce);
652 }
653 }
654 if (info.getOrder() != null && info.getOrder().length() > 0) {
655 if (info.isDescendant()) {
656 criteria.addOrder(Order.desc(info.getOrder()));
657 } else {
658 criteria.addOrder(Order.asc(info.getOrder()));
659 }
660 }
661 }
662 return criteria;
663 }
664
665
666
667
668
669
670 public void begin() throws DAOException {
671 if (logger.isDebugEnabled()) {
672 logger.debug("begin() - start");
673 }
674 if (BusinessObjectFactory.transaction.get() == null) {
675 try {
676 BusinessObjectFactory.transaction.set(this.current().beginTransaction());
677 } catch (HibernateException he) {
678 logger.debug("begin() - error", he);
679 throw new DAOException("session.error.begin", he);
680 }
681 } else {
682 logger.warn("begin() - transaction already started");
683 }
684 }
685
686
687
688
689
690
691 public void commit() throws DAOException {
692 if (logger.isDebugEnabled()) {
693 logger.debug("commit() - start");
694 }
695 Transaction transaction = (Transaction)BusinessObjectFactory.transaction.get();
696 try {
697 transaction.commit();
698 } catch (HibernateException he) {
699 logger.debug("commit() - error", he);
700 throw new DAOException("session.error.commit", he);
701 } catch (NullPointerException npe) {
702 logger.debug("commit() - transaction never started");
703 throw new DAOException("session.error.commit");
704 } finally {
705 BusinessObjectFactory.transaction.set(null);
706 }
707 }
708
709
710
711
712
713
714 public void rollback() throws DAOException {
715 if (logger.isDebugEnabled()) {
716 logger.debug("rollback() - start");
717 }
718 Transaction transaction = (Transaction)BusinessObjectFactory.transaction.get();
719 try {
720 transaction.rollback();
721 } catch (HibernateException he) {
722 logger.debug("rollback() - error", he);
723 throw new DAOException("session.error.rollback", he);
724 } catch (NullPointerException npe) {
725 logger.warn("rollback() - transaction never started", npe);
726 } finally {
727 BusinessObjectFactory.transaction.set(null);
728 }
729 }
730
731
732
733
734
735 public class Paginator extends net.smartlab.web.page.Paginator implements Collection {
736
737
738
739
740 private final Log logger = LogFactory.getLog(Paginator.class);
741
742
743
744
745
746 private Object statement;
747
748
749
750
751
752
753
754
755
756
757
758 public Paginator(Criteria criteria) throws HibernateException {
759 this(criteria, Paginator.UNLIMITED_ITEMS, Paginator.UNLIMITED_PAGES);
760 }
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775 public Paginator(Criteria criteria, int size, int pages) throws HibernateException {
776 super(size, pages);
777 this.statement = criteria;
778 ResultTransformer rt = ((CriteriaImpl)criteria).getResultTransformer();
779 List temp = new ArrayList();
780 Iterator orderings = ((CriteriaImpl)criteria).iterateOrderings();
781 while (orderings.hasNext()) {
782 Order ordering = ((CriteriaImpl.OrderEntry)orderings.next()).getOrder();
783 orderings.remove();
784 temp.add(ordering);
785 }
786 criteria.setProjection(Projections.rowCount());
787 this.setCount(((Integer)criteria.uniqueResult()).intValue());
788 criteria.setProjection(null);
789 if (rt == null) {
790 rt = Criteria.ROOT_ENTITY;
791 }
792 criteria.setResultTransformer(rt);
793 orderings = temp.iterator();
794 while (orderings.hasNext()) {
795 criteria.addOrder((Order)orderings.next());
796 }
797 this.setSize(size);
798 }
799
800
801
802
803
804
805
806
807
808
809
810 public Paginator(Query query) throws DAOException, HibernateException {
811 this(query, Paginator.UNLIMITED_ITEMS, Paginator.UNLIMITED_PAGES);
812 }
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829 public Paginator(Query query, int size, int pages) throws DAOException, HibernateException {
830 super(size, pages);
831 this.statement = query;
832 int queryCount = query.count();
833 this.setCount(queryCount);
834 this.setSize(size);
835 }
836
837
838
839
840 public void setPage(int page) {
841 if (logger.isDebugEnabled()) {
842 logger.debug("setPage(page = " + page + ") - start");
843 }
844 if (statement instanceof Criteria) {
845 ((Criteria)this.statement).setFirstResult((page - 1) * super.getPageSize());
846 } else {
847 ((Query)this.statement).setFirstResult((page - 1) * super.getPageSize());
848 }
849 super.setPage(page);
850 }
851
852
853
854
855
856
857 public void setSize(int size) {
858 if (logger.isDebugEnabled()) {
859 logger.debug("setSize(size = " + size + ") - start");
860 }
861 if (size != UNLIMITED_ITEMS) {
862 super.setPageSize(size);
863 if (statement instanceof Criteria) {
864 ((Criteria)this.statement).setMaxResults(size);
865 } else {
866 ((Query)this.statement).setMaxResults(size);
867 }
868 } else {
869 super.setPageSize(this.getCount());
870 }
871 }
872
873
874
875
876 protected void setArray() {
877 if (logger.isDebugEnabled()) {
878 logger.debug("setArray() - start");
879 }
880 try {
881 Iterator elements = null;
882 if (statement instanceof Criteria) {
883 elements = ((Criteria)this.statement).list().iterator();
884 } else {
885 elements = ((Query)this.statement).list().iterator();
886 }
887 for (int i = 0; i < array.length && elements.hasNext(); i++) {
888 array[i] = elements.next();
889 }
890 } catch (HibernateException he) {
891 logger.error("setArray() - error", he);
892 }
893 }
894
895
896
897
898 public boolean add(Object obj) {
899 throw new UnsupportedOperationException();
900 }
901
902
903
904
905 public boolean addAll(Collection collection) {
906 throw new UnsupportedOperationException();
907 }
908
909
910
911
912 public void clear() {
913 throw new UnsupportedOperationException();
914 }
915
916
917
918
919 public boolean contains(Object item) {
920 if (logger.isDebugEnabled()) {
921 logger.debug("contains(item = " + item + ") - start");
922 }
923 for (int i = 0; i < array.length; i++) {
924 if (array[i].equals(item)) {
925 return true;
926 }
927 }
928 return false;
929 }
930
931
932
933
934 public boolean containsAll(Collection item) {
935 throw new UnsupportedOperationException();
936 }
937
938
939
940
941 public boolean isEmpty() {
942 return super.getCount() == 0;
943 }
944
945
946
947
948 public Iterator iterator() {
949 return this;
950 }
951
952
953
954
955 public boolean remove(Object obj) {
956 throw new UnsupportedOperationException();
957 }
958
959
960
961
962 public boolean removeAll(Collection collection) {
963 throw new UnsupportedOperationException();
964 }
965
966
967
968
969 public boolean retainAll(Collection collection) {
970 throw new UnsupportedOperationException();
971 }
972
973
974
975
976 public int size() {
977 return super.getCount();
978 }
979
980
981
982
983 public Object[] toArray() {
984 return array;
985 }
986
987
988
989
990 public Object[] toArray(Object[] array) {
991 return this.array;
992 }
993 }
994 }