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.ComponentPro;
035    import railo.runtime.PageContext;
036    import railo.runtime.config.ConfigWebImpl;
037    import railo.runtime.db.DataSource;
038    import railo.runtime.db.DatasourceConnection;
039    import railo.runtime.db.DatasourceConnectionPool;
040    import railo.runtime.exp.ExpressionException;
041    import railo.runtime.exp.PageException;
042    import railo.runtime.listener.ApplicationContextPro;
043    import railo.runtime.op.Caster;
044    import railo.runtime.orm.ORMConfiguration;
045    import railo.runtime.orm.ORMEngine;
046    import railo.runtime.orm.ORMException;
047    import railo.runtime.orm.ORMSession;
048    import railo.runtime.orm.ORMUtil;
049    import railo.runtime.orm.hibernate.event.AllEventListener;
050    import railo.runtime.orm.hibernate.event.EventListener;
051    import railo.runtime.orm.hibernate.event.InterceptorImpl;
052    import railo.runtime.orm.hibernate.event.PostDeleteEventListenerImpl;
053    import railo.runtime.orm.hibernate.event.PostInsertEventListenerImpl;
054    import railo.runtime.orm.hibernate.event.PostLoadEventListenerImpl;
055    import railo.runtime.orm.hibernate.event.PostUpdateEventListenerImpl;
056    import railo.runtime.orm.hibernate.event.PreDeleteEventListenerImpl;
057    import railo.runtime.orm.hibernate.event.PreInsertEventListenerImpl;
058    import railo.runtime.orm.hibernate.event.PreLoadEventListenerImpl;
059    import railo.runtime.orm.hibernate.event.PreUpdateEventListenerImpl;
060    import railo.runtime.orm.hibernate.tuplizer.AbstractEntityTuplizerImpl;
061    import railo.runtime.orm.naming.CFCNamingStrategy;
062    import railo.runtime.orm.naming.DefaultNamingStrategy;
063    import railo.runtime.orm.naming.NamingStrategy;
064    import railo.runtime.orm.naming.SmartNamingStrategy;
065    import railo.runtime.text.xml.XMLCaster;
066    import railo.runtime.text.xml.XMLUtil;
067    import railo.runtime.type.CastableStruct;
068    import railo.runtime.type.Collection;
069    import railo.runtime.type.KeyImpl;
070    import railo.runtime.type.Struct;
071    import railo.runtime.type.StructImpl;
072    import railo.runtime.type.util.ArrayUtil;
073    import railo.runtime.type.util.ComponentUtil;
074    import railo.runtime.util.ApplicationContext;
075    
076    public class HibernateORMEngine implements ORMEngine {
077    
078    
079            private static final Collection.Key INIT = KeyImpl.intern("init");
080    
081            private Configuration configuration;
082    
083            private SessionFactory _factory;
084            private String datasource;
085            //private Map<String,Long> _cfcids=new HashMap<String, Long>();
086            //private Map<String,String> _cfcs=new HashMap<String, String>();
087            private Map<String,CFCInfo> cfcs=new HashMap<String, CFCInfo>();
088    
089            private Struct tableInfo=new StructImpl();
090    
091            
092            private QueryPlanCache _queryPlanCache;
093    
094            private DataSource ds;
095    
096            private List<ComponentPro> arr;
097    
098            private Object hash;
099    
100            private ORMConfiguration ormConf;
101    
102            private NamingStrategy namingStrategy=DefaultNamingStrategy.INSTANCE;
103    
104            public HibernateORMEngine() {}
105    
106            void checkExistent(PageContext pc,Component cfc) throws ORMException {
107                    if(!cfcs.containsKey(id(HibernateCaster.getEntityName(cfc))))
108                throw new ORMException(this,"there is no mapping definition for component ["+cfc.getAbsName()+"]");
109            }
110    
111            
112            
113            
114            /**
115             * @see railo.runtime.orm.ORMEngine#init(railo.runtime.PageContext)
116             */
117            public void init(PageContext pc) throws PageException{
118                    getSessionFactory(pc,true);
119            }
120                    
121            /**
122             * @see railo.runtime.orm.ORMEngine#getSession(railo.runtime.PageContext)
123             */
124            public ORMSession createSession(PageContext pc) throws PageException {
125                    ApplicationContextPro appContext = ((ApplicationContextPro)pc.getApplicationContext());
126                    String dsn=appContext.getORMDatasource();
127                    
128                    //DatasourceManager manager = pc.getDataSourceManager();
129                    //DatasourceConnection dc=manager.getConnection(pc,dsn, null, null);
130                    DatasourceConnection dc = ((ConfigWebImpl)pc.getConfig()).getDatasourceConnectionPool().getDatasourceConnection(pc,pc.getConfig().getDataSource(dsn),null,null);
131                    try{
132                            
133                            return new HibernateORMSession(this,getSessionFactory(pc),dc);
134                    }
135                    catch(PageException pe){
136                            //manager.releaseConnection(pc, dc);// connection is closed when session ends
137                            throw pe;
138                    }
139            }
140            
141    
142            QueryPlanCache getQueryPlanCache(PageContext pc) throws PageException {
143                    SessionFactory _old = _factory;
144                    SessionFactory _new = getSessionFactory(pc);
145                    
146                    if(_queryPlanCache==null || _old!=_new){
147                            _queryPlanCache=new QueryPlanCache((SessionFactoryImplementor) _new);
148                    }
149                    return _queryPlanCache;
150            }
151    
152            /**
153             * @see railo.runtime.orm.ORMEngine#getSessionFactory(railo.runtime.PageContext)
154             */
155            public SessionFactory getSessionFactory(PageContext pc) throws PageException{
156                    return getSessionFactory(pc,false);
157            }
158            
159            public boolean reload(PageContext pc, boolean force) throws PageException {
160                    if(force) {
161                            if(_factory!=null){
162                                    _factory.close();
163                                    _factory=null;
164                                    configuration=null;
165                            }
166                    }
167                    else {
168                            Object h = hash((ApplicationContextPro)pc.getApplicationContext());
169                            if(this.hash.equals(h))return false;
170                    }
171                    
172                    getSessionFactory(pc,true);
173                    return true;
174            }
175    
176    
177            private synchronized SessionFactory getSessionFactory(PageContext pc,boolean init) throws PageException {
178                    ApplicationContextPro appContext = ((ApplicationContextPro)pc.getApplicationContext());
179                    if(!appContext.isORMEnabled())
180                            throw new ORMException(this,"ORM is not enabled in application.cfc/cfapplication");
181                    
182                    this.hash=hash(appContext);
183                    
184                    // datasource
185                    String dsn=appContext.getORMDatasource();
186                    if(StringUtil.isEmpty(dsn))
187                            throw new ORMException(this,"missing datasource defintion in application.cfc/cfapplication");
188                    if(!dsn.equalsIgnoreCase(datasource)){
189                            configuration=null;
190                            if(_factory!=null) _factory.close();
191                            _factory=null;
192                            datasource=dsn.toLowerCase();
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,pc.getConfig().getDataSource(dsn),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<ComponentPro> 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                                    ComponentPro cfc;
231                                    String name,lcName;
232                                    Map<String,String> names=new HashMap<String,String>();
233                                    Iterator<ComponentPro> 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,pc.getConfig().getDataSource(dsn),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(ApplicationContextPro appContext) {
387                    String hash=appContext.getORMDatasource()+":"+appContext.getORMConfiguration().hash();
388                    //print.ds(hash);
389                    return hash;
390            }
391    
392            public void createMapping(PageContext pc,Component cfc, DatasourceConnection dc, ORMConfiguration ormConf) throws PageException {
393                    ComponentPro cfcp=ComponentUtil.toComponentPro(cfc);
394                    String id=id(HibernateCaster.getEntityName(cfcp));
395                    CFCInfo info=cfcs.get(id);
396                    //Long modified=cfcs.get(id);
397                    String xml;
398                    long cfcCompTime = ComponentUtil.getCompileTime(pc,cfcp.getPageSource());
399                    if(info==null || (ORMUtil.equals(info.getCFC(),cfcp) )) {//&& info.getModified()!=cfcCompTime
400                            StringBuilder sb=new StringBuilder();
401                            
402                            long xmlLastMod = loadMapping(sb,ormConf, cfcp);
403                            Element root;
404                            // create maaping
405                            if(true || xmlLastMod< cfcCompTime) {//MUSTMUST
406                                    configuration=null;
407                                    Document doc=null;
408                                    try {
409                                            doc=XMLUtil.newDocument();
410                                    }catch(Throwable t){t.printStackTrace();}
411                                    
412                                    root=doc.createElement("hibernate-mapping");
413                                    doc.appendChild(root);
414                                    pc.addPageSource(cfcp.getPageSource(), true);
415                                    try{
416                                            HBMCreator.createXMLMapping(pc,dc,cfcp,ormConf,root, this);
417                                    }
418                                    finally{
419                                            pc.removeLastPageSource(true);
420                                    }
421                                    xml=XMLCaster.toString(root.getChildNodes(),true);
422                                    saveMapping(ormConf,cfcp,root);
423                            }
424                            // load
425                            else {
426                                    xml=sb.toString();
427                                    root=Caster.toXML(xml).getOwnerDocument().getDocumentElement();
428                                    /*print.o("1+++++++++++++++++++++++++++++++++++++++++");
429                                    print.o(xml);
430                                    print.o("2+++++++++++++++++++++++++++++++++++++++++");
431                                    print.o(root);
432                                    print.o("3+++++++++++++++++++++++++++++++++++++++++");*/
433                                    
434                            }
435                            cfcs.put(id, new CFCInfo(ComponentUtil.getCompileTime(pc,cfcp.getPageSource()),xml,cfcp));
436                            
437                    }
438                    
439            }
440    
441            private static void saveMapping(ORMConfiguration ormConf, Component cfc, Element hm) throws ExpressionException {
442                    if(ormConf.saveMapping()){
443                            Resource res=ComponentUtil.toComponentPro(cfc).getPageSource().getPhyscalFile();
444                            if(res!=null){
445                                    res=res.getParentResource().getRealResource(res.getName()+".hbm.xml");
446                                    try{
447                                    IOUtil.write(res, 
448                                                    XMLCaster.toString(hm,false,
449                                                                    HibernateSessionFactory.HIBERNATE_3_PUBLIC_ID,
450                                                                    HibernateSessionFactory.HIBERNATE_3_SYSTEM_ID,
451                                                                    HibernateSessionFactory.HIBERNATE_3_ENCODING), HibernateSessionFactory.HIBERNATE_3_ENCODING, false);
452                                    }
453                                    catch(Exception e){} 
454                            }
455                    }
456            }
457            
458            private static long loadMapping(StringBuilder sb,ORMConfiguration ormConf, Component cfc) throws ExpressionException {
459                    
460                    Resource res=ComponentUtil.toComponentPro(cfc).getPageSource().getPhyscalFile();
461                    if(res!=null){
462                            res=res.getParentResource().getRealResource(res.getName()+".hbm.xml");
463                            try{
464                                    sb.append(IOUtil.toString(res, "UTF-8"));
465                                    return res.lastModified();
466                            }
467                            catch(Exception e){} 
468                    }
469                    return 0;
470            }
471    
472            /**
473             * @see railo.runtime.orm.ORMEngine#getMode()
474             */
475            public int getMode() {
476                    //MUST impl
477                    return MODE_LAZY;
478            }
479            
480            public DataSource getDataSource(){
481                    return ds;
482            }
483    
484            /**
485             * @see railo.runtime.orm.ORMEngine#getLabel()
486             */
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            /**
574             * @see railo.runtime.orm.ORMEngine#getConfiguration(railo.runtime.PageContext)
575             */
576            public ORMConfiguration getConfiguration(PageContext pc) {
577                    ApplicationContext ac = pc.getApplicationContext();
578                    if(!(ac instanceof ApplicationContextPro))
579                            return null;
580                    ApplicationContextPro acp=(ApplicationContextPro) ac;
581                    if(!acp.isORMEnabled())
582                            return null;
583                    return  acp.getORMConfiguration();
584            }
585    
586            /**
587             * @param pc
588             * @param session
589             * @param entityName name of the entity to get
590             * @param unique create a unique version that can be manipulated
591             * @param init call the nit method of the cfc or not
592             * @return
593             * @throws PageException
594             */
595            public Component create(PageContext pc, HibernateORMSession session,String entityName, boolean unique) throws PageException {
596                    
597                    // get existing entity
598                    ComponentPro cfc = _create(pc,entityName,unique);
599                    if(cfc!=null)return cfc;
600                    
601                    // reinit ORMEngine
602                    SessionFactory _old = _factory;
603                    SessionFactory _new = getSessionFactory(pc,true);
604                    if(_old!=_new){
605                            session.resetSession(_new);
606                            cfc = _create(pc,entityName,unique);
607                            if(cfc!=null)return cfc;
608                    }
609                    
610                    
611                    
612                    ApplicationContextPro appContext = ((ApplicationContextPro)pc.getApplicationContext());
613                    ORMConfiguration ormConf = appContext.getORMConfiguration();
614                    Resource[] locations = ormConf.getCfcLocations();
615                    
616                    throw new ORMException(
617                                    "No entity (persitent component) with name ["+entityName+"] found, available entities are ["+railo.runtime.type.List.arrayToList(getEntityNames(), ", ")+"] ",
618                                    "component are searched in the following directories ["+toString(locations)+"]");
619                    
620            
621            }
622            
623            
624            private String toString(Resource[] locations) {
625                    if(locations==null) return "";
626                    StringBuilder sb=new StringBuilder();
627                    for(int i=0;i<locations.length;i++){
628                            if(i>0) sb.append(", ");
629                            sb.append(locations[i].getAbsolutePath());
630                    }
631                    return sb.toString();
632            }
633    
634            private ComponentPro _create(PageContext pc, String entityName, boolean unique) throws PageException {
635                    CFCInfo info = cfcs.get(id(entityName));
636                    if(info!=null) {
637                            ComponentPro cfc = info.getCFC();
638                            if(unique){
639                                    cfc=(ComponentPro)cfc.duplicate(false);
640                                    if(cfc.contains(pc,INIT))cfc.call(pc, "init",new Object[]{});
641                            }
642                            return cfc;
643                    }
644                    return null;
645            }
646    
647            public static String id(String id) {
648                    return id.toLowerCase().trim();
649            }
650    
651            public Component getEntityByCFCName(String cfcName,boolean unique) throws PageException {
652                    String name=cfcName;
653                    int pointIndex=cfcName.lastIndexOf('.');
654                    if(pointIndex!=-1) {
655                            name=cfcName.substring(pointIndex+1);
656                    }
657                    else 
658                            cfcName=null;
659                    
660                    
661                    
662                    ComponentPro cfc;
663                    String[] names=null;
664                    // search array (array exist when cfcs is in generation)
665                    
666                    if(arr!=null){
667                            names=new String[arr.size()];
668                            int index=0;
669                            Iterator<ComponentPro> it2 = arr.iterator();
670                            while(it2.hasNext()){
671                                    cfc=it2.next();
672                                    names[index++]=cfc.getName();
673                                    if(isEntity(cfc,cfcName,name)) //if(cfc.equalTo(name))
674                                            return unique?(Component)cfc.duplicate(false):cfc;
675                            }
676                    }
677                    else {
678                            // search cfcs
679                            Iterator<Entry<String, CFCInfo>> it = cfcs.entrySet().iterator();
680                            Entry<String, CFCInfo> entry;
681                            while(it.hasNext()){
682                                    entry=it.next();
683                                    cfc=entry.getValue().getCFC();
684                                    if(isEntity(cfc,cfcName,name)) //if(cfc.instanceOf(name))
685                                            return unique?(Component)cfc.duplicate(false):cfc;
686                                    
687                                    //if(name.equalsIgnoreCase(HibernateCaster.getEntityName(cfc)))
688                                    //      return cfc;
689                            }
690                            names=cfcs.keySet().toArray(new String[cfcs.size()]);
691                    }
692                    
693                    // search by entityname //TODO is this ok?
694                    CFCInfo info = cfcs.get(name.toLowerCase());
695                    if(info!=null) {
696                            cfc=info.getCFC();
697                            return unique?(Component)cfc.duplicate(false):cfc;
698                    }
699                    
700                    throw new ORMException(this,"entity ["+name+"] "+(StringUtil.isEmpty(cfcName)?"":"with cfc name ["+cfcName+"] ")+"does not exist, existing  entities are ["+railo.runtime.type.List.arrayToList(names, ", ")+"]");
701                    
702            }
703            
704    
705            private boolean isEntity(ComponentPro cfc, String cfcName, String name) {
706                    if(!StringUtil.isEmpty(cfcName)) {
707                            if(cfc.equalTo(cfcName)) return true;
708    
709                            if(cfcName.indexOf('.')!=-1) {
710                                    String path=cfcName.replace('.', '/')+".cfc";
711                                    Resource[] locations = ormConf.getCfcLocations();
712                                    for(int i=0;i<locations.length;i++){
713                                            if(locations[i].getRealResource(path).equals(cfc.getPageSource().getFile()))
714                                                    return true;
715                                    }
716                                    return false;
717                            }
718                    }
719                    
720                    if(cfc.equalTo(name)) return true;
721                    return name.equalsIgnoreCase(HibernateCaster.getEntityName(cfc));
722            }
723    
724            public Component getEntityByEntityName(String entityName,boolean unique) throws PageException {
725                    ComponentPro cfc;
726                    
727                    
728                    CFCInfo info = cfcs.get(entityName.toLowerCase());
729                    if(info!=null) {
730                            cfc=info.getCFC();
731                            return unique?(Component)cfc.duplicate(false):cfc;
732                    }
733                    
734                    if(arr!=null){
735                            Iterator<ComponentPro> it2 = arr.iterator();
736                            while(it2.hasNext()){
737                                    cfc=it2.next();
738                                    if(HibernateCaster.getEntityName(cfc).equalsIgnoreCase(entityName))
739                                            return unique?(Component)cfc.duplicate(false):cfc;
740                            }
741                    }
742                    
743                    
744                    
745                    throw new ORMException(this,"entity ["+entityName+"] does not exist");
746                    
747            }
748            
749            
750    
751            public String[] getEntityNames() {
752                    Iterator<Entry<String, CFCInfo>> it = cfcs.entrySet().iterator();
753                    String[] names=new String[cfcs.size()];
754                    int index=0;
755                    while(it.hasNext()){
756                            names[index++]=HibernateCaster.getEntityName(it.next().getValue().getCFC());
757                            //names[index++]=it.next().getValue().getCFC().getName();
758                    }
759                    return names;
760                    
761                    //return cfcs.keySet().toArray(new String[cfcs.size()]);
762            }
763    
764            public String convertTableName(String tableName) {
765                    if(tableName==null) return null;
766                    //print.o("table:"+namingStrategy.getType()+":"+tableName+":"+namingStrategy.convertTableName(tableName));
767                    return namingStrategy.convertTableName(tableName);
768            }
769    
770            public String convertColumnName(String columnName) {
771                    if(columnName==null) return null;
772                    //print.o("column:"+namingStrategy.getType()+":"+columnName+":"+namingStrategy.convertTableName(columnName));
773                    return namingStrategy.convertColumnName(columnName);
774            }
775            
776            
777            
778    }
779    class CFCInfo {
780            private String xml;
781            private long modified;
782            private ComponentPro cfc;
783            
784            public CFCInfo(long modified, String xml, ComponentPro cfc) {
785                    this.modified=modified;
786                    this.xml=xml;
787                    this.cfc=cfc;
788            }
789            /**
790             * @return the cfc
791             */
792            public ComponentPro getCFC() {
793                    return cfc;
794            }
795            /**
796             * @return the xml
797             */
798            public String getXML() {
799                    return xml;
800            }
801            /**
802             * @return the modified
803             */
804            public long getModified() {
805                    return modified;
806            }
807            
808    }
809