001    package railo.runtime.orm;
002    
003    import java.io.IOException;
004    import java.util.ArrayList;
005    import java.util.Iterator;
006    
007    import org.w3c.dom.Attr;
008    import org.w3c.dom.Element;
009    import org.w3c.dom.NamedNodeMap;
010    
011    import railo.commons.digest.MD5;
012    import railo.commons.io.res.Resource;
013    import railo.commons.io.res.util.ResourceUtil;
014    import railo.commons.lang.StringUtil;
015    import railo.runtime.PageContext;
016    import railo.runtime.PageSource;
017    import railo.runtime.config.Config;
018    import railo.runtime.config.ConfigWebImpl;
019    import railo.runtime.engine.ThreadLocalPageContext;
020    import railo.runtime.exp.ExpressionException;
021    import railo.runtime.listener.ApplicationContext;
022    import railo.runtime.op.Caster;
023    import railo.runtime.op.Decision;
024    import railo.runtime.type.Array;
025    import railo.runtime.type.ArrayImpl;
026    import railo.runtime.type.Collection;
027    import railo.runtime.type.KeyImpl;
028    import railo.runtime.type.Struct;
029    import railo.runtime.type.StructImpl;
030    import railo.runtime.type.util.KeyConstants;
031    import railo.runtime.type.util.ListUtil;
032    
033    public class ORMConfigurationImpl implements ORMConfiguration {
034            public static final int DBCREATE_NONE=0;
035            public static final int DBCREATE_UPDATE=1;
036            public static final int DBCREATE_DROP_CREATE=2;
037            
038            public static final Collection.Key AUTO_GEN_MAP = KeyImpl.intern("autogenmap");
039            public static final Collection.Key CATALOG = KeyImpl.intern("catalog");
040            public static final Collection.Key IS_DEFAULT_CFC_LOCATION = KeyImpl.intern("isDefaultCfclocation");
041            public static final Collection.Key DB_CREATE = KeyImpl.intern("dbCreate");
042            public static final Collection.Key DIALECT = KeyImpl.intern("dialect");
043            public static final Collection.Key FLUSH_AT_REQUEST_END = KeyImpl.intern("flushAtRequestEnd");
044            public static final Collection.Key LOG_SQL = KeyImpl.intern("logSql");
045            public static final Collection.Key SAVE_MAPPING = KeyImpl.intern("savemapping");
046            public static final Collection.Key SCHEMA = KeyImpl.intern("schema");
047            public static final Collection.Key SECONDARY_CACHE_ENABLED = KeyImpl.intern("secondarycacheenabled");
048            public static final Collection.Key SQL_SCRIPT = KeyImpl.intern("sqlscript");
049            public static final Collection.Key USE_DB_FOR_MAPPING = KeyImpl.intern("useDBForMapping");
050            public static final Collection.Key CACHE_CONFIG = KeyImpl.intern("cacheconfig");
051            public static final Collection.Key CACHE_PROVIDER = KeyImpl.intern("cacheProvider");
052            public static final Collection.Key ORM_CONFIG = KeyImpl.intern("ormConfig");
053            public static final Collection.Key EVENT_HANDLING = KeyImpl.intern("eventHandling");
054            public static final Collection.Key EVENT_HANDLER = KeyImpl.intern("eventHandler");
055            public static final Collection.Key AUTO_MANAGE_SESSION = KeyImpl.intern("autoManageSession");
056            public static final Collection.Key NAMING_STRATEGY = KeyImpl.intern("namingstrategy");
057            
058            
059            private boolean autogenmap=true;
060            private String catalog;
061            private Resource[] cfcLocations;
062            private int dbCreate=DBCREATE_NONE;
063            private String dialect;
064            private Boolean eventHandling=null;
065            private boolean flushAtRequestEnd=true;
066            private boolean logSQL;
067            private boolean saveMapping;
068            private String schema;
069            private boolean secondaryCacheEnabled;
070            private Resource sqlScript;
071            private boolean useDBForMapping=true;
072            private Resource cacheConfig;
073            private String cacheProvider;
074            private Resource ormConfig;
075            private String eventHandler;
076            private String namingStrategy;
077            private boolean isDefaultCfcLocation=true;
078            private boolean skipCFCWithError=true;
079            private boolean autoManageSession=true;
080    
081            private ORMConfigurationImpl(){
082                    autogenmap=true;
083                    dbCreate=DBCREATE_NONE;
084                    flushAtRequestEnd=true;
085                    useDBForMapping=true;           
086            }
087            
088            
089            
090            
091    
092    
093            public static ORMConfiguration load(Config config,ApplicationContext ac, Element el, Resource defaultCFCLocation,ORMConfiguration defaultConfig) {
094                    return _load(config,ac, new _GetElement(el),defaultCFCLocation,defaultConfig);
095            }
096            
097            public static ORMConfiguration load(Config config,ApplicationContext ac,Struct settings, Resource defaultCFCLocation,ORMConfiguration defaultConfig) {
098                    return _load(config,ac, new _GetStruct(settings),defaultCFCLocation,defaultConfig);
099            }
100    
101            private static ORMConfiguration _load(Config config,ApplicationContext ac, _Get settings, Resource defaultCFCLocation,ORMConfiguration dc) {
102                    
103                    if(dc==null)dc=new ORMConfigurationImpl();
104                    ORMConfigurationImpl c = ((ORMConfigurationImpl)dc).duplicate();
105                    c.cfcLocations=defaultCFCLocation==null?new Resource[0]:new Resource[]{defaultCFCLocation};
106                    
107                    // autogenmap
108                    c.autogenmap=Caster.toBooleanValue(settings.get(AUTO_GEN_MAP,dc.autogenmap()),dc.autogenmap());
109                    
110                    // catalog
111                    c.catalog=StringUtil.trim(Caster.toString(settings.get(CATALOG,dc.getCatalog()),dc.getCatalog()),dc.getCatalog());
112                    
113                    // cfclocation
114                    Object obj = settings.get(KeyConstants._cfcLocation,null);
115                    
116                    if(obj!=null){
117                            java.util.List<Resource> list=loadCFCLocation(config,ac,obj,true);
118                            
119                            if(list!=null && list.size()>0){
120                                    c.cfcLocations=list.toArray(new Resource[list.size()]);
121                                    c.isDefaultCfcLocation=false;
122                            }
123                    }
124                    if(c.cfcLocations == null)
125                            c.cfcLocations=defaultCFCLocation==null?new Resource[0]:new Resource[]{defaultCFCLocation};
126                    
127                    // dbcreate
128                    obj = settings.get(DB_CREATE,null);
129                    if(obj!=null){
130                            String str = Caster.toString(obj,"").trim().toLowerCase();
131                            c.dbCreate=dbCreateAsInt(str);
132                    }
133                    
134                    // dialect
135                    c.dialect = StringUtil.trim(Caster.toString(settings.get(DIALECT,dc.getDialect()),dc.getDialect()),dc.getDialect());
136                    
137                    // namingstrategy
138                    c.namingStrategy=Caster.toString(settings.get(NAMING_STRATEGY,dc.namingStrategy()),dc.namingStrategy());
139                    
140                    // eventHandler
141                    c.eventHandler=Caster.toString(settings.get(EVENT_HANDLER,dc.eventHandler()),dc.eventHandler());
142                    
143                    // eventHandling
144                    Boolean b=Caster.toBoolean(settings.get(EVENT_HANDLING,null),null);
145                    if(b==null) {
146                            if(dc.eventHandling()) 
147                                    b=Boolean.TRUE;
148                            else 
149                                    b=!StringUtil.isEmpty(c.eventHandler,true);
150                    }
151                    c.eventHandling=b;
152                    
153                    // flushatrequestend
154                    c.flushAtRequestEnd=Caster.toBooleanValue(settings.get(FLUSH_AT_REQUEST_END,dc.flushAtRequestEnd()),dc.flushAtRequestEnd());
155                    
156                    // logSQL
157                    c.logSQL=Caster.toBooleanValue(settings.get(LOG_SQL,dc.logSQL()),dc.logSQL());
158                    
159    
160                    // autoManageSession
161                    c.autoManageSession=Caster.toBooleanValue(settings.get(AUTO_MANAGE_SESSION,dc.autoManageSession()),dc.autoManageSession());
162                    
163                    // skipCFCWithError
164                    c.skipCFCWithError=Caster.toBooleanValue(settings.get(KeyConstants._skipCFCWithError,dc.skipCFCWithError()),dc.skipCFCWithError());
165                    
166                    // savemapping
167                    c.saveMapping=Caster.toBooleanValue(settings.get(SAVE_MAPPING,dc.saveMapping()),dc.saveMapping());
168                    
169                    // schema
170                    c.schema=StringUtil.trim(Caster.toString(settings.get(SCHEMA,dc.getSchema()),dc.getSchema()),dc.getSchema());
171                    
172                    // secondarycacheenabled
173                    c.secondaryCacheEnabled=Caster.toBooleanValue(settings.get(SECONDARY_CACHE_ENABLED,dc.secondaryCacheEnabled()),dc.secondaryCacheEnabled());
174                    
175                    // sqlscript
176                    obj = settings.get(SQL_SCRIPT,null);
177                    if(!StringUtil.isEmpty(obj)){
178                            try {
179                                    c.sqlScript=toRes(config, obj, true);
180                            } catch (ExpressionException e) {
181                                    //print.e(e);
182                            }
183                    }
184                    
185                    // useDBForMapping
186                    c.useDBForMapping=Caster.toBooleanValue(settings.get(USE_DB_FOR_MAPPING,dc.useDBForMapping()),dc.useDBForMapping());
187                    
188                    // cacheconfig
189                    obj = settings.get(CACHE_CONFIG,null);
190                    if(!StringUtil.isEmpty(obj)){
191                            try {
192                                    c.cacheConfig=toRes(config, obj, true);
193                            } catch (ExpressionException e) {
194                                    //print.printST(e);
195                            }
196                    }
197                    
198                    // cacheprovider
199                    c.cacheProvider=StringUtil.trim(Caster.toString(settings.get(CACHE_PROVIDER,dc.getCacheProvider()),dc.getCacheProvider()),dc.getCacheProvider());
200                    
201                    // ormconfig
202                    obj = settings.get(ORM_CONFIG,null);
203                    if(!StringUtil.isEmpty(obj)){
204                            try {
205                                    c.ormConfig=toRes(config, obj, true);
206                            } catch (ExpressionException e) {
207                                    //print.printST(e);
208                            }
209                    }
210                    
211                    return c;
212            }       
213    
214            public static java.util.List<Resource> loadCFCLocation(Config config, ApplicationContext ac,Object obj, boolean onlyDir) {
215                    
216                    Resource res;
217                    if(!Decision.isArray(obj)){
218                            String list = Caster.toString(obj,null);
219                            if(!StringUtil.isEmpty(list)) {
220                                    obj=ListUtil.listToArray(list, ',');
221                            }
222                    }
223                    
224                    if(Decision.isArray(obj)) {
225                            Array arr=Caster.toArray(obj,null);
226                            java.util.List<Resource> list=new ArrayList<Resource>();
227                            Iterator<Object> it = arr.valueIterator();
228                            while(it.hasNext()){
229                                    try     {
230                                            res=toResourceExisting(config,ac,it.next(),onlyDir);
231                                            if(res!=null) list.add(res);
232                                    }
233                                    catch(Throwable t){}
234                            }
235                            return list;
236                    }
237                    
238                    
239                    return null;
240            }
241    
242    
243    
244    
245    
246    
247            private static Resource toRes(Config config, Object obj, boolean existing) throws ExpressionException {
248                    PageContext pc = ThreadLocalPageContext.get();
249                    if(pc!=null)return Caster.toResource(pc, obj, existing);
250                    return Caster.toResource(config, obj, existing);
251            }
252    
253            private static Resource toResourceExisting(Config config, ApplicationContext ac,Object obj, boolean onlyDir) {
254                    //Resource root = config.getRootDirectory();
255                    String path = Caster.toString(obj,null);
256                    if(StringUtil.isEmpty(path,true)) return null;
257                    path=path.trim();
258                    Resource res;
259                    PageContext pc = ThreadLocalPageContext.get();
260                    
261                    // first check relative to application.cfc
262                    if(pc!=null) {
263                            if(ac==null) ac= pc.getApplicationContext();
264                            
265                            // abs path
266                            if(path.startsWith("/")){
267                                    ConfigWebImpl cwi=(ConfigWebImpl) config;
268                                    PageSource ps = cwi.getPageSourceExisting(
269                                                    pc, ac==null?null:ac.getMappings(), path, false, false, true, false);
270                                    //res=cwi.getPhysicalResourceExistingX(
271                                    //              pc, 
272                                    //              ac==null?null:ac.getMappings(), path, 
273                                    //              false, false, true);
274                                    if(ps!=null){
275                                            res=ps.getResource();
276                                            if(res!=null && (!onlyDir || res.isDirectory())) return res;
277                                    }
278                                    
279                            }
280                            // real path
281                            else {
282                                    Resource src= ac!=null?ac.getSource():null;
283                                    if(src!=null) {
284                                            res=src.getParentResource().getRealResource(path);
285                                            if(res!=null && (!onlyDir || res.isDirectory())) return res;
286                                    }
287                                    // happens when this is called from within the application.cfc (init)
288                                    else {
289                                            res=ResourceUtil.toResourceNotExisting(pc, path);
290                                            if(res!=null && (!onlyDir || res.isDirectory())) return res;
291                                    }
292                            }
293                    }
294                    
295                    
296                    
297                    // then in the webroot
298                    res=config.getRootDirectory().getRealResource(path);
299                    if(res!=null && (!onlyDir || res.isDirectory())) return res;
300                    
301                    // then absolute
302                    res = ResourceUtil.toResourceNotExisting(config, path);
303                    
304                    if(res!=null && (!onlyDir || res.isDirectory())) return res;
305                    return null;
306            }
307    
308    
309    
310    
311    
312    
313            private ORMConfigurationImpl duplicate() {
314                    
315                    ORMConfigurationImpl other = new ORMConfigurationImpl();
316                    
317                    
318                    
319                    other.autogenmap=autogenmap;
320                    other.catalog=catalog;
321                    other.cfcLocations=cfcLocations;
322                    other.isDefaultCfcLocation=isDefaultCfcLocation;
323                    other.dbCreate=dbCreate;
324                    other.dialect=dialect;
325                    other.eventHandler=eventHandler;
326                    other.namingStrategy=namingStrategy;
327                    other.eventHandling=eventHandling;
328                    other.flushAtRequestEnd=flushAtRequestEnd;
329                    other.logSQL=logSQL;
330                    other.saveMapping=saveMapping;
331                    other.schema=schema;
332                    other.secondaryCacheEnabled=secondaryCacheEnabled;
333                    other.sqlScript=sqlScript;
334                    other.useDBForMapping=useDBForMapping;
335                    other.cacheConfig=cacheConfig;
336                    other.cacheProvider=cacheProvider;
337                    other.ormConfig=ormConfig;
338                    other.autoManageSession=autoManageSession;
339                    other.skipCFCWithError=skipCFCWithError;
340                    return other;
341            }
342    
343            public String hash() {
344                    
345                    String data=autogenmap+":"+catalog+":"+isDefaultCfcLocation
346                    +":"+dbCreate+":"+dialect+":"+eventHandling+":"+namingStrategy+":"+eventHandler+":"+flushAtRequestEnd+":"+logSQL+":"+autoManageSession+":"+skipCFCWithError+":"+saveMapping+":"+schema+":"+secondaryCacheEnabled+":"+
347                    useDBForMapping+":"+cacheProvider
348                    
349                    +":"+toStr(cfcLocations)+":"+toStr(sqlScript)+":"+toStr(cacheConfig)+":"+toStr(ormConfig)
350                    ;
351                    
352                    try {
353                            return MD5.getDigestAsString(data);
354                    } catch (IOException e) {
355                            return null;
356                    }
357            }
358    
359    
360    
361    
362    
363            private String toStr(Resource res) {
364                    if(res==null) return "";
365                    return res.getAbsolutePath();
366            }
367            private String toStr(Resource[] reses) {
368                    if(reses==null) return "";
369                    StringBuilder sb=new StringBuilder();
370                    for(int i=0;i<reses.length;i++){
371                            sb.append(toStr(reses[i]));
372                    }
373                    return sb.toString();
374            }
375    
376    
377    
378    
379    
380    
381            /**
382             * @return the autogenmap
383             */
384            public boolean autogenmap() {
385                    return autogenmap;
386            }
387    
388            /**
389             * @return the catalog
390             */
391            public String getCatalog() {
392                    return catalog;
393            }
394    
395            /**
396             * @return the cfcLocation
397             */
398            public Resource[] getCfcLocations() {
399                    return cfcLocations;
400            }
401            public boolean isDefaultCfcLocation() {
402                    return isDefaultCfcLocation;
403            }
404    
405            /**
406             * @return the dbCreate
407             */
408            public int getDbCreate() {
409                    return dbCreate;
410            }
411    
412            /**
413             * @return the dialect
414             */
415            public String getDialect() {
416                    return dialect;
417            }
418    
419            /**
420             * @return the eventHandling
421             */
422            public boolean eventHandling() {
423                    return eventHandling==null?false:eventHandling.booleanValue();
424            }
425    
426            public String eventHandler() {
427                    return eventHandler;
428            }
429    
430            public String namingStrategy() {
431                    return namingStrategy;
432            }
433            
434            
435    
436            /**
437             * @return the flushAtRequestEnd
438             */
439            public boolean flushAtRequestEnd() {
440                    return flushAtRequestEnd;
441            }
442    
443            /**
444             * @return the logSQL
445             */
446            public boolean logSQL() {
447                    return logSQL;
448            }
449    
450            /**
451             * @return the saveMapping
452             */
453            public boolean saveMapping() {
454                    return saveMapping;
455            }
456    
457            /**
458             * @return the schema
459             */
460            public String getSchema() {
461                    return schema;
462            }
463    
464            /**
465             * @return the secondaryCacheEnabled
466             */
467            public boolean secondaryCacheEnabled() {
468                    return secondaryCacheEnabled;
469            }
470    
471            /**
472             * @return the sqlScript
473             */
474            public Resource getSqlScript() {
475                    return sqlScript;
476            }
477    
478            /**
479             * @return the useDBForMapping
480             */
481            public boolean useDBForMapping() {
482                    return useDBForMapping;
483            }
484    
485            /**
486             * @return the cacheConfig
487             */
488            public Resource getCacheConfig() {
489                    return cacheConfig;
490            }
491    
492            /**
493             * @return the cacheProvider
494             */
495            public String getCacheProvider() {
496                    return cacheProvider;
497            }
498    
499            /**
500             * @return the ormConfig
501             */
502            public Resource getOrmConfig() {
503                    return ormConfig;
504            }
505    
506            public boolean skipCFCWithError() {
507                    return skipCFCWithError;
508            }
509            public boolean autoManageSession() {
510                    return autoManageSession;
511            }
512    
513    
514    
515    
516            public Object toStruct() {
517                    
518                    Resource[] locs = getCfcLocations();
519                    Array arrLocs=new ArrayImpl();
520                    if(locs!=null)for(int i=0;i<locs.length;i++){
521                            arrLocs.appendEL(getAbsolutePath(locs[i]));
522                    }
523                    Struct sct=new StructImpl();
524                    sct.setEL(AUTO_GEN_MAP,this.autogenmap());
525                    sct.setEL(CATALOG,StringUtil.emptyIfNull(getCatalog()));
526                    sct.setEL(KeyConstants._cfcLocation,arrLocs);
527                    sct.setEL(IS_DEFAULT_CFC_LOCATION,isDefaultCfcLocation());
528                    sct.setEL(DB_CREATE,dbCreateAsString(getDbCreate()));
529                    sct.setEL(DIALECT,StringUtil.emptyIfNull(getDialect()));
530                    sct.setEL(EVENT_HANDLING,eventHandling());
531                    sct.setEL(EVENT_HANDLER,eventHandler());
532                    sct.setEL(NAMING_STRATEGY,namingStrategy());
533                    sct.setEL(FLUSH_AT_REQUEST_END,flushAtRequestEnd());
534                    sct.setEL(LOG_SQL,logSQL());
535                    sct.setEL(SAVE_MAPPING,saveMapping());
536                    sct.setEL(SCHEMA,StringUtil.emptyIfNull(getSchema()));
537                    sct.setEL(SECONDARY_CACHE_ENABLED,secondaryCacheEnabled());
538                    sct.setEL(SQL_SCRIPT,StringUtil.toStringEmptyIfNull(getSqlScript()));
539                    sct.setEL(USE_DB_FOR_MAPPING,useDBForMapping());
540                    sct.setEL(CACHE_CONFIG,getAbsolutePath(getCacheConfig()));
541                    sct.setEL(CACHE_PROVIDER,StringUtil.emptyIfNull(getCacheProvider()));
542                    sct.setEL(ORM_CONFIG,getAbsolutePath(getOrmConfig()));
543                    
544                    
545                    return sct;
546            }
547    
548    
549            private static String getAbsolutePath(Resource res) {
550                    if(res==null )return "";
551                    return res.getAbsolutePath();
552            }
553    
554    
555    
556    
557    
558    
559            public static int dbCreateAsInt(String dbCreate) {
560                    if(dbCreate==null)dbCreate="";
561                    else dbCreate=dbCreate.trim().toLowerCase();
562                    
563                    if("update".equals(dbCreate))return DBCREATE_UPDATE;
564                    if("dropcreate".equals(dbCreate))return DBCREATE_DROP_CREATE;
565                    if("drop-create".equals(dbCreate))return DBCREATE_DROP_CREATE;
566                    
567                    return DBCREATE_NONE;
568            }
569            
570    
571    
572    
573            public static String dbCreateAsString(int dbCreate) {
574                    
575                    switch(dbCreate){
576                    case DBCREATE_DROP_CREATE: return "dropcreate";
577                    case DBCREATE_UPDATE: return "update";
578                    }
579                    
580                    return "none";
581            }
582    
583    
584    
585    
586    
587    
588            
589    
590            
591    
592    
593    
594    
595            
596            
597            
598    }
599    
600    interface _Get {
601            public Object get(Collection.Key name,Object defaultValue);
602    }
603    
604    class _GetStruct implements _Get {
605            
606            private Struct sct;
607            public _GetStruct(Struct sct){
608                    this.sct=sct;
609            }
610            
611            public Object get(Collection.Key name,Object defaultValue){
612                    return sct.get(name,defaultValue);
613            }
614            
615            public String toString(){
616                    return "_GetStruct:"+sct.toString();
617            }
618    }
619    
620    class _GetElement implements _Get {
621            
622            private Element el;
623            public _GetElement(Element el){
624                    this.el=el;
625            }
626            public Object get(Collection.Key name,Object defaultValue){
627                    String value=_get(name.getString());
628                    if(value==null)value = _get(StringUtil.camelToHypenNotation(name.getString()));
629                    if(value==null)value = _get(name.getLowerString());
630                    if(value==null){
631                            NamedNodeMap map = el.getAttributes();
632                            int len=map.getLength();
633                            Attr attr;
634                            String n;
635                            for(int i=0;i<len;i++){
636                                    attr=(Attr) map.item(i);
637                                    n=attr.getName();
638                                    n=StringUtil.replace(n, "-", "", false).toLowerCase();
639                                    if(n.equalsIgnoreCase(name.getLowerString())) return attr.getValue();
640                            }
641                            
642                    }
643                    
644                    if(value==null) return defaultValue;
645                    return value;
646            }
647            
648            private String _get(String name) {
649                    if(el.hasAttribute(name)) return el.getAttribute(name);
650                    return null;
651            }
652    }
653