001    package railo.runtime.orm.hibernate;
002    
003    import java.sql.DatabaseMetaData;
004    import java.sql.ResultSet;
005    import java.sql.SQLException;
006    import java.util.ArrayList;
007    import java.util.HashMap;
008    import java.util.Iterator;
009    import java.util.List;
010    import java.util.Map;
011    import java.util.Map.Entry;
012    
013    import org.hibernate.EntityMode;
014    import org.hibernate.SessionFactory;
015    import org.hibernate.cfg.Configuration;
016    import org.hibernate.engine.SessionFactoryImplementor;
017    import org.hibernate.engine.query.QueryPlanCache;
018    import org.hibernate.event.EventListeners;
019    import org.hibernate.event.PostDeleteEventListener;
020    import org.hibernate.event.PostInsertEventListener;
021    import org.hibernate.event.PostLoadEventListener;
022    import org.hibernate.event.PostUpdateEventListener;
023    import org.hibernate.event.PreDeleteEventListener;
024    import org.hibernate.event.PreLoadEventListener;
025    import org.hibernate.tuple.entity.EntityTuplizerFactory;
026    import org.w3c.dom.Document;
027    import org.w3c.dom.Element;
028    
029    import railo.commons.db.DBUtil;
030    import railo.commons.io.IOUtil;
031    import railo.commons.io.res.Resource;
032    import railo.commons.lang.StringUtil;
033    import railo.runtime.Component;
034    import railo.runtime.PageContext;
035    import railo.runtime.PageContextImpl;
036    import railo.runtime.config.ConfigWebImpl;
037    import railo.runtime.config.Constants;
038    import railo.runtime.db.DataSource;
039    import railo.runtime.db.DataSourcePro;
040    import railo.runtime.db.DatasourceConnection;
041    import railo.runtime.db.DatasourceConnectionPool;
042    import railo.runtime.exp.PageException;
043    import railo.runtime.listener.ApplicationContext;
044    import railo.runtime.listener.ApplicationContextPro;
045    import railo.runtime.op.Caster;
046    import railo.runtime.op.Duplicator;
047    import railo.runtime.orm.ORMConfiguration;
048    import railo.runtime.orm.ORMEngine;
049    import railo.runtime.orm.ORMException;
050    import railo.runtime.orm.ORMSession;
051    import railo.runtime.orm.ORMUtil;
052    import railo.runtime.orm.hibernate.event.AllEventListener;
053    import railo.runtime.orm.hibernate.event.EventListener;
054    import railo.runtime.orm.hibernate.event.InterceptorImpl;
055    import railo.runtime.orm.hibernate.event.PostDeleteEventListenerImpl;
056    import railo.runtime.orm.hibernate.event.PostInsertEventListenerImpl;
057    import railo.runtime.orm.hibernate.event.PostLoadEventListenerImpl;
058    import railo.runtime.orm.hibernate.event.PostUpdateEventListenerImpl;
059    import railo.runtime.orm.hibernate.event.PreDeleteEventListenerImpl;
060    import railo.runtime.orm.hibernate.event.PreInsertEventListenerImpl;
061    import railo.runtime.orm.hibernate.event.PreLoadEventListenerImpl;
062    import railo.runtime.orm.hibernate.event.PreUpdateEventListenerImpl;
063    import railo.runtime.orm.hibernate.tuplizer.AbstractEntityTuplizerImpl;
064    import railo.runtime.orm.naming.CFCNamingStrategy;
065    import railo.runtime.orm.naming.DefaultNamingStrategy;
066    import railo.runtime.orm.naming.NamingStrategy;
067    import railo.runtime.orm.naming.SmartNamingStrategy;
068    import railo.runtime.text.xml.XMLCaster;
069    import railo.runtime.text.xml.XMLUtil;
070    import railo.runtime.type.CastableStruct;
071    import railo.runtime.type.Collection;
072    import railo.runtime.type.KeyImpl;
073    import railo.runtime.type.Struct;
074    import railo.runtime.type.StructImpl;
075    import railo.runtime.type.util.ArrayUtil;
076    import railo.runtime.type.util.ComponentUtil;
077    
078    public class HibernateORMEngine implements ORMEngine {
079    
080    
081            private static final Collection.Key INIT = KeyImpl.intern("init");
082    
083            private Configuration configuration;
084    
085            private SessionFactory _factory;
086            private String _datasource;
087            //private Map<String,Long> _cfcids=new HashMap<String, Long>();
088            //private Map<String,String> _cfcs=new HashMap<String, String>();
089            private Map<String,CFCInfo> cfcs=new HashMap<String, CFCInfo>();
090    
091            private Struct tableInfo=new StructImpl();
092    
093            
094            private QueryPlanCache _queryPlanCache;
095    
096            private DataSource ds;
097    
098            private List<Component> arr;
099    
100            private Object hash;
101    
102            private ORMConfiguration ormConf;
103    
104            private NamingStrategy namingStrategy=DefaultNamingStrategy.INSTANCE;
105    
106            public HibernateORMEngine() {}
107    
108            void checkExistent(PageContext pc,Component cfc) throws ORMException {
109                    if(!cfcs.containsKey(id(HibernateCaster.getEntityName(cfc))))
110                throw new ORMException(this,"there is no mapping definition for component ["+cfc.getAbsName()+"]");
111            }
112    
113            
114            
115            
116            @Override
117            public void init(PageContext pc) throws PageException{
118                    getSessionFactory(pc,true);
119            }
120                    
121            @Override
122            public ORMSession createSession(PageContext pc) throws PageException {
123                    ApplicationContextPro appContext = (ApplicationContextPro) pc.getApplicationContext();
124                    Object o=appContext.getORMDataSource();
125                    
126                    DataSource ds=o instanceof DataSource?(DataSource)o:((PageContextImpl)pc).getDataSource(Caster.toString(o));
127                    
128                    DatasourceConnection dc = ((ConfigWebImpl)pc.getConfig()).getDatasourceConnectionPool().getDatasourceConnection(pc,ds,null,null);
129                    try{
130                            
131                            return new HibernateORMSession(this,getSessionFactory(pc),dc);
132                    }
133                    catch(PageException pe){
134                            //manager.releaseConnection(pc, dc);// connection is closed when session ends
135                            throw pe;
136                    }
137            }
138            
139    
140            QueryPlanCache getQueryPlanCache(PageContext pc) throws PageException {
141                    SessionFactory _old = _factory;
142                    SessionFactory _new = getSessionFactory(pc);
143                    
144                    if(_queryPlanCache==null || _old!=_new){
145                            _queryPlanCache=new QueryPlanCache((SessionFactoryImplementor) _new);
146                    }
147                    return _queryPlanCache;
148            }
149    
150            @Override
151            public SessionFactory getSessionFactory(PageContext pc) throws PageException{
152                    return getSessionFactory(pc,false);
153            }
154            
155            public boolean reload(PageContext pc, boolean force) throws PageException {
156                    if(force) {
157                            if(_factory!=null){
158                                    _factory.close();
159                                    _factory=null;
160                                    configuration=null;
161                            }
162                    }
163                    else {
164                            Object h = hash(pc);
165                            if(this.hash.equals(h))return false;
166                    }
167                    
168                    getSessionFactory(pc,true);
169                    return true;
170            }
171    
172    
173            private synchronized SessionFactory getSessionFactory(PageContext pc,boolean init) throws PageException {
174                    ApplicationContextPro appContext = (ApplicationContextPro) pc.getApplicationContext();
175                    if(!appContext.isORMEnabled())
176                            throw new ORMException(this,"ORM is not enabled in "+Constants.APP_CFC+"/"+Constants.CFAPP_NAME);
177                    
178                    this.hash=hash(pc);
179                    
180                    // datasource
181                    Object o=appContext.getORMDataSource();
182                    if(StringUtil.isEmpty(o))
183                            throw new ORMException(this,"missing datasource defintion in "+Constants.APP_CFC+"/"+Constants.CFAPP_NAME);
184                    
185                    DataSource _ds = o instanceof DataSource?(DataSource)o:((PageContextImpl)pc).getDataSource(Caster.toString(o));
186                    
187                    
188                    if(ds==null || !ds.equals(_ds)){
189                            configuration=null;
190                            if(_factory!=null) _factory.close();
191                            _factory=null;
192                            ds=_ds;
193                    }
194                    
195                    // config
196                    ormConf = appContext.getORMConfiguration();
197                    
198                    //List<Component> arr = null;
199                    arr=null;
200                    if(init){
201                            if(ormConf.autogenmap()){
202                                    arr = HibernateSessionFactory.loadComponents(pc, this, ormConf);
203                                    cfcs.clear();
204                            }
205                            else 
206                                    throw new HibernateException(this,"orm setting autogenmap=false is not supported yet");
207                    }
208                    
209                    // load entities
210                    if(!ArrayUtil.isEmpty(arr)) {
211                            loadNamingStrategy(ormConf);
212                            
213                            
214                            DatasourceConnectionPool pool = ((ConfigWebImpl)pc.getConfig()).getDatasourceConnectionPool();
215                            DatasourceConnection dc = pool.getDatasourceConnection(pc,ds,null,null);
216                            //DataSourceManager manager = pc.getDataSourceManager();
217                            //DatasourceConnection dc=manager.getConnection(pc,dsn, null, null);
218                            //this.ds=dc.getDatasource();
219                            try {
220                                    Iterator<Component> it = arr.iterator();
221                                    while(it.hasNext()){
222                                            createMapping(pc,it.next(),dc,ormConf);
223                                    }
224                            }
225                            finally {
226                                    pool.releaseDatasourceConnection(dc);
227                                    //manager.releaseConnection(pc,dc);
228                            }
229                            if(arr.size()!=cfcs.size()){
230                                    Component cfc;
231                                    String name,lcName;
232                                    Map<String,String> names=new HashMap<String,String>();
233                                    Iterator<Component> it = arr.iterator();
234                                    while(it.hasNext()){
235                                            cfc=it.next();
236                                            name=HibernateCaster.getEntityName(cfc);
237                                            lcName=name.toLowerCase();
238                                            if(names.containsKey(lcName))
239                                                    throw new ORMException(this,"Entity Name ["+name+"] is ambigous, ["+names.get(lcName)+"] and ["+cfc.getPageSource().getDisplayPath()+"] use the same entity name."); 
240                                            names.put(lcName,cfc.getPageSource().getDisplayPath());
241                                    }       
242                            }
243                    }
244                    arr=null;               
245                    if(configuration!=null) return _factory;
246    
247                    //MUST
248                    //cacheconfig
249                    //cacheprovider
250                    //...
251                    
252                    String mappings=HibernateSessionFactory.createMappings(this,cfcs);
253                    
254                    DatasourceConnectionPool pool = ((ConfigWebImpl)pc.getConfig()).getDatasourceConnectionPool();
255                    DatasourceConnection dc = pool.getDatasourceConnection(pc,ds,null,null);
256                    try{
257                            configuration = HibernateSessionFactory.createConfiguration(this,mappings,dc,ormConf);
258                    } 
259                    catch (Exception e) {
260                            throw Caster.toPageException(e);
261                    }
262                    finally {
263                            pool.releaseDatasourceConnection(dc);
264                    }
265                    
266                    addEventListeners(pc, configuration,ormConf,cfcs);
267                    
268                    EntityTuplizerFactory tuplizerFactory = configuration.getEntityTuplizerFactory();
269                    //tuplizerFactory.registerDefaultTuplizerClass(EntityMode.MAP, CFCEntityTuplizer.class);
270                    //tuplizerFactory.registerDefaultTuplizerClass(EntityMode.MAP, MapEntityTuplizer.class);
271                    tuplizerFactory.registerDefaultTuplizerClass(EntityMode.MAP, AbstractEntityTuplizerImpl.class);
272                    tuplizerFactory.registerDefaultTuplizerClass(EntityMode.POJO, AbstractEntityTuplizerImpl.class);
273                    //tuplizerFactory.registerDefaultTuplizerClass(EntityMode.POJO, AbstractEntityTuplizerImpl.class);
274                    
275                    //configuration.setEntityResolver(new CFCEntityResolver());
276                    //configuration.setEntityNotFoundDelegate(new EntityNotFoundDelegate());
277                    
278                    
279                    
280                    return _factory = configuration.buildSessionFactory();
281            }
282            
283            private void loadNamingStrategy(ORMConfiguration ormConf) throws PageException {
284                    String strNamingStrategy=ormConf.namingStrategy();
285                    if(StringUtil.isEmpty(strNamingStrategy,true)) {
286                            namingStrategy=DefaultNamingStrategy.INSTANCE;
287                    }
288                    else {
289                            strNamingStrategy=strNamingStrategy.trim();
290                            if("default".equalsIgnoreCase(strNamingStrategy)) 
291                                    namingStrategy=DefaultNamingStrategy.INSTANCE;
292                            else if("smart".equalsIgnoreCase(strNamingStrategy)) 
293                                    namingStrategy=SmartNamingStrategy.INSTANCE;
294                            else 
295                                    namingStrategy=new CFCNamingStrategy(strNamingStrategy);
296                    }
297            }
298    
299            private static void addEventListeners(PageContext pc, Configuration config,ORMConfiguration ormConfig, Map<String, CFCInfo> cfcs) throws PageException {
300                    if(!ormConfig.eventHandling()) return;
301                    String eventHandler = ormConfig.eventHandler();
302                    AllEventListener listener=null;
303                    if(!StringUtil.isEmpty(eventHandler,true)){
304                            //try {
305                                    Component c = pc.loadComponent(eventHandler.trim());
306                                    
307                                    listener = new AllEventListener(c);
308                            //config.setInterceptor(listener);
309                            //}catch (PageException e) {e.printStackTrace();}
310                    }
311                    config.setInterceptor(new InterceptorImpl(listener));
312            EventListeners listeners = config.getEventListeners();
313            
314            // post delete
315                    List<EventListener> 
316                    list=merge(listener,cfcs,EventListener.POST_DELETE);
317                    listeners.setPostDeleteEventListeners(list.toArray(new PostDeleteEventListener[list.size()]));
318                    
319            // post insert
320                    list=merge(listener,cfcs,EventListener.POST_INSERT);
321                    listeners.setPostInsertEventListeners(list.toArray(new PostInsertEventListener[list.size()]));
322                    
323                    // post update
324                    list=merge(listener,cfcs,EventListener.POST_UPDATE);
325                    listeners.setPostUpdateEventListeners(list.toArray(new PostUpdateEventListener[list.size()]));
326                    
327                    // post load
328                    list=merge(listener,cfcs,EventListener.POST_LOAD);
329                    listeners.setPostLoadEventListeners(list.toArray(new PostLoadEventListener[list.size()]));
330                    
331                    // pre delete
332                    list=merge(listener,cfcs,EventListener.PRE_DELETE);
333                    listeners.setPreDeleteEventListeners(list.toArray(new PreDeleteEventListener[list.size()]));
334                    
335                    // pre insert
336                    //list=merge(listener,cfcs,EventListener.PRE_INSERT);
337                    //listeners.setPreInsertEventListeners(list.toArray(new PreInsertEventListener[list.size()]));
338                    
339                    // pre load
340                    list=merge(listener,cfcs,EventListener.PRE_LOAD);
341                    listeners.setPreLoadEventListeners(list.toArray(new PreLoadEventListener[list.size()]));
342                    
343                    // pre update
344                    //list=merge(listener,cfcs,EventListener.PRE_UPDATE);
345                    //listeners.setPreUpdateEventListeners(list.toArray(new PreUpdateEventListener[list.size()]));
346            }
347    
348            private static List<EventListener> merge(EventListener listener, Map<String, CFCInfo> cfcs, Collection.Key eventType) {
349                    List<EventListener> list=new ArrayList<EventListener>();
350                            
351                    
352                    Iterator<Entry<String, CFCInfo>> it = cfcs.entrySet().iterator();
353                    Entry<String, CFCInfo> entry;
354                    Component cfc;
355                    while(it.hasNext()){
356                            entry = it.next();
357                            cfc = entry.getValue().getCFC();
358                            if(EventListener.hasEventType(cfc,eventType)) {
359                                    if(EventListener.POST_DELETE.equals(eventType))
360                                            list.add(new PostDeleteEventListenerImpl(cfc));
361                                    if(EventListener.POST_INSERT.equals(eventType))
362                                            list.add(new PostInsertEventListenerImpl(cfc));
363                                    if(EventListener.POST_LOAD.equals(eventType))
364                                            list.add(new PostLoadEventListenerImpl(cfc));
365                                    if(EventListener.POST_UPDATE.equals(eventType))
366                                            list.add(new PostUpdateEventListenerImpl(cfc));
367                                    
368                                    if(EventListener.PRE_DELETE.equals(eventType))
369                                            list.add(new PreDeleteEventListenerImpl(cfc));
370                                    if(EventListener.PRE_INSERT.equals(eventType))
371                                            list.add(new PreInsertEventListenerImpl(cfc));
372                                    if(EventListener.PRE_LOAD.equals(eventType))
373                                            list.add(new PreLoadEventListenerImpl(cfc));
374                                    if(EventListener.PRE_UPDATE.equals(eventType))
375                                            list.add(new PreUpdateEventListenerImpl(cfc));
376                            }
377                    }
378                    
379                    // general listener
380                    if(listener!=null && EventListener.hasEventType(listener.getCFC(),eventType))
381                            list.add(listener);
382                    
383                    return list;
384            }
385    
386            private Object hash(PageContext pc) throws PageException {
387                    ApplicationContextPro appContext=(ApplicationContextPro) pc.getApplicationContext();
388                    Object o=appContext.getORMDataSource();
389                    DataSource ds;
390                    if(o instanceof DataSource) ds=(DataSource) o;
391                    else ds=((PageContextImpl)pc).getDataSource(Caster.toString(o));
392                    if(ds instanceof DataSourcePro)
393                            return hash=((DataSourcePro)ds).id()+":"+appContext.getORMConfiguration().hash();
394                    
395                    return ds.getClazz()+":"+ds.getDsnTranslated()+":"+appContext.getORMConfiguration().hash();
396            }
397    
398            public void createMapping(PageContext pc,Component cfc, DatasourceConnection dc, ORMConfiguration ormConf) throws PageException {
399                    String id=id(HibernateCaster.getEntityName(cfc));
400                    CFCInfo info=cfcs.get(id);
401                    //Long modified=cfcs.get(id);
402                    String xml;
403                    long cfcCompTime = ComponentUtil.getCompileTime(pc,cfc.getPageSource());
404                    if(info==null || (ORMUtil.equals(info.getCFC(),cfc) ))  {//&& info.getModified()!=cfcCompTime
405                            StringBuilder sb=new StringBuilder();
406                            
407                            long xmlLastMod = loadMapping(sb,ormConf, cfc);
408                            Element root;
409                            // create maaping
410                            if(true || xmlLastMod< cfcCompTime) {//MUSTMUST
411                                    configuration=null;
412                                    Document doc=null;
413                                    try {
414                                            doc=XMLUtil.newDocument();
415                                    }catch(Throwable t){t.printStackTrace();}
416                                    
417                                    root=doc.createElement("hibernate-mapping");
418                                    doc.appendChild(root);
419                                    pc.addPageSource(cfc.getPageSource(), true);
420                                    try{
421                                            HBMCreator.createXMLMapping(pc,dc,cfc,ormConf,root, this);
422                                    }
423                                    finally{
424                                            pc.removeLastPageSource(true);
425                                    }
426                                    xml=XMLCaster.toString(root.getChildNodes(),true,true);
427                                    saveMapping(ormConf,cfc,root);
428                            }
429                            // load
430                            else {
431                                    xml=sb.toString();
432                                    root=Caster.toXML(xml).getOwnerDocument().getDocumentElement();
433                                    /*print.o("1+++++++++++++++++++++++++++++++++++++++++");
434                                    print.o(xml);
435                                    print.o("2+++++++++++++++++++++++++++++++++++++++++");
436                                    print.o(root);
437                                    print.o("3+++++++++++++++++++++++++++++++++++++++++");*/
438                                    
439                            }
440                            cfcs.put(id, new CFCInfo(ComponentUtil.getCompileTime(pc,cfc.getPageSource()),xml,cfc));
441                    }
442                    
443            }
444    
445            private static void saveMapping(ORMConfiguration ormConf, Component cfc, Element hm) {
446                    if(ormConf.saveMapping()){
447                            Resource res=cfc.getPageSource().getResource();
448                            if(res!=null){
449                                    res=res.getParentResource().getRealResource(res.getName()+".hbm.xml");
450                                    try{
451                                    IOUtil.write(res, 
452                                                    XMLCaster.toString(hm,false,true,
453                                                                    HibernateSessionFactory.HIBERNATE_3_PUBLIC_ID,
454                                                                    HibernateSessionFactory.HIBERNATE_3_SYSTEM_ID,
455                                                                    HibernateSessionFactory.HIBERNATE_3_ENCODING), HibernateSessionFactory.HIBERNATE_3_ENCODING, false);
456                                    }
457                                    catch(Exception e){} 
458                            }
459                    }
460            }
461            
462            private static long loadMapping(StringBuilder sb,ORMConfiguration ormConf, Component cfc) {
463                    
464                    Resource res=cfc.getPageSource().getResource();
465                    if(res!=null){
466                            res=res.getParentResource().getRealResource(res.getName()+".hbm.xml");
467                            try{
468                                    sb.append(IOUtil.toString(res, "UTF-8"));
469                                    return res.lastModified();
470                            }
471                            catch(Exception e){} 
472                    }
473                    return 0;
474            }
475    
476            @Override
477            public int getMode() {
478                    //MUST impl
479                    return MODE_LAZY;
480            }
481            
482            public DataSource getDataSource(){
483                    return ds;
484            }
485    
486            @Override
487            public String getLabel() {
488                    return "Hibernate";
489            }
490    
491            public Struct getTableInfo(DatasourceConnection dc, String tableName,ORMEngine engine) throws PageException {
492                    Collection.Key keyTableName=KeyImpl.init(tableName);
493                    Struct columnsInfo = (Struct) tableInfo.get(keyTableName,null);
494                    if(columnsInfo!=null) return columnsInfo;
495                    
496                    columnsInfo = checkTable(dc,tableName,engine);
497            tableInfo.setEL(keyTableName,columnsInfo);
498            return columnsInfo;
499            }
500            
501            private static Struct checkTable(DatasourceConnection dc, String tableName, ORMEngine engine) throws PageException {
502                    String dbName=dc.getDatasource().getDatabase();
503                    try {
504                            
505                            DatabaseMetaData md = dc.getConnection().getMetaData();
506                            Struct rows=checkTableFill(md,dbName,tableName);
507                            if(rows.size()==0)      {
508                                    String tableName2 = checkTableValidate(md,dbName,tableName);
509                                    if(tableName2!=null)rows=checkTableFill(md,dbName,tableName2);
510                            }
511                            
512                            if(rows.size()==0)      {
513                                    //ORMUtil.printError("there is no table with name  ["+tableName+"] defined", engine);
514                                    return null;
515                            }
516                            return rows;
517                    } catch (SQLException e) {
518                            throw Caster.toPageException(e);
519                    }
520            }
521            
522    
523    
524            private static Struct checkTableFill(DatabaseMetaData md, String dbName, String tableName) throws SQLException, PageException {
525                    Struct rows=new CastableStruct(tableName,Struct.TYPE_LINKED);
526                    ResultSet columns = md.getColumns(dbName, null, tableName, null);
527                    //print.o(new QueryImpl(columns,""));
528                    try{
529                            String name;
530                            Object nullable;
531                            while(columns.next()) {
532                                    name=columns.getString("COLUMN_NAME");
533                                    
534                                    nullable=columns.getObject("IS_NULLABLE");
535                                    rows.setEL(KeyImpl.init(name),new ColumnInfo(
536                                                    name,
537                                                    columns.getInt("DATA_TYPE"),
538                                                    columns.getString("TYPE_NAME"),
539                                                    columns.getInt("COLUMN_SIZE"),
540                                                    Caster.toBooleanValue(nullable) 
541                                    ));
542                            }
543                    }
544                    finally {
545                            DBUtil.closeEL(columns);
546                    }// Table susid defined for cfc susid does not exist.
547                    
548                    return rows;
549            }
550    
551            private static String checkTableValidate(DatabaseMetaData md, String dbName,String tableName) {
552    
553                    ResultSet tables=null;
554            try{
555                    tables = md.getTables(dbName, null, null, null);
556                            String name;
557                            while(tables.next()) {
558                                    name=tables.getString("TABLE_NAME");
559                                    if(name.equalsIgnoreCase(tableName) && StringUtil.indexOfIgnoreCase(tables.getString("TABLE_TYPE"), "SYSTEM")==-1)
560                                    return name;    
561                            }
562                    }
563            catch(Throwable t){}
564                    finally {
565                            DBUtil.closeEL(tables);
566                    }
567            return null;
568            
569            
570                    
571            }
572    
573            @Override
574            public ORMConfiguration getConfiguration(PageContext pc) {
575                    ApplicationContext ac = pc.getApplicationContext();
576                    if(!ac.isORMEnabled())
577                            return null;
578                    return  ac.getORMConfiguration();
579            }
580    
581            /**
582             * @param pc
583             * @param session
584             * @param entityName name of the entity to get
585             * @param unique create a unique version that can be manipulated
586             * @param init call the nit method of the cfc or not
587             * @return
588             * @throws PageException
589             */
590            public Component create(PageContext pc, HibernateORMSession session,String entityName, boolean unique) throws PageException {
591                    
592                    // get existing entity
593                    Component cfc = _create(pc,entityName,unique);
594                    if(cfc!=null)return cfc;
595                    
596                    // reinit ORMEngine
597                    SessionFactory _old = _factory;
598                    SessionFactory _new = getSessionFactory(pc,true);
599                    if(_old!=_new){
600                            session.resetSession(_new);
601                            cfc = _create(pc,entityName,unique);
602                            if(cfc!=null)return cfc;
603                    }
604                    
605                    
606                    
607                    ORMConfiguration ormConf = pc.getApplicationContext().getORMConfiguration();
608                    Resource[] locations = ormConf.getCfcLocations();
609                    
610                    throw new ORMException(
611                                    "No entity (persitent component) with name ["+entityName+"] found, available entities are ["+railo.runtime.type.util.ListUtil.arrayToList(getEntityNames(), ", ")+"] ",
612                                    "component are searched in the following directories ["+toString(locations)+"]");
613                    
614            }
615            
616            
617            private String toString(Resource[] locations) {
618                    if(locations==null) return "";
619                    StringBuilder sb=new StringBuilder();
620                    for(int i=0;i<locations.length;i++){
621                            if(i>0) sb.append(", ");
622                            sb.append(locations[i].getAbsolutePath());
623                    }
624                    return sb.toString();
625            }
626    
627            private Component _create(PageContext pc, String entityName, boolean unique) throws PageException {
628                    CFCInfo info = cfcs.get(id(entityName));
629                    if(info!=null) {
630                            Component cfc = info.getCFC();
631                            if(unique){
632                                    cfc=(Component)Duplicator.duplicate(cfc,false);
633                                    if(cfc.contains(pc,INIT))cfc.call(pc, "init",new Object[]{});
634                            }
635                            return cfc;
636                    }
637                    return null;
638            }
639    
640            public static String id(String id) {
641                    return id.toLowerCase().trim();
642            }
643    
644            public Component getEntityByCFCName(String cfcName,boolean unique) throws PageException {
645                    String name=cfcName;
646                    int pointIndex=cfcName.lastIndexOf('.');
647                    if(pointIndex!=-1) {
648                            name=cfcName.substring(pointIndex+1);
649                    }
650                    else 
651                            cfcName=null;
652                    
653                    
654                    
655                    Component cfc;
656                    String[] names=null;
657                    // search array (array exist when cfcs is in generation)
658                    
659                    if(arr!=null){
660                            names=new String[arr.size()];
661                            int index=0;
662                            Iterator<Component> it2 = arr.iterator();
663                            while(it2.hasNext()){
664                                    cfc=it2.next();
665                                    names[index++]=cfc.getName();
666                                    if(isEntity(cfc,cfcName,name)) //if(cfc.equalTo(name))
667                                            return unique?(Component)Duplicator.duplicate(cfc,false):cfc;
668                            }
669                    }
670                    else {
671                            // search cfcs
672                            Iterator<Entry<String, CFCInfo>> it = cfcs.entrySet().iterator();
673                            Entry<String, CFCInfo> entry;
674                            while(it.hasNext()){
675                                    entry=it.next();
676                                    cfc=entry.getValue().getCFC();
677                                    if(isEntity(cfc,cfcName,name)) //if(cfc.instanceOf(name))
678                                            return unique?(Component)Duplicator.duplicate(cfc,false):cfc;
679                                    
680                                    //if(name.equalsIgnoreCase(HibernateCaster.getEntityName(cfc)))
681                                    //      return cfc;
682                            }
683                            names=cfcs.keySet().toArray(new String[cfcs.size()]);
684                    }
685                    
686                    // search by entityname //TODO is this ok?
687                    CFCInfo info = cfcs.get(name.toLowerCase());
688                    if(info!=null) {
689                            cfc=info.getCFC();
690                            return unique?(Component)Duplicator.duplicate(cfc,false):cfc;
691                    }
692                    
693                    throw new ORMException(this,"entity ["+name+"] "+(StringUtil.isEmpty(cfcName)?"":"with cfc name ["+cfcName+"] ")+"does not exist, existing  entities are ["+railo.runtime.type.util.ListUtil.arrayToList(names, ", ")+"]");
694                    
695            }
696            
697    
698            private boolean isEntity(Component cfc, String cfcName, String name) {
699                    if(!StringUtil.isEmpty(cfcName)) {
700                            if(cfc.equalTo(cfcName)) return true;
701    
702                            if(cfcName.indexOf('.')!=-1) {
703                                    String path=cfcName.replace('.', '/')+".cfc";
704                                    Resource[] locations = ormConf.getCfcLocations();
705                                    for(int i=0;i<locations.length;i++){
706                                            if(locations[i].getRealResource(path).equals(cfc.getPageSource().getResource()))
707                                                    return true;
708                                    }
709                                    return false;
710                            }
711                    }
712                    
713                    if(cfc.equalTo(name)) return true;
714                    return name.equalsIgnoreCase(HibernateCaster.getEntityName(cfc));
715            }
716    
717            public Component getEntityByEntityName(String entityName,boolean unique) throws PageException {
718                    Component cfc;
719                    
720                    
721                    CFCInfo info = cfcs.get(entityName.toLowerCase());
722                    if(info!=null) {
723                            cfc=info.getCFC();
724                            return unique?(Component)Duplicator.duplicate(cfc,false):cfc;
725                    }
726                    
727                    if(arr!=null){
728                            Iterator<Component> it2 = arr.iterator();
729                            while(it2.hasNext()){
730                                    cfc=it2.next();
731                                    if(HibernateCaster.getEntityName(cfc).equalsIgnoreCase(entityName))
732                                            return unique?(Component)Duplicator.duplicate(cfc,false):cfc;
733                            }
734                    }
735                    
736                    
737                    
738                    throw new ORMException(this,"entity ["+entityName+"] does not exist");
739                    
740            }
741            
742            
743    
744            public String[] getEntityNames() {
745                    Iterator<Entry<String, CFCInfo>> it = cfcs.entrySet().iterator();
746                    String[] names=new String[cfcs.size()];
747                    int index=0;
748                    while(it.hasNext()){
749                            names[index++]=HibernateCaster.getEntityName(it.next().getValue().getCFC());
750                            //names[index++]=it.next().getValue().getCFC().getName();
751                    }
752                    return names;
753                    
754                    //return cfcs.keySet().toArray(new String[cfcs.size()]);
755            }
756    
757            public String convertTableName(String tableName) {
758                    if(tableName==null) return null;
759                    //print.o("table:"+namingStrategy.getType()+":"+tableName+":"+namingStrategy.convertTableName(tableName));
760                    return namingStrategy.convertTableName(tableName);
761            }
762    
763            public String convertColumnName(String columnName) {
764                    if(columnName==null) return null;
765                    //print.o("column:"+namingStrategy.getType()+":"+columnName+":"+namingStrategy.convertTableName(columnName));
766                    return namingStrategy.convertColumnName(columnName);
767            }
768            
769            
770            
771    }
772    class CFCInfo {
773            private String xml;
774            private long modified;
775            private Component cfc;
776            
777            public CFCInfo(long modified, String xml, Component cfc) {
778                    this.modified=modified;
779                    this.xml=xml;
780                    this.cfc=cfc;
781            }
782            /**
783             * @return the cfc
784             */
785            public Component getCFC() {
786                    return cfc;
787            }
788            /**
789             * @return the xml
790             */
791            public String getXML() {
792                    return xml;
793            }
794            /**
795             * @return the modified
796             */
797            public long getModified() {
798                    return modified;
799            }
800            
801    }
802