001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.orm.hibernate;
020
021import java.io.Serializable;
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.Iterator;
025import java.util.List;
026import java.util.Map;
027import java.util.Map.Entry;
028
029import lucee.commons.lang.types.RefBoolean;
030import lucee.loader.util.Util;
031import lucee.runtime.Component;
032import lucee.runtime.ComponentScope;
033import lucee.runtime.PageContext;
034import lucee.runtime.db.DataSource;
035import lucee.runtime.db.DatasourceConnection;
036import lucee.runtime.db.SQLItem;
037import lucee.runtime.exp.PageException;
038import lucee.runtime.op.Caster;
039import lucee.runtime.orm.ORMEngine;
040import lucee.runtime.orm.ORMSession;
041import lucee.runtime.orm.ORMTransaction;
042import lucee.runtime.orm.ORMUtil;
043import lucee.runtime.type.Array;
044import lucee.runtime.type.Collection.Key;
045import lucee.runtime.type.KeyImpl;
046import lucee.runtime.type.Struct;
047import lucee.runtime.type.scope.Argument;
048
049import org.hibernate.Criteria;
050import org.hibernate.FlushMode;
051import org.hibernate.NonUniqueResultException;
052import org.hibernate.QueryException;
053import org.hibernate.Session;
054import org.hibernate.SessionFactory;
055import org.hibernate.Transaction;
056import org.hibernate.criterion.Example;
057import org.hibernate.criterion.Order;
058import org.hibernate.criterion.Restrictions;
059import org.hibernate.engine.query.HQLQueryPlan;
060import org.hibernate.engine.query.ParameterMetadata;
061import org.hibernate.engine.query.QueryPlanCache;
062import org.hibernate.metadata.ClassMetadata;
063import org.hibernate.type.Type;
064
065public class HibernateORMSession implements ORMSession {
066
067        private SessionFactoryData data;
068        //private DataSource[] sources;
069        private DatasourceConnection[] connections;
070        //private Map<DataSource,Session> _sessions=new HashMap<DataSource, Session>();
071        
072        //private Map<Key,DataSource> _sources=new HashMap<Key, DataSource>();
073        private Map<Key,Session> _sessions=new HashMap<Key, Session>();
074
075        public HibernateORMSession(PageContext pc,SessionFactoryData data) throws PageException{
076                this.data=data;
077                //this.dc=dc;
078                DataSource[] sources = data.getDataSources();
079                connections=new DatasourceConnection[sources.length];
080                
081                for(int i=0;i<sources.length;i++){
082                        connections[i]=CommonUtil.getDatasourceConnection(pc, sources[i]);
083                        createSession(data.getFactory(KeyImpl.init(sources[i].getName())),connections[i]);
084                }
085        }
086        
087        /*private Session session(){
088                return _session;
089        }*/
090
091        private Session getSession(Key datasSourceName) throws PageException{
092                Session s = _sessions.get(datasSourceName);
093                if(s!=null) return s; 
094                
095                lucee.commons.lang.ExceptionUtil.similarKeyMessage(
096                                _sessions.keySet().toArray(new Key[_sessions.size()])
097                                ,datasSourceName.getString(),"datasource","datasources",true);
098                
099                throw ExceptionUtil.createException(data, null, "there is no Session for the datasource ["+datasSourceName+"]",null);
100        }
101        
102        public SessionFactoryData getSessionFactoryData(){
103                return data;
104        }
105        SessionFactory getSessionFactory(Key datasSourceName) throws PageException{
106                Session s = getSession(datasSourceName);
107                return s.getSessionFactory();
108        }
109        
110        void resetSession(PageContext pc,SessionFactory factory, Key dataSourceName, SessionFactoryData data) throws PageException { 
111                
112                for(int i=0;i<connections.length;i++){
113                        if(dataSourceName.equals(connections[i].getDatasource().getName())) {
114                                createSession(factory, connections[i]);
115                                return;
116                        }
117                }
118                DataSource ds = data.getDataSource(dataSourceName);
119                DatasourceConnection dc = CommonUtil.getDatasourceConnection(pc, ds);
120                try{
121                        createSession(factory, dc);
122                }
123                finally {
124                        CommonUtil.releaseDatasourceConnection(pc, dc);
125                }
126        }
127        
128        void createSession(SessionFactory factory, DatasourceConnection dc) { 
129                Session session;
130                _sessions.put(KeyImpl.init(dc.getDatasource().getName()), session=factory.openSession(dc.getConnection()));
131                session.setFlushMode(FlushMode.MANUAL);
132        }
133
134        @Override
135        public ORMEngine getEngine() {
136                return data.getEngine();
137        }
138        
139        @Override
140        public void flushAll(PageContext pc) throws PageException {
141                // release all connections
142                for(int i=0;i<connections.length;i++) {
143                        flush(pc, connections[i].getDatasource());
144                }
145        }
146        
147        @Override
148        public void flush(PageContext pc) throws PageException {
149                flush(pc, (String)null);// not simply null then it get ambgious for some compiler
150        }
151        
152        @Override
153        public void flush(PageContext pc, String datasource) throws PageException {
154                flush(pc, ORMUtil.getDataSource(pc,datasource));
155        }
156        
157        
158        private void flush(PageContext pc, DataSource datasource) throws PageException {
159                Key dsn = KeyImpl.init(datasource.getName());
160                
161                try {
162                        getSession(dsn).flush();
163                        
164                }
165                catch(Throwable t) {
166                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
167                        throw CommonUtil.toPageException(t);
168                }
169                
170        }
171
172        @Override
173        public void delete(PageContext pc, Object obj) throws PageException {
174                if(CommonUtil.isArray(obj)){
175                        
176                        // convert to a usable structure
177                        Map<Key,List<Component>> cfcs=new HashMap<Key, List<Component>>();
178                        {
179                                Array arr = CommonUtil.toArray(obj);
180                                Iterator<?> it = arr.valueIterator();
181                                Component cfc;
182                                
183                                Key dsn;
184                                List<Component> list;
185                                while(it.hasNext()){
186                                        cfc = HibernateCaster.toComponent(it.next());
187                                        dsn = KeyImpl.init(ORMUtil.getDataSourceName(pc, cfc));
188                                        list = cfcs.get(dsn);
189                                        if(list==null)cfcs.put(dsn, list=new ArrayList<Component>());
190                                        list.add(cfc);
191                                }
192                        }
193                        
194                        
195                        Iterator<Entry<Key, List<Component>>> it = cfcs.entrySet().iterator();
196                        while(it.hasNext()){
197                                Entry<Key, List<Component>> e = it.next();
198                                Transaction trans = getSession(e.getKey()).getTransaction();
199                                if(trans.isActive()) trans.begin();
200                                else trans=null;
201                                
202                                try{
203                                        Iterator<Component> _it = e.getValue().iterator();
204                                        while(_it.hasNext()){
205                                                _delete(pc,_it.next(),e.getKey());
206                                        }
207                                }
208                                catch(Throwable t){
209                                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
210                                        if(trans!=null)trans.rollback();
211                                        throw CommonUtil.toPageException(t);
212                                }
213                                if(trans!=null)trans.commit();
214                        }
215                }
216                else _delete(pc,HibernateCaster.toComponent(obj),null);
217        }
218        
219        public void _delete(PageContext pc, Component cfc, Key dsn) throws PageException {
220                if(dsn==null)dsn = KeyImpl.init(ORMUtil.getDataSourceName(pc, cfc));
221                data.checkExistent(pc,cfc);
222                try{
223                        getSession(dsn).delete(HibernateCaster.getEntityName(cfc), cfc);
224                }
225                catch(Throwable t){
226                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
227                        throw CommonUtil.toPageException(t);
228                }
229        }
230        
231        
232        
233        @Override
234        public void save(PageContext pc, Object obj,boolean forceInsert) throws PageException {
235                Component cfc = HibernateCaster.toComponent(obj);
236                String name = HibernateCaster.getEntityName(cfc);
237                Key dsn = KeyImpl.init(ORMUtil.getDataSourceName(pc, cfc));
238                
239                try {
240                        Session session = getSession(dsn);
241                        if(forceInsert)
242                                session.save(name, cfc);
243                        else
244                                session.saveOrUpdate(name, cfc);
245                }
246                catch(Throwable t){
247                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
248                        throw ExceptionUtil.createException(this,null,t);
249                }
250        }
251        
252        @Override
253        public void reload(PageContext pc,Object obj) throws PageException {
254                Component cfc = HibernateCaster.toComponent(obj);
255                Key dsn = KeyImpl.init(ORMUtil.getDataSourceName(pc, cfc));
256                data.checkExistent(pc,cfc);
257                getSession(dsn).refresh(cfc);
258        }
259        
260
261        @Override
262        public Component create(PageContext pc, String entityName)throws PageException {
263                return data.getEngine().create(pc,this, entityName,true);
264        }
265        
266        @Override
267        public void clear(PageContext pc) throws PageException {
268                clear(pc, null);
269        }
270        
271
272        
273        @Override
274        public void clear(PageContext pc, String datasource) throws PageException {
275                Key dsn = KeyImpl.init(ORMUtil.getDataSource(pc,datasource).getName());
276
277                getSession(dsn).clear();
278                /*Iterator<Session> it = _sessions.values().iterator();
279                while(it.hasNext()){
280                        it.next().clear();
281                }*/
282        }
283        
284        @Override
285        public void evictQueries(PageContext pc) throws PageException {
286                evictQueries(pc, null,null);
287        }
288        
289        @Override
290        public void evictQueries(PageContext pc,String cacheName) throws PageException {
291                evictQueries(pc, cacheName, null);
292        }
293
294        @Override
295        public void evictQueries(PageContext pc,String cacheName, String datasource) throws PageException {
296                Key dsn = KeyImpl.init(ORMUtil.getDataSource(pc,datasource).getName());
297                SessionFactory factory = getSession(dsn).getSessionFactory();
298                
299                if(Util.isEmpty(cacheName))factory.evictQueries();
300                else factory.evictQueries(cacheName);
301                
302                /*Iterator<Session> it = _sessions.values().iterator();
303                while(it.hasNext()){
304                        SessionFactory f = it.next().getSessionFactory();
305                        if(Util.isEmpty(cacheName))f.evictQueries();
306                        else f.evictQueries(cacheName);
307                }*/
308        }
309        
310        @Override
311        public void evictEntity(PageContext pc, String entityName) throws PageException {
312                evictEntity(pc, entityName, null);
313        }
314
315        @Override
316        public void evictEntity(PageContext pc, String entityName, String id) throws PageException {
317                Iterator<Session> it = _sessions.values().iterator();
318                while(it.hasNext()){
319                        SessionFactory f = it.next().getSessionFactory();
320                        if(id==null) f.evictEntity(entityName);
321                        else f.evictEntity(entityName,CommonUtil.toSerializable(id));
322                }
323        }
324        
325        @Override
326        public void evictCollection(PageContext pc, String entityName, String collectionName) throws PageException {
327                evictCollection(pc, entityName, collectionName, null);
328        }
329
330        @Override
331        public void evictCollection(PageContext pc, String entityName, String collectionName, String id) throws PageException {
332                String role=entityName+"."+collectionName;
333                
334                Iterator<Session> it = _sessions.values().iterator();
335                while(it.hasNext()){
336                        SessionFactory f = it.next().getSessionFactory();
337                        if(id==null) f.evictCollection(role);
338                        else f.evictCollection(role,CommonUtil.toSerializable(id));
339                }
340        }
341
342        @Override
343        public Object executeQuery(PageContext pc, String dataSourceName,String hql, Array params, boolean unique,Struct queryOptions) throws PageException {
344                return _executeQuery(pc, dataSourceName,hql, params, unique, queryOptions);
345        }
346
347        @Override
348        public Object executeQuery(PageContext pc,String dataSourceName, String hql, Struct params, boolean unique,Struct queryOptions) throws PageException {
349                return _executeQuery(pc, dataSourceName,hql, params, unique, queryOptions);
350        }
351        
352        private Object _executeQuery(PageContext pc, String dataSourceName,String hql, Object params, boolean unique,Struct queryOptions) throws PageException {
353                Key dsn;
354                if(dataSourceName==null)dsn=KeyImpl.init(ORMUtil.getDefaultDataSource(pc).getName());
355                else dsn=KeyImpl.init(dataSourceName);
356                
357                Session s=getSession(dsn);
358                try{
359                        return __executeQuery(pc,s,dsn, hql, params, unique, queryOptions);
360                }
361                catch(QueryException qe) {
362                        // argument scope is array and struct at the same time, by default it is handled as struct, if this fails try it as array
363                        if(params instanceof Argument) {
364                                try{
365                                        return __executeQuery(pc, s, dsn, hql, CommonUtil.toArray((Argument)params), unique, queryOptions);
366                                }
367                                catch(Throwable t){
368                                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
369                                        t.printStackTrace();
370                                }
371                        }
372                        throw qe;
373                }
374                
375        }
376        
377        private Object __executeQuery(PageContext pc, Session session,Key dsn,String hql, Object params, boolean unique,Struct options) throws PageException {
378                //Session session = getSession(pc,null);
379                hql=hql.trim();
380                org.hibernate.Query query = session.createQuery(hql); 
381                // options
382                if(options!=null){
383                        // maxresults
384                        Object obj=options.get("maxresults",null);
385                        if(obj!=null) {
386                                int max=CommonUtil.toIntValue(obj,-1);
387                                if(max<0) throw ExceptionUtil.createException(this,null,"option [maxresults] has an invalid value ["+obj+"], value should be a number bigger or equal to 0",null);
388                                query.setMaxResults(max);
389                        }
390                        // offset
391                        obj=options.get("offset",null);
392                        if(obj!=null) {
393                                int off=CommonUtil.toIntValue(obj,-1);
394                                if(off<0) throw ExceptionUtil.createException(this,null,"option [offset] has an invalid value ["+obj+"], value should be a number bigger or equal to 0",null);
395                                query.setFirstResult(off);
396                        }
397                        // readonly
398                        obj=options.get("readonly",null);
399                        if(obj!=null) {
400                                Boolean ro=CommonUtil.toBoolean(obj,null);
401                                if(ro==null) throw ExceptionUtil.createException(this,null,"option [readonly] has an invalid value ["+obj+"], value should be a boolean value",null);
402                                query.setReadOnly(ro.booleanValue());
403                        }
404                        // timeout
405                        obj=options.get("timeout",null);
406                        if(obj!=null) {
407                                int to=CommonUtil.toIntValue(obj,-1);
408                                if(to<0) throw ExceptionUtil.createException(this,null,"option [timeout] has an invalid value ["+obj+"], value should be a number bigger or equal to 0",null);
409                                query.setTimeout(to);
410                        }
411        }
412                
413                
414                // params
415                if(params!=null){
416                        QueryPlanCache cache=data.getQueryPlanCache(dsn);
417                        HQLQueryPlan plan = cache.getHQLQueryPlan(hql, false, java.util.Collections.EMPTY_MAP);
418                        ParameterMetadata meta = plan.getParameterMetadata();
419                        Type type;
420                        Object obj;
421                        
422
423                        // struct
424                        if(CommonUtil.isStruct(params)) {
425                                Struct sct=CommonUtil.toStruct(params);
426                                Key[] keys       = CommonUtil.keys(sct);
427                                String name;
428                                // fix case-senstive
429                                Struct names=CommonUtil.createStruct();
430                                if(meta!=null){
431                                        Iterator<String> it = meta.getNamedParameterNames().iterator();
432                                        while(it.hasNext()){
433                                                name=it.next();
434                                                names.setEL(name, name);
435                                        }
436                                }
437                                
438                                RefBoolean isArray=CommonUtil.createRefBoolean();
439                                for(int i=0;i<keys.length;i++){
440                                        obj=sct.get(keys[i],null);
441                                        if(meta!=null){
442                                                name=(String) names.get(keys[i],null);
443                                                if(name==null) continue; // param not needed will be ignored
444                                                type = meta.getNamedParameterExpectedType(name);
445                                                obj=HibernateCaster.toSQL(type, obj,isArray);
446                                                if(isArray.toBooleanValue()) {
447                                                        if(obj instanceof Object[])
448                                                                query.setParameterList(name, (Object[])obj,type);
449                                                        else if(obj instanceof List)
450                                                                query.setParameterList(name, (List)obj,type);
451                                                        else
452                                                                query.setParameterList(name, Caster.toList(obj),type);
453                                                }
454                                                else
455                                                        query.setParameter(name, obj,type);
456                                                
457                                                
458                                        }
459                                        else
460                                                query.setParameter(keys[i].getString(), obj);
461                                }
462                        }
463                        
464                        // array
465                        else if(CommonUtil.isArray(params)){
466                                Array arr=CommonUtil.toArray(params);
467                                Iterator it = arr.valueIterator();
468                                int index=0;
469                                SQLItem item;
470                                RefBoolean isArray=null;
471                                while(it.hasNext()){
472                                        obj=it.next();
473                                        if(obj instanceof SQLItem) {
474                                                item=(SQLItem) obj;
475                                                obj=item.getValue();
476                                                //HibernateCaster.toHibernateType(item.getType(), null); MUST
477                                                //query.setParameter(index, item.getValue(),type);
478                                        }
479                                        if(meta!=null){
480                                                type = meta.getOrdinalParameterExpectedType(index+1);
481                                                obj=HibernateCaster.toSQL(type, obj,isArray);
482                                                // TOOD can the following be done somehow
483                                                //if(isArray.toBooleanValue())
484                                                //      query.setParameterList(index, (Object[])obj,type);
485                                                //else
486                                                        query.setParameter(index, obj,type);
487                                        }
488                                        else
489                                                query.setParameter(index, obj);
490                                        index++;
491                                }
492                                if(meta.getOrdinalParameterCount()>index)
493                                        throw ExceptionUtil.createException(this,null,"parameter array is to small ["+arr.size()+"], need ["+meta.getOrdinalParameterCount()+"] elements",null);
494                        }
495                }
496                
497                
498                
499                // select
500                String lcHQL = hql.toLowerCase();
501                if(lcHQL.startsWith("select") || lcHQL.startsWith("from")){
502                        if(unique){
503                                return uniqueResult(query);
504                        }
505                        
506                        return query.list();
507                }
508            // update
509                return new Double(query.executeUpdate());
510        }
511        
512        
513        
514        private Object uniqueResult(org.hibernate.Query query) throws PageException {
515                try{
516                        return query.uniqueResult();
517                }
518                catch(NonUniqueResultException e){
519                        List list = query.list();
520                        if(list.size()>0) return list.iterator().next();
521                        throw CommonUtil.toPageException(e);
522                }
523                catch(Throwable t){
524                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
525                        throw CommonUtil.toPageException(t);
526                }
527        }
528
529        @Override
530        public lucee.runtime.type.Query toQuery(PageContext pc, Object obj, String name) throws PageException {
531                return HibernateCaster.toQuery(pc,this,obj,name);
532        }
533        @Override
534        public void close(PageContext pc) throws PageException {
535                close(pc, null);
536        }
537        @Override
538        public void close(PageContext pc, String datasource) throws PageException {
539                DataSource ds = ORMUtil.getDataSource(pc,datasource);
540                Key dsn = KeyImpl.init(ds.getName());
541                
542                // close Session
543                getSession(dsn).close();
544                
545                // release connection
546                List<DatasourceConnection> list=new ArrayList<DatasourceConnection>();
547                for(int i=0;i<connections.length;i++){
548                        if(connections[i].getDatasource().equals(ds)) {
549                                CommonUtil.releaseDatasourceConnection(pc, connections[i]);
550                        }
551                        else list.add(connections[i]);
552                }
553                connections=list.toArray(new DatasourceConnection[list.size()]);
554        }
555        
556        @Override
557        public void closeAll(PageContext pc) throws PageException {
558                
559                Iterator<Session> it = _sessions.values().iterator();
560                while(it.hasNext()){
561                        Session s = it.next();
562                        s.close();
563                }
564                
565                // release all connections
566                for(int i=0;i<connections.length;i++){
567                        CommonUtil.releaseDatasourceConnection(pc, connections[i]);
568                }
569                connections=null;
570        }
571        
572        @Override
573        public Component merge(PageContext pc, Object obj) throws PageException {
574                Component cfc = HibernateCaster.toComponent(obj);
575                CFCInfo info = data.checkExistent(pc,cfc);
576                
577                String name=HibernateCaster.getEntityName(cfc);
578                
579                return CommonUtil.toComponent(getSession(KeyImpl.init(info.getDataSource().getName())).merge(name, cfc));
580        }
581        
582
583        @Override
584        public Component load(PageContext pc, String name, Struct filter) throws PageException {
585                return (Component) load(pc, name, filter, null, null, true);
586        }
587
588        @Override
589        public Array loadAsArray(PageContext pc, String name, Struct filter) throws PageException {
590                return loadAsArray(pc, name, filter,null,null);
591        }
592        
593        @Override
594        public Array loadAsArray(PageContext pc, String name, String id, String order) throws PageException{
595                return loadAsArray(pc, name, id);// order is ignored in this case ACF compatibility
596        }
597        
598        @Override
599        public Array loadAsArray(PageContext pc, String name, String id) throws PageException {
600                Array arr=CommonUtil.createArray();
601                Component c = load(pc, name, id);
602                if(c!=null)arr.append(c);
603                return arr;
604        }
605        
606        @Override
607        public Array loadAsArray(PageContext pc, String name, Struct filter, Struct options) throws PageException {
608                return loadAsArray(pc, name, filter,options,null);
609        }
610        
611        @Override
612        public Array loadAsArray(PageContext pc, String name, Struct filter, Struct options, String order) throws PageException {
613                return CommonUtil.toArray(load(pc, name, filter, options, order, false));
614        }
615        
616        @Override
617        public Component load(PageContext pc, String cfcName, String id) throws PageException {
618                //Component cfc = create(pc,cfcName);
619                
620                
621                Component cfc=data.getEngine().create(pc, this,cfcName,false);
622                Key dsn = KeyImpl.init(ORMUtil.getDataSourceName(pc, cfc));
623                Session sess = getSession(dsn);
624                String name = HibernateCaster.getEntityName(cfc);
625                Object obj=null;
626                try{
627                        ClassMetadata metaData = sess.getSessionFactory().getClassMetadata(name);
628                        if(metaData==null) throw ExceptionUtil.createException(this,null,"could not load meta information for entity ["+name+"]",null);
629                        Serializable oId = CommonUtil.toSerializable(
630                                        CommonUtil.castTo(pc, 
631                                                        metaData
632                                                                .getIdentifierType()
633                                                                .getReturnedClass(), 
634                                                        id));
635                        obj=sess.get(name,oId);
636                }
637                catch(Throwable t){
638                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
639                        throw CommonUtil.toPageException(t);
640                }
641                
642                return (Component) obj;
643        }
644        
645        @Override
646        public Component loadByExample(PageContext pc, Object obj) throws PageException {
647                return CommonUtil.toComponent(loadByExample(pc,obj, true));
648        }
649        
650        @Override
651        public Array loadByExampleAsArray(PageContext pc, Object obj) throws PageException {
652                return CommonUtil.toArray(loadByExample(pc,obj, false));
653        }
654        
655        private Object loadByExample(PageContext pc, Object obj,  boolean unique) throws PageException {
656                Component cfc=HibernateCaster.toComponent(obj);
657                Key dsn = KeyImpl.init(ORMUtil.getDataSourceName(pc, cfc));
658                ComponentScope scope = cfc.getComponentScope();
659                String name=HibernateCaster.getEntityName(cfc);
660                Session sess = getSession(dsn);
661                Object rtn=null;
662
663                try{
664                        //trans.begin();
665                        
666                        ClassMetadata metaData = sess.getSessionFactory().getClassMetadata(name);
667                        String idName = metaData.getIdentifierPropertyName();
668                        Type idType = metaData.getIdentifierType();
669                 
670                        Criteria criteria=sess.createCriteria(name);
671                        if(!Util.isEmpty(idName)){
672                                Object idValue = scope.get(CommonUtil.createKey(idName),null);
673                                if(idValue!=null){
674                                        criteria.add(Restrictions.eq(idName, HibernateCaster.toSQL(idType, idValue,null)));
675                                }
676                        }
677                        criteria.add(Example.create(cfc));
678             
679                // execute
680                        
681                        if(!unique){
682                                rtn = criteria.list();
683                        }
684                        else {
685                                //Map map=(Map) criteria.uniqueResult();
686                                rtn= criteria.uniqueResult();
687                        }
688                 }
689                 catch(Throwable t){
690                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
691                        // trans.rollback();
692                        throw CommonUtil.toPageException(t);
693                 }
694                 //trans.commit();
695
696                 return rtn;
697        }
698        
699        
700        private Object load(PageContext pc, String cfcName, Struct filter, Struct options, String order, boolean unique) throws PageException {
701                Component cfc=data.getEngine().create(pc, this,cfcName,false);
702                Key dsn = KeyImpl.init(ORMUtil.getDataSourceName(pc, cfc));
703                Session sess = getSession(dsn);
704
705                String name = HibernateCaster.getEntityName(cfc);
706                ClassMetadata metaData = null;
707                
708                Object rtn;
709                try{
710                        //trans.begin();
711                        
712                        Criteria criteria = sess.createCriteria(name);
713                        
714                        // filter
715                        if(filter!=null && !filter.isEmpty()){
716                                metaData = sess.getSessionFactory().getClassMetadata(name);
717                                Object value;
718                                Entry<Key, Object> entry;
719                                Iterator<Entry<Key, Object>> it = filter.entryIterator();
720                                String colName;
721                                while(it.hasNext()){
722                                        entry = it.next();
723                                        colName=HibernateUtil.validateColumnName(metaData, CommonUtil.toString(entry.getKey()));
724                                        Type type = HibernateUtil.getPropertyType(metaData,colName,null);
725                                        value=entry.getValue();
726                                        if(!(value instanceof Component)) 
727                                                value=HibernateCaster.toSQL(type,value,null);
728                                        
729                                        if(value!=null) criteria.add(Restrictions.eq(colName, value));
730                                        else                    criteria.add(Restrictions.isNull(colName));
731                                }
732                        }
733                        
734                        // options
735                        boolean ignoreCase=false;
736                        if(options!=null && !options.isEmpty()){
737                                // ignorecase
738                                Boolean ignorecase=CommonUtil.toBoolean(options.get("ignorecase",null),null);
739                        if(ignorecase!=null)ignoreCase=ignorecase.booleanValue();
740                        
741                                // offset
742                                int offset=CommonUtil.toIntValue(options.get("offset",null),0);
743                                if(offset>0) criteria.setFirstResult(offset);
744                        
745                                // maxResults
746                                int max=CommonUtil.toIntValue(options.get("maxresults",null),-1);
747                                if(max>-1) criteria.setMaxResults(max);
748                        
749                                // cacheable
750                                Boolean cacheable=CommonUtil.toBoolean(options.get("cacheable",null),null);
751                        if(cacheable!=null)criteria.setCacheable(cacheable.booleanValue());
752                        
753                        // MUST cacheName ?
754                        
755                                // maxResults
756                                int timeout=CommonUtil.toIntValue(options.get("timeout",null),-1);
757                                if(timeout>-1) criteria.setTimeout(timeout);
758                        }
759                        
760                        // order 
761                        if(!Util.isEmpty(order)){
762                                if(metaData==null)metaData = sess.getSessionFactory().getClassMetadata(name);
763                                
764                                String[] arr = CommonUtil.toStringArray(order, ',');
765                                CommonUtil.trimItems(arr);
766                        String[] parts;
767                        String col;
768                        boolean isDesc;
769                        Order _order;
770                        //ColumnInfo ci;
771                        for(int i=0;i<arr.length;i++) {
772                                parts=CommonUtil.toStringArray(arr[i],  " \t\n\b\r");
773                                CommonUtil.trimItems(parts);
774                            col=parts[0];
775                            
776                            col=HibernateUtil.validateColumnName(metaData, col);
777                                        isDesc=false;
778                                        if(parts.length>1){
779                                                if(parts[1].equalsIgnoreCase("desc"))isDesc=true;
780                                                else if(!parts[1].equalsIgnoreCase("asc")){
781                                                        throw ExceptionUtil.createException((ORMSession)null,null,"invalid order direction defintion ["+parts[1]+"]","valid values are [asc, desc]");
782                                                }
783                                                
784                                        }
785                                        _order=isDesc?Order.desc(col):Order.asc(col);
786                            if(ignoreCase)_order.ignoreCase();
787                            
788                            criteria.addOrder(_order);
789                        
790                        }
791                        }
792                        
793                        // execute
794                        if(!unique){
795                                rtn = HibernateCaster.toCFML(criteria.list());
796                        }
797                        else {
798                                rtn= HibernateCaster.toCFML(criteria.uniqueResult());
799                        }
800                        
801                        
802                }
803                catch(Throwable t){
804                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
805                        throw CommonUtil.toPageException(t);
806                }
807                
808                return rtn;
809        }
810        
811        
812        
813
814        @Override
815        public Session getRawSession(String dsn) throws PageException {
816                return getSession(KeyImpl.init(dsn));
817        }
818        
819        @Override
820        public SessionFactory getRawSessionFactory(String dsn) throws PageException {
821                return getSession(KeyImpl.init(dsn)).getSessionFactory();
822        }
823
824        @Override
825        public boolean isValid(DataSource ds) {
826                Session sess = _sessions.get(ds);
827                return sess!=null && sess.isOpen();
828        }
829        
830        @Override
831        public boolean isValid() {
832                if(_sessions.size()==0) return false;
833                Iterator<Session> it = _sessions.values().iterator();
834                while(it.hasNext()){
835                        if(!it.next().isOpen()) return false;
836                }
837                return true;
838        }
839
840        @Override
841        public ORMTransaction getTransaction(String dsn,boolean autoManage) throws PageException {
842                return new HibernateORMTransaction(getSession(KeyImpl.init(dsn)),autoManage);
843        }
844        
845        @Override
846        public String[] getEntityNames() {
847                List<String> names = data.getEntityNames();
848                return names.toArray(new String[names.size()]);
849        }
850
851        @Override
852        public DataSource[] getDataSources() {
853                return data.getDataSources();
854        } 
855}