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