001    package railo.runtime.orm.hibernate;
002    
003    
004    import java.util.ArrayList;
005    import java.util.HashMap;
006    import java.util.Iterator;
007    import java.util.Map;
008    import java.util.Map.Entry;
009    
010    import org.w3c.dom.Document;
011    import org.w3c.dom.Element;
012    import org.w3c.dom.NodeList;
013    
014    import railo.commons.lang.StringUtil;
015    import railo.runtime.Component;
016    import railo.runtime.ComponentPro;
017    import railo.runtime.PageContext;
018    import railo.runtime.component.Property;
019    import railo.runtime.db.DatasourceConnection;
020    import railo.runtime.exp.PageException;
021    import railo.runtime.op.Caster;
022    import railo.runtime.op.Decision;
023    import railo.runtime.orm.ORMConfiguration;
024    import railo.runtime.orm.ORMEngine;
025    import railo.runtime.orm.ORMException;
026    import railo.runtime.text.xml.XMLUtil;
027    import railo.runtime.type.Collection;
028    import railo.runtime.type.Collection.Key;
029    import railo.runtime.type.KeyImpl;
030    import railo.runtime.type.List;
031    import railo.runtime.type.Struct;
032    import railo.runtime.type.StructImpl;
033    import railo.runtime.type.dt.DateTimeImpl;
034    import railo.runtime.type.util.ArrayUtil;
035    import railo.runtime.type.util.ComponentUtil;
036    
037    public class HBMCreator {
038            
039            
040            private static final Collection.Key PROPERTY = KeyImpl.intern("property");
041            private static final Collection.Key FIELD_TYPE = KeyImpl.intern("fieldType");
042            private static final Collection.Key LINK_TABLE = KeyImpl.intern("linktable");
043            private static final Collection.Key CFC = KeyImpl.intern("cfc");
044            private static final Collection.Key GENERATOR = KeyImpl.intern("generator");
045            private static final Collection.Key PARAMS = KeyImpl.intern("params");
046            private static final Collection.Key SEQUENCE = KeyImpl.intern("sequence");
047            private static final Collection.Key UNIQUE_KEY_NAME = KeyImpl.intern("uniqueKeyName");
048            private static final Collection.Key GENERATED = KeyImpl.intern("generated");
049            
050            public static void createXMLMapping(PageContext pc,DatasourceConnection dc, Component cfc,ORMConfiguration ormConf,Element hibernateMapping,HibernateORMEngine engine) throws PageException {
051                    
052                    // MUST Support for embeded objects 
053                    ComponentPro cfci = ComponentUtil.toComponentPro(cfc);
054                    Struct meta = cfci.getMetaData(pc);
055                    
056                    String extend = cfc.getExtends();
057                    boolean isClass=StringUtil.isEmpty(extend);
058                    
059                    Property[] _props=getProperties(pc,engine,cfci,dc,ormConf,meta,isClass);
060                    
061                    
062                    
063                    Map<String, PropertyCollection> joins=new HashMap<String, PropertyCollection>();
064                    PropertyCollection propColl = splitJoins(engine,cfc,joins, _props);
065                    
066                    
067                    
068                    // create class element and attach
069                    Document doc = XMLUtil.getDocument(hibernateMapping);
070                    
071                    StringBuilder comment=new StringBuilder();
072                    comment.append("\nsource:").append(cfci.getPageSource().getDisplayPath());
073                    comment.append("\ncompilation-time:").append(new DateTimeImpl(ComponentUtil.getCompileTime(pc,cfci.getPageSource()),false)).append("\n");
074                    
075                    hibernateMapping.appendChild(doc.createComment(comment.toString()));
076                    
077                    //print.e(cfc.getAbsName()+";"+isClass+" -> "+cfci.getBaseAbsName()+":"+cfci.isBasePeristent());
078                    if(!isClass && !cfci.isBasePeristent()) {
079                            isClass=true;
080                    } 
081                    
082                    
083                    Element join=null;
084                    boolean doTable=true;
085                    
086                    Element clazz;
087                    if(isClass)  {
088                            clazz = doc.createElement("class");
089                            hibernateMapping.appendChild(clazz);
090                    }
091                    // extended CFC
092                    else{
093                            String ext = List.last(extend,'.').trim();
094                            try {
095                                    Component base = engine.getEntityByCFCName(ext, false);
096                                    ext = HibernateCaster.getEntityName(base);
097                            }
098                            catch(Throwable t){}
099                            
100                            
101                            String discriminatorValue = toString(engine,cfc,null,meta,"discriminatorValue");
102                            if(!StringUtil.isEmpty(discriminatorValue,true)) {
103                                    doTable=false;
104                                    clazz = doc.createElement("subclass");
105                                    hibernateMapping.appendChild(clazz);
106                            //addClassAttributes(classNode);
107                            clazz.setAttribute("extends", ext);
108                            clazz.setAttribute("discriminator-value", discriminatorValue);
109                            
110                            String joincolumn = toString(engine,cfc,null,meta,"joincolumn",false);
111                            if(!StringUtil.isEmpty(joincolumn)){
112                                    join = doc.createElement("join");
113                                    clazz.appendChild(join);
114                                    doTable=true;
115                                    Element key = doc.createElement("key");
116                                    join.appendChild(key);
117                                    key.setAttribute("column", formatColumn(engine,joincolumn));
118                            }
119                            
120                            }
121                            else {
122                                    clazz = doc.createElement("joined-subclass");
123                                    hibernateMapping.appendChild(clazz);
124                                    clazz.setAttribute("extends",ext);
125                                    Element key = doc.createElement("key");
126                                clazz.appendChild(key);
127                            key.setAttribute("column", formatColumn(engine,toString(engine,cfc,null,meta,"joincolumn",true)));
128                            }
129    
130                    }
131                    
132                    //createXMLMappingTuplizer(clazz,pc);
133    
134                    addGeneralClassAttributes(pc,ormConf,engine,cfc,meta,clazz);
135                    String tableName=getTableName(engine,pc,meta,cfc);
136                    
137                    if(join!=null) clazz=join;
138                    if(doTable)addGeneralTableAttributes(pc,ormConf,engine,cfc,meta,clazz);
139                    
140                    
141            
142            
143            Struct columnsInfo=null;
144            if(ormConf.useDBForMapping()){
145                    columnsInfo = engine.getTableInfo(dc,getTableName(engine,pc, meta, cfci),engine);
146            }
147    
148            if(isClass)setCacheStrategy(engine,cfc,null,doc, meta, clazz);
149            
150                    // id
151            if(isClass) addId(cfc,doc,clazz,pc,meta,propColl,columnsInfo,tableName,engine);
152                  
153            // discriminator
154            if(isClass) addDiscriminator(engine,cfc,doc,clazz,pc,meta);
155            
156                    // version
157            if(isClass)addVersion(cfc,clazz,pc, propColl,columnsInfo,tableName,engine);
158                    
159                    // property
160                    addProperty(cfc,clazz,pc, propColl,columnsInfo,tableName,engine);
161                    
162                    // relations
163                    addRelation(cfc,clazz,pc, propColl,columnsInfo,tableName,engine,ormConf,dc);
164    
165                    // collection
166                    addCollection(cfc,clazz,pc, propColl,columnsInfo,tableName,engine,ormConf);
167                    
168                    // join
169                    addJoin(cfc,clazz,pc, joins,columnsInfo,tableName,engine,ormConf,dc);
170    
171                    
172            }
173            
174            private static Property[] getProperties(PageContext pc, HibernateORMEngine engine, ComponentPro cfci, DatasourceConnection dc, ORMConfiguration ormConf, Struct meta, boolean isClass) throws ORMException, PageException {
175                    Property[] _props = cfci.getProperties(true);
176                    if(isClass && _props.length==0 && ormConf.useDBForMapping()){
177                            if(meta==null)meta = cfci.getMetaData(pc);
178                    _props=HibernateUtil.createPropertiesFromTable(dc,getTableName(engine,pc, meta, cfci));
179            }
180                    return _props;
181            }
182    
183    
184    
185    
186    
187    
188    
189    
190    
191    
192    
193    
194            private static void addId(Component cfc,Document doc, Element clazz, PageContext pc, Struct meta, PropertyCollection propColl, Struct columnsInfo, String tableName, HibernateORMEngine engine) throws PageException {
195                    Property[] _ids = getIds(engine,cfc,propColl);
196                    
197            //Property[] _ids = ids.toArray(new Property[ids.size()]);
198            
199            if(_ids.length==1) 
200                    createXMLMappingId(cfc,clazz,pc, _ids[0],columnsInfo,tableName,engine);
201            else if(_ids.length>1) 
202                    createXMLMappingCompositeId(cfc,clazz,pc, _ids,columnsInfo,tableName,engine);
203            else 
204                    throw new HibernateException(engine,cfc,"missing id property for entity ["+HibernateCaster.getEntityName(cfc)+"]");
205            }
206            
207    
208            public static PropertyCollection splitJoins(HibernateORMEngine engine,Component cfc,Map<String, PropertyCollection> joins,Property[] props) {
209                    Struct sct=new StructImpl();
210                    ArrayList<Property> others = new ArrayList<Property>();
211                    java.util.List<Property> list;
212                    String table;
213                    Property prop;
214                    String fieldType;
215                    boolean isJoin;
216                    for(int i=0;i<props.length;i++){
217                            prop=props[i];
218                            table=getTable(engine,cfc,prop);
219                            // joins
220                            if(!StringUtil.isEmpty(table,true)){
221                                    isJoin=true;
222                                    // wrong field type
223                                    try {
224                                            fieldType = toString(engine, cfc, prop, sct, FIELD_TYPE,false);
225                                            
226                                            if("collection".equalsIgnoreCase(fieldType)) isJoin=false;
227                                            else if("primary".equals(fieldType)) isJoin=false;
228                                            else if("version".equals(fieldType)) isJoin=false;
229                                            else if("timestamp".equals(fieldType)) isJoin=false;
230                                    } 
231                                    catch (ORMException e) {}
232                                    
233                                    // missing column
234                                    String columns=null;
235                                    try {
236                                            if(isRelated(props[i])){
237                                            columns=toString(engine,cfc,props[i], prop.getDynamicAttributes(), "fkcolumn");
238                                    }
239                                    else {
240                                            columns=toString(engine,cfc,props[i], prop.getDynamicAttributes(), "joincolumn");
241                                    }
242                                    }
243                                    catch(ORMException e){}
244                                    if(StringUtil.isEmpty(columns)) isJoin=false;
245                                    
246                                    if(isJoin){
247                                            table=table.trim();
248                                            list = (java.util.List<Property>) sct.get(table,null);
249                                            if(list==null){
250                                                    list=new ArrayList<Property>();
251                                                    sct.setEL(KeyImpl.init(table), list);
252                                            }
253                                            list.add(prop);
254                                            continue;
255                                    }
256                            }
257                            others.add(prop);
258                    }
259                    
260                    // fill to joins
261                    Key[] keys = sct.keys();
262                    Key key;
263                    for(int i=0;i<keys.length;i++){
264                            key=keys[i];
265                            list=(java.util.List<Property>) sct.get(key,null);
266                            joins.put(key.getString(), new PropertyCollection(key.getString(),list));
267                    }
268                    
269                    
270                    
271                    return new PropertyCollection(null,others);
272            }
273            
274            
275            
276            
277    
278            public static Property[] getIds(HibernateORMEngine engine,Component cfc,PropertyCollection pc) {
279                    return getIds(engine,cfc,pc.getProperties(), pc.getTableName(),false);
280            }
281            
282            public static Property[] getIds(HibernateORMEngine engine,Component cfc,Property[] props,String tableName, boolean ignoreTableName) {
283                    ArrayList<Property> ids=new ArrayList<Property>();
284            for(int y=0;y<props.length;y++){
285                    if(!ignoreTableName && !hasTable(engine,cfc,props[y], tableName)) continue;
286                    
287                    
288                    String fieldType = Caster.toString(props[y].getDynamicAttributes().get(FIELD_TYPE,null),null);
289                            if("id".equalsIgnoreCase(fieldType) || List.listFindNoCaseIgnoreEmpty(fieldType,"id",',')!=-1)
290                                    ids.add(props[y]);
291                    }
292            
293            // no id field defined
294            if(ids.size()==0) {
295                    String fieldType;
296                    for(int y=0;y<props.length;y++){
297                            if(!ignoreTableName && !hasTable(engine,cfc,props[y], tableName)) continue;
298                    fieldType = Caster.toString(props[y].getDynamicAttributes().get(FIELD_TYPE,null),null);
299                            if(StringUtil.isEmpty(fieldType,true) && props[y].getName().equalsIgnoreCase("id")){
300                                    ids.add(props[y]);
301                                    props[y].getDynamicAttributes().setEL(FIELD_TYPE, "id");
302                            }
303                    }
304            } 
305            
306            // still no id field defined
307            if(ids.size()==0 && props.length>0) {
308                    String owner = props[0].getOwnerName();
309                            if(!StringUtil.isEmpty(owner)) owner=List.last(owner, '.').trim();
310                    
311                    String fieldType;
312                    if(!StringUtil.isEmpty(owner)){
313                            String id=owner+"id";
314                            for(int y=0;y<props.length;y++){
315                                    if(!ignoreTableName && !hasTable(engine,cfc,props[y], tableName)) continue;
316                            fieldType = Caster.toString(props[y].getDynamicAttributes().get(FIELD_TYPE,null),null);
317                                    if(StringUtil.isEmpty(fieldType,true) && props[y].getName().equalsIgnoreCase(id)){
318                                            ids.add(props[y]);
319                                            props[y].getDynamicAttributes().setEL(FIELD_TYPE, "id");
320                                    }
321                            }
322                    }
323            } 
324            return ids.toArray(new Property[ids.size()]);
325            }
326    
327    
328    
329    
330    
331    
332            private static void addVersion(Component cfc,Element clazz, PageContext pc,PropertyCollection propColl, Struct columnsInfo, String tableName,HibernateORMEngine engine) throws PageException {
333            Property[] props = propColl.getProperties();
334                    for(int y=0;y<props.length;y++){
335                            String fieldType = Caster.toString(props[y].getDynamicAttributes().get(FIELD_TYPE,null),null);
336                            if("version".equalsIgnoreCase(fieldType))
337                                    createXMLMappingVersion(engine,clazz,pc, cfc,props[y]);
338                            else if("timestamp".equalsIgnoreCase(fieldType))
339                                    createXMLMappingTimestamp(engine,clazz,pc,cfc, props[y]);
340                    }
341            }
342    
343    
344    
345            private static void addCollection(Component cfc,Element clazz, PageContext pc,PropertyCollection propColl, Struct columnsInfo, String tableName,HibernateORMEngine engine, ORMConfiguration ormConf) throws PageException {
346                    Property[] props = propColl.getProperties();
347                    for(int y=0;y<props.length;y++){
348                            String fieldType = Caster.toString(props[y].getDynamicAttributes().get(FIELD_TYPE,"column"),"column");
349                            if("collection".equalsIgnoreCase(fieldType))
350                                    createXMLMappingCollection(clazz,pc, cfc,props[y],ormConf,engine);
351                    }
352            }
353            
354            
355            private static void addJoin(Component cfc,Element clazz, PageContext pc,Map<String, PropertyCollection> joins, Struct columnsInfo, String tableName,HibernateORMEngine engine, ORMConfiguration ormConf, DatasourceConnection dc) throws PageException {
356            
357                    Iterator<Entry<String, PropertyCollection>> it = joins.entrySet().iterator();
358                    Entry<String, PropertyCollection> entry;
359                    while(it.hasNext()){
360                            entry = it.next();
361                            addJoin(cfc,engine,pc,columnsInfo,ormConf,clazz,entry.getValue(),dc);
362                    }
363                    
364                    
365                    
366        }
367            
368            private static void addJoin(Component cfc,HibernateORMEngine engine,PageContext pc,Struct columnsInfo,  ORMConfiguration ormConf, Element clazz, PropertyCollection coll, DatasourceConnection dc) throws PageException {
369                    String table = coll.getTableName();
370                    Property[] properties = coll.getProperties();
371                    if(properties.length==0) return;
372                    
373                    Document doc = XMLUtil.getDocument(clazz);
374                    
375                    Element join = doc.createElement("join");
376            clazz.appendChild(join);
377                    
378            join.setAttribute("table", escape(engine.convertTableName(coll.getTableName())));
379            //addTableInfo(joinNode, table, schema, catalog);
380            
381            Property first = properties[0];
382            String schema = null, catalog=null, mappedBy=null, columns=null;
383            if(isRelated(first)){
384                    catalog=toString(engine,cfc,first, first.getDynamicAttributes(), "linkcatalog");
385                    schema=toString(engine,cfc,first, first.getDynamicAttributes(), "linkschema");
386                    columns=toString(engine,cfc,first, first.getDynamicAttributes(), "fkcolumn");
387                    
388            }
389            else {
390                    catalog=toString(engine,cfc,first, first.getDynamicAttributes(), "catalog");
391                    schema=toString(engine,cfc,first, first.getDynamicAttributes(), "schema");
392                    mappedBy=toString(engine,cfc,first, first.getDynamicAttributes(), "mappedby");
393                    columns=toString(engine,cfc,first, first.getDynamicAttributes(), "joincolumn");
394            }
395    
396            if(!StringUtil.isEmpty(catalog)) join.setAttribute("catalog", catalog);
397            if(!StringUtil.isEmpty(schema)) join.setAttribute("schema", schema);
398            
399            Element key = doc.createElement("key");
400            join.appendChild(key);
401            if(!StringUtil.isEmpty(mappedBy)) key.setAttribute("property-ref", mappedBy);
402            setColumn(engine,doc, key, columns);
403            
404            addProperty(cfc,join,pc, coll,columnsInfo,table,engine);
405                    int count=addRelation(cfc,join,pc, coll,columnsInfo,table,engine, ormConf,dc);
406            
407                    if(count>0) join.setAttribute("inverse", "true");
408                            
409                    
410            }
411    
412    
413    
414    
415    
416    
417    
418            
419    
420    
421    
422            private static int addRelation(Component cfc,Element clazz, PageContext pc,PropertyCollection propColl, Struct columnsInfo, String tableName,HibernateORMEngine engine,  ORMConfiguration ormConf, DatasourceConnection dc) throws PageException {
423            Property[] props = propColl.getProperties();
424                    int count=0;
425            for(int y=0;y<props.length;y++){
426                            String fieldType = Caster.toString(props[y].getDynamicAttributes().get(FIELD_TYPE,"column"),"column");
427                            if("one-to-one".equalsIgnoreCase(fieldType)){
428                                    createXMLMappingOneToOne(clazz,pc, cfc,props[y],engine);
429                                    count++;
430                            }
431                            else if("many-to-one".equalsIgnoreCase(fieldType)){
432                                    createXMLMappingManyToOne(clazz,pc, cfc,props[y],engine,propColl);
433                                    count++;
434                            }
435                            else if("one-to-many".equalsIgnoreCase(fieldType)){
436                                    createXMLMappingOneToMany(cfc,engine,propColl,ormConf,clazz,pc, props[y]);
437                                    count++;
438                            }
439                            else if("many-to-many".equalsIgnoreCase(fieldType)){
440                                    createXMLMappingManyToMany(cfc,engine,propColl,clazz,pc, props[y],ormConf,dc);
441                                    count++;
442                            }
443                    }
444            return count;
445            }
446            
447            public static boolean isRelated(Property prop) {
448                    String fieldType = Caster.toString(prop.getDynamicAttributes().get(FIELD_TYPE,"column"),"column");
449                    if(StringUtil.isEmpty(fieldType,true)) return false;
450                    fieldType=fieldType.toLowerCase().trim();
451                    
452                    if("one-to-one".equals(fieldType))              return true;
453                    if("many-to-one".equals(fieldType))     return true;
454                    if("one-to-many".equals(fieldType))     return true;
455                    if("many-to-many".equals(fieldType))    return true;
456                    return false;
457            }
458    
459    
460    
461            private static void addProperty(Component cfc,Element clazz, PageContext pc, PropertyCollection propColl, Struct columnsInfo, String tableName, HibernateORMEngine engine) throws ORMException {
462                    Property[] props = propColl.getProperties();
463                    for(int y=0;y<props.length;y++){
464                            String fieldType = Caster.toString(props[y].getDynamicAttributes().get(FIELD_TYPE,"column"),"column");
465                            if("column".equalsIgnoreCase(fieldType))
466                                    createXMLMappingProperty(clazz,pc,cfc, props[y],columnsInfo,tableName,engine);
467                    }
468            }
469    
470    
471    
472            private static void addDiscriminator(HibernateORMEngine engine,Component cfc,Document doc,Element clazz, PageContext pc,Struct meta) throws ORMException {
473                    
474             String str = toString(engine,cfc,null,meta,"discriminatorColumn");
475             if(!StringUtil.isEmpty(str,true)){
476                     Element disc = doc.createElement("discriminator");
477                     clazz.appendChild(disc);
478                     disc.setAttribute("column",formatColumn(engine,str));
479             }
480             
481    
482            
483            
484            }
485    
486    
487    
488            private static void addGeneralClassAttributes(PageContext pc, ORMConfiguration ormConf, HibernateORMEngine engine, Component cfc, Struct meta, Element clazz) throws PageException {
489            
490            // name
491                    clazz.setAttribute("node", HibernateCaster.toComponentName(cfc));
492                    
493            // entity-name
494            String str=toString(engine,cfc,null,meta,"entityname");
495                    if(StringUtil.isEmpty(str,true)) str=HibernateCaster.getEntityName(cfc);
496                    clazz.setAttribute("entity-name",str);
497                    
498    
499            // batch-size
500            Integer i = toInteger(engine,cfc,meta,"batchsize");
501            if(i!=null && i.intValue()>0)clazz.setAttribute("batch-size",Caster.toString(i));
502                    
503                    // dynamic-insert
504            Boolean b = toBoolean(engine,cfc,meta,"dynamicinsert");
505            if(b!=null && b.booleanValue())clazz.setAttribute("dynamic-insert","true");
506            
507            // dynamic-update
508            b=toBoolean(engine,cfc,meta,"dynamicupdate");
509            if(b!=null && b.booleanValue())clazz.setAttribute("dynamic-update","true");
510            
511                    // lazy (dtd defintion:<!ATTLIST class lazy (true|false) #IMPLIED>)
512            b=toBoolean(engine,cfc,meta,"lazy");
513            if(b==null) b=Boolean.TRUE;
514            clazz.setAttribute("lazy",Caster.toString(b.booleanValue()));
515                    
516            // select-before-update
517            b=toBoolean(engine,cfc,meta,"selectbeforeupdate");
518            if(b!=null && b.booleanValue())clazz.setAttribute("select-before-update","true");
519    
520            // optimistic-lock
521            str=toString(engine,cfc,null,meta,"optimisticLock");
522            if(!StringUtil.isEmpty(str,true)) {
523                    str=str.trim().toLowerCase();
524                    if("all".equals(str) || "dirty".equals(str) || "none".equals(str) || "version".equals(str))
525                            clazz.setAttribute("optimistic-lock",str);
526                    else
527                            throw new HibernateException(engine,cfc,"invalid value ["+str+"] for attribute [optimisticlock] of tag [component], valid values are [all,dirty,none,version]");
528            }
529            
530            // read-only
531            b=toBoolean(engine,cfc,meta,"readOnly");
532            if(b!=null && b.booleanValue()) clazz.setAttribute("mutable", "false");
533            
534            // rowid
535            str=toString(engine,cfc,null,meta,"rowid");
536            if(!StringUtil.isEmpty(str,true)) clazz.setAttribute("rowid",str);
537            
538            // where
539            str=toString(engine,cfc,null,meta,"where");
540            if(!StringUtil.isEmpty(str,true)) clazz.setAttribute("where", str);
541    
542           
543            }
544            private static void addGeneralTableAttributes(PageContext pc, ORMConfiguration ormConf, HibernateORMEngine engine, Component cfc, Struct meta, Element clazz) throws PageException {
545                     // table
546            clazz.setAttribute("table",escape(getTableName(engine,pc,meta,cfc)));
547            
548            // catalog
549            String str = toString(engine,cfc,null,meta,"catalog");
550            if(str==null)// empty string is allowed as input
551                    str=ormConf.getCatalog();
552            if(!StringUtil.isEmpty(str,true)) clazz.setAttribute("catalog", str);
553            
554            // schema
555            str=toString(engine,cfc,null,meta,"schema");
556            if(str==null)// empty string is allowed as input
557                    str=ormConf.getSchema();
558            if(!StringUtil.isEmpty(str,true)) clazz.setAttribute( "schema", str);
559            
560            }
561            private static String escape(String str) {
562                    if(HibernateUtil.isKeyword(str)) return "`"+str+"`";
563                    return str;
564            }
565    
566    
567    
568    
569    
570    
571            private static String getTableName(HibernateORMEngine engine,PageContext pc, Struct meta, Component cfc) throws ORMException {
572                    String tableName=toString(engine,cfc,null,meta,"table");
573                    if(StringUtil.isEmpty(tableName,true)) 
574                            tableName=HibernateCaster.getEntityName(cfc);
575                    return engine.convertTableName(tableName);
576            }
577            
578            private static String getTable(HibernateORMEngine engine,Component cfc,Property prop) {
579                    try {
580                            return engine.convertTableName(toString(engine,cfc,prop, prop.getDynamicAttributes(), "table"));
581                    } catch (ORMException e) {
582                            return null;
583                    }
584            }
585            
586            private static boolean hasTable(HibernateORMEngine engine,Component cfc,Property prop,String tableName) {
587                    String t = getTable(engine,cfc,prop);
588                    boolean left=StringUtil.isEmpty(t,true);
589                    boolean right=StringUtil.isEmpty(tableName,true);
590                    if(left && right) return true;
591                    if(left || right) return false;
592                    return tableName.trim().equalsIgnoreCase(t.trim());
593            }
594    
595    
596    
597    
598    
599    
600            private static void createXMLMappingCompositeId(Component cfc,Element clazz, PageContext pc,Property[] props,Struct columnsInfo,String tableName,HibernateORMEngine engine) throws PageException {
601                    Struct meta;
602                    
603                    Document doc = XMLUtil.getDocument(clazz);
604                    Element cid = doc.createElement("composite-id");
605                    clazz.appendChild(cid);
606                    
607                    //cid.setAttribute("mapped","true");
608                    
609                    
610                    Property prop;
611                    // ids
612                    for(int y=0;y<props.length;y++){
613                            prop=props[y];
614                            meta = prop.getDynamicAttributes();
615                            Element key = doc.createElement("key-property");
616                            cid.appendChild(key);
617                            
618                            // name
619                            key.setAttribute("name",prop.getName());
620                            
621                            // column
622                            Element column = doc.createElement("column");
623                            key.appendChild(column);
624                            
625                            String str = toString(engine,cfc,prop,meta,"column");
626                    if(StringUtil.isEmpty(str,true)) str=prop.getName();
627                    column.setAttribute("name",formatColumn(engine,str));
628                    ColumnInfo info=getColumnInfo(columnsInfo,tableName,str,engine,null);
629                    
630                str = toString(engine,cfc,prop,meta,"sqltype");
631                    if(!StringUtil.isEmpty(str,true)) column.setAttribute("sql-type",str);
632                    str = toString(engine,cfc,prop,meta,"length");
633                    if(!StringUtil.isEmpty(str,true)) column.setAttribute("length",str);
634                
635                    /*if(info!=null){
636                            column.setAttribute("sql-type",info.getTypeName());
637                            column.setAttribute("length",Caster.toString(info.getSize()));
638                    }*/
639                            
640                     // type
641                            //str=getType(info,prop,meta,"long"); //MUSTMUST
642                            //key.setAttribute("type", str);
643                            
644                            String generator=toString(engine,cfc,prop,meta,"generator");
645                            String type = getType(engine,info,cfc,prop,meta,getDefaultTypeForGenerator(generator,"string"));
646                            if(!StringUtil.isEmpty(type))key.setAttribute("type", type);
647                            
648                            
649                            
650                
651                    }
652                    
653                    // many-to-one
654                    String fieldType;
655                    for(int y=0;y<props.length;y++){
656                            prop=props[y];
657                            meta = prop.getDynamicAttributes();
658                            fieldType = toString(engine,cfc,prop,meta,"fieldType");
659                            if(List.listFindNoCaseIgnoreEmpty(fieldType,"many-to-one",',')==-1)continue;
660                            
661                            Element key = doc.createElement("key-many-to-one");
662                            cid.appendChild(key);
663                            
664                            // name
665                            key.setAttribute("name",prop.getName());
666                            
667                            // entity-name
668                            setForeignEntityName(pc, engine,cfc,prop, meta, key,false);
669                            
670                            // fkcolum
671                            String str=toString(engine,cfc,prop,meta,"fkcolumn");
672                            setColumn(engine,doc, key, str);
673                            
674                            // lazy
675                            setLazy(engine,cfc,prop,meta,key);
676                    }
677            }
678            
679            
680            private static void createXMLMappingId(Component cfc,Element clazz, PageContext pc,Property prop,Struct columnsInfo,String tableName,HibernateORMEngine engine) throws PageException {
681                    Struct meta = prop.getDynamicAttributes();
682                    String str;
683                    
684                    Document doc = XMLUtil.getDocument(clazz);
685                    Element id = doc.createElement("id");
686                    clazz.appendChild(id);
687                            
688            // access
689            str=toString(engine,cfc,prop,meta,"access");
690                    if(!StringUtil.isEmpty(str,true))id.setAttribute("access", str);
691            
692                    // name
693                    id.setAttribute("name",prop.getName());
694                    
695                    // column
696                    Element column = doc.createElement("column");
697                    id.appendChild(column);
698    
699                    str=toString(engine,cfc,prop,meta,"column");
700            if(StringUtil.isEmpty(str,true)) str=prop.getName();
701            column.setAttribute("name",formatColumn(engine,str));
702            ColumnInfo info=getColumnInfo(columnsInfo,tableName,str,engine,null);
703            StringBuilder foreignCFC=new StringBuilder();
704                    String generator=createXMLMappingGenerator(engine,id,pc,cfc,prop,foreignCFC);
705    
706                    str = toString(engine,cfc,prop,meta,"length");
707            if(!StringUtil.isEmpty(str,true)) column.setAttribute("length",str);
708            
709                    // type    
710                    String type = getType(engine,info,cfc,prop,meta,getDefaultTypeForGenerator(engine,generator,foreignCFC));
711                    //print.o(prop.getName()+":"+type+"::"+getDefaultTypeForGenerator(engine,generator,foreignCFC));
712                    if(!StringUtil.isEmpty(type))id.setAttribute("type", type);
713                    
714                    // unsaved-value
715                    str=toString(engine,cfc,prop,meta,"unsavedValue");  
716                    if(str!=null)id.setAttribute("unsaved-value", str);
717                    
718            }
719            
720            private static String getDefaultTypeForGenerator(HibernateORMEngine engine, String generator,StringBuilder foreignCFC) {
721                    String value = getDefaultTypeForGenerator(generator, null);
722                    if(value!=null) return value;
723                    
724                    if("foreign".equalsIgnoreCase(generator)) {
725                            if(!StringUtil.isEmpty(foreignCFC)) {
726                                    try {
727                                            Component cfc = engine.getEntityByCFCName(foreignCFC.toString(), false);
728                                            if(cfc!=null){
729                                                    ComponentPro cfcp = ComponentUtil.toComponentPro(cfc);
730                                                    Property[] ids = getIds(engine,cfc,cfcp.getProperties(true),null,true);
731                                                    if(!ArrayUtil.isEmpty(ids)){
732                                                            Property id = ids[0];
733                                                            id.getDynamicAttributes();
734                                                            Struct meta = id.getDynamicAttributes();
735                                                            if(meta!=null){
736                                                                    String type=Caster.toString(meta.get(KeyImpl.TYPE,null));
737                                                                    
738                                                                    if(!StringUtil.isEmpty(type) && (!type.equalsIgnoreCase("any") && !type.equalsIgnoreCase("object"))){
739                                                                            return type;
740                                                                    }
741                                                                    else {
742                                                                            String g=Caster.toString(meta.get(GENERATOR,null));
743                                                                            if(!StringUtil.isEmpty(g)){
744                                                                                    return getDefaultTypeForGenerator(engine,g,foreignCFC);
745                                                                            }
746                                                                    }
747                                                            }
748                                                    }
749                                            }
750                                    }
751                                    catch(Throwable t){}
752                            }
753                            return "string";
754                    }
755                    
756                    return "string";
757            }
758            
759            private static String getDefaultTypeForGenerator(String generator,String defaultValue) {
760                    if("increment".equalsIgnoreCase(generator)) return "integer";
761                    if("identity".equalsIgnoreCase(generator)) return "integer";
762                    if("native".equalsIgnoreCase(generator)) return "integer";
763                    if("seqhilo".equalsIgnoreCase(generator)) return "string";
764                    if("uuid".equalsIgnoreCase(generator)) return "string";
765                    if("guid".equalsIgnoreCase(generator)) return "string";
766                    if("select".equalsIgnoreCase(generator)) return "string";
767                    return defaultValue;
768            }
769            
770            private static String getType(HibernateORMEngine engine,ColumnInfo info, Component cfc,Property prop,Struct meta,String defaultValue) throws ORMException {
771                    // ormType
772                    String type = toString(engine,cfc,prop,meta,"ormType");
773                    //type=HibernateCaster.toHibernateType(info,type,null);
774                    
775                    // dataType
776                    if(StringUtil.isEmpty(type,true)){
777                            type=toString(engine,cfc,prop,meta,"dataType");
778                            //type=HibernateCaster.toHibernateType(info,type,null);
779                    }
780                    
781                    // type
782                    if(StringUtil.isEmpty(type,true)){
783                            type=prop.getType();
784                            //type=HibernateCaster.toHibernateType(info,type,null);
785                    }
786                    
787                    // type from db info
788                    if(StringUtil.isEmpty(type,true)){
789                            if(info!=null){
790                                    type=info.getTypeName();
791                                    //type=HibernateCaster.toHibernateType(info,type,defaultValue);
792                            }
793                            else return defaultValue;
794                    }
795                    
796                    return HibernateCaster.toHibernateType(info,type,defaultValue);
797            }
798    
799    
800    
801    
802    
803    
804    
805    
806    
807            private static ColumnInfo getColumnInfo(Struct columnsInfo,String tableName,String columnName,ORMEngine engine,ColumnInfo defaultValue) throws ORMException {
808                    if(columnsInfo!=null) {
809                    ColumnInfo info = (ColumnInfo) columnsInfo.get(KeyImpl.getInstance(columnName),null);
810                            if(info==null) return defaultValue;
811                            return info;
812            }
813                    return defaultValue;
814            }
815            
816            /*private static ColumnInfo getColumnInfo(Struct columnsInfo,String tableName,String columnName,ORMEngine engine) throws ORMException {
817                    if(columnsInfo!=null) {
818                    ColumnInfo info = (ColumnInfo) columnsInfo.get(columnName,null);
819                            if(info==null) {
820                                    String msg="table ["+tableName+"] has no column with name ["+columnName+"]";
821                                    if(columnsInfo!=null)
822                                            msg+=", column names are ["+List.arrayToList(columnsInfo.keysAsString(), ", ")+"]";
823                                    ORMUtil.printError(msg, engine);
824                                    
825                                    //throw new ORMException(msg);
826                            }
827                            return info;
828            }
829                    return null;
830            }*/
831    
832            private static String createXMLMappingGenerator(HibernateORMEngine engine,Element id, PageContext pc,Component cfc,Property prop,StringBuilder foreignCFC) throws PageException {
833                    Struct meta = prop.getDynamicAttributes();
834                    
835                    // generator
836                    String className=toString(engine,cfc,prop,meta,"generator");
837                    if(StringUtil.isEmpty(className,true)) return null;
838                    
839    
840                    Document doc = XMLUtil.getDocument(id);
841                    Element generator = doc.createElement("generator");
842                    id.appendChild(generator);
843                    
844                    generator.setAttribute("class", className);
845                    
846                    //print.e("generator:"+className);
847                    
848                    // params
849                    Object obj=meta.get(PARAMS,null);
850                    //if(obj!=null){
851                            Struct sct=null;
852                            if(obj==null) obj=new StructImpl();
853                            else if(obj instanceof String) obj=convertToSimpleMap((String)obj);
854                            
855                            if(Decision.isStruct(obj)) sct=Caster.toStruct(obj);
856                            else throw new HibernateException(engine,cfc,"invalid value for attribute [params] of tag [property]");
857                            className=className.trim().toLowerCase();
858                            
859                            // special classes
860                            if("foreign".equals(className)){
861                                    if(!sct.containsKey(PROPERTY)) sct.setEL(PROPERTY, toString(engine,cfc,prop,meta, PROPERTY,true));
862                                    
863                                    if(sct.containsKey(PROPERTY)){
864                                            String p = Caster.toString(sct.get(PROPERTY),null);
865                                            if(!StringUtil.isEmpty(p))foreignCFC.append(p);
866                                    }
867                                    
868                                    
869                            }
870                            else if("select".equals(className)){
871                                    //print.e("select:"+toString(meta, "selectKey",true));
872                                    if(!sct.containsKey(KeyImpl.KEY)) sct.setEL(KeyImpl.KEY, toString(engine,cfc,prop,meta, "selectKey",true));
873                            }
874                            else if("sequence".equals(className)){
875                                    if(!sct.containsKey(SEQUENCE)) sct.setEL(SEQUENCE, toString(engine,cfc,prop,meta, "sequence",true));
876                            }
877                            
878                            Key[] keys = sct.keys();
879                            Element param;
880                            for(int y=0;y<keys.length;y++){
881                                    
882                                    param = doc.createElement("param");
883                                    generator.appendChild(param);
884                                    
885                                    param.setAttribute( "name", keys[y].getLowerString());
886                                    param.appendChild(doc.createTextNode(Caster.toString(sct.get(keys[y]))));
887                                    
888                            }
889                    //}
890                    return className;
891            }
892            
893            
894            
895            
896    
897            
898    
899            private static void createXMLMappingProperty(Element clazz, PageContext pc,Component cfc,Property prop,Struct columnsInfo,String tableName,HibernateORMEngine engine) throws ORMException {
900                    Struct meta = prop.getDynamicAttributes();
901                    
902            
903                    
904                    // get table name
905                    String columnName=toString(engine,cfc,prop,meta,"column");
906            if(StringUtil.isEmpty(columnName,true)) columnName=prop.getName();
907            
908            ColumnInfo info=getColumnInfo(columnsInfo,tableName,columnName,engine,null);
909                    
910                    Document doc = XMLUtil.getDocument(clazz);
911                    final Element property = doc.createElement("property");
912                    clazz.appendChild(property);
913                    
914                    //name
915                    property.setAttribute("name",prop.getName());
916                    
917                    // type
918                    String str = getType(engine,info, cfc,prop, meta, "string");
919                    property.setAttribute("type",str);
920                    
921                    
922                    
923                    // formula or column
924                    str=toString(engine,cfc,prop,meta,"formula");
925            Boolean b;
926                    if(!StringUtil.isEmpty(str,true))       {
927                    property.setAttribute("formula","("+str+")");
928            }
929            else {
930                    //property.setAttribute("column",columnName);
931                    
932                    Element column = doc.createElement("column");
933                    property.appendChild(column);
934                    column.setAttribute("name", escape(engine.convertColumnName(columnName)));
935    
936                // check
937                str=toString(engine,cfc,prop,meta,"check");
938                if(!StringUtil.isEmpty(str,true)) column.setAttribute("check",str);
939                
940                    // default
941                    str=toString(engine,cfc,prop,meta,"dbDefault");
942                    if(!StringUtil.isEmpty(str,true)) column.setAttribute("default",str);
943                
944                // index
945                str=toString(engine,cfc,prop,meta,"index");
946                if(!StringUtil.isEmpty(str,true)) column.setAttribute("index",str);
947                    
948                    // length
949                Integer i = toInteger(engine,cfc,meta,"length");
950                if(i!=null && i>0) column.setAttribute("length",Caster.toString(i.intValue()));
951                
952                // not-null
953                b=toBoolean(engine,cfc,meta,"notnull");
954                if(b!=null && b.booleanValue())column.setAttribute("not-null","true");
955                
956                // precision
957                i=toInteger(engine,cfc,meta,"precision");
958                if(i!=null && i>-1) column.setAttribute("precision",Caster.toString(i.intValue()));
959                
960                // scale
961                i=toInteger(engine,cfc,meta,"scale");
962                if(i!=null && i>-1) column.setAttribute("scale",Caster.toString(i.intValue()));
963                
964                // sql-type
965                str=toString(engine,cfc,prop,meta,"sqltype");
966                if(!StringUtil.isEmpty(str,true)) column.setAttribute("sql-type",str);
967                
968            // unique
969                b=toBoolean(engine,cfc,meta,"unique");
970                    if(b!=null && b.booleanValue())column.setAttribute("unique","true");
971                    
972                    // unique-key
973                    str=toString(engine,cfc,prop,meta,"uniqueKey");
974                    if(StringUtil.isEmpty(str))str=Caster.toString(meta.get(UNIQUE_KEY_NAME,null),null);
975                    if(!StringUtil.isEmpty(str,true)) column.setAttribute("unique-key",str);
976                    
977                    
978            }
979            
980            // generated
981            str=toString(engine,cfc,prop,meta,"generated");
982            if(!StringUtil.isEmpty(str,true)){
983                    str=str.trim().toLowerCase();
984                    
985                    if("always".equals(str) || "insert".equals(str) || "never".equals(str))
986                            property.setAttribute("generated",str);
987                    else
988                            throw invalidValue(engine,cfc,prop,"generated",str,"always,insert,never");
989                                    //throw new ORMException(engine,"invalid value ["+str+"] for attribute [generated] of column ["+columnName+"], valid values are [always,insert,never]");
990            }
991            
992            
993            // update
994            b=toBoolean(engine,cfc,meta,"update");
995            if(b!=null && !b.booleanValue())property.setAttribute("update","false");
996            
997            // insert
998            b=toBoolean(engine,cfc,meta,"insert");
999            if(b!=null && !b.booleanValue())property.setAttribute("insert","false");
1000            
1001            // lazy (dtd defintion:<!ATTLIST property lazy (true|false) "false">)
1002            b=toBoolean(engine,cfc,meta,"lazy");
1003            if(b!=null && b.booleanValue())property.setAttribute("lazy","true");
1004            
1005            // optimistic-lock
1006            b=toBoolean(engine,cfc,meta,"optimisticlock");
1007            if(b!=null && !b.booleanValue())property.setAttribute("optimistic-lock","false");
1008            
1009            }
1010            
1011            
1012            /*
1013            MUST dies kommt aber nicht hier sondern in verarbeitung in component
1014            <cfproperty 
1015        persistent="true|false" 
1016       >
1017             * */
1018            private static void createXMLMappingOneToOne(Element clazz, PageContext pc,Component cfc,Property prop,HibernateORMEngine engine) throws PageException {
1019                    Struct meta = prop.getDynamicAttributes();
1020                    
1021                    Boolean b;
1022                    
1023                    Document doc = XMLUtil.getDocument(clazz);
1024                    Element x2o;
1025                    
1026                    // column
1027                    String fkcolumn=toString(engine,cfc,prop,meta,"fkcolumn");
1028                    String linkTable=toString(engine,cfc,prop,meta,"linkTable");
1029                    
1030                    
1031                    if(!StringUtil.isEmpty(linkTable,true) || !StringUtil.isEmpty(fkcolumn,true)) {
1032                            clazz=getJoin(clazz);
1033                            
1034                            x2o= doc.createElement("many-to-one");
1035                            //x2o.setAttribute("column", fkcolumn);
1036                            x2o.setAttribute("unique", "true");
1037                            
1038                            if(!StringUtil.isEmpty(linkTable,true)){
1039                                    setColumn(engine,doc, x2o, linkTable);
1040                            }
1041                            else {
1042                                    setColumn(engine,doc, x2o, fkcolumn);
1043                            }
1044    
1045                            
1046                            
1047                            
1048                            // update
1049                    b=toBoolean(engine,cfc,meta,"update");
1050                    if(b!=null)x2o.setAttribute("update",Caster.toString(b.booleanValue()));
1051                    
1052                    // insert
1053                    b=toBoolean(engine,cfc,meta,"insert");
1054                    if(b!=null)x2o.setAttribute("insert",Caster.toString(b.booleanValue()));
1055                    
1056                    // not-null
1057                    b=toBoolean(engine,cfc,meta,"notNull");
1058                    if(b!=null)x2o.setAttribute("not-null",Caster.toString(b.booleanValue()));
1059                    
1060                    
1061                    // optimistic-lock
1062                    b=toBoolean(engine,cfc,meta,"optimisticLock");
1063                    if(b!=null)x2o.setAttribute("optimistic-lock",Caster.toString(b.booleanValue()));
1064                    
1065                    // not-found
1066                            b=toBoolean(engine,cfc,meta, "missingRowIgnored");
1067                    if(b!=null && b.booleanValue()) x2o.setAttribute("not-found", "ignore");
1068    
1069                            /* / index
1070                            str=toString(meta,"index");
1071                            if(!StringUtil.isEmpty(str,true)) x2o.setAttribute("index", str); 
1072                            */
1073                            
1074                            
1075                    }
1076                    else {
1077                            x2o= doc.createElement("one-to-one");
1078                    }
1079                    clazz.appendChild(x2o);
1080                    
1081                    // access
1082                    String str=toString(engine,cfc,prop,meta,"access");
1083                    if(!StringUtil.isEmpty(str,true)) x2o.setAttribute("access", str);
1084                            
1085                    // constrained
1086                    b=toBoolean(engine,cfc,meta, "constrained");
1087            if(b!=null && b.booleanValue()) x2o.setAttribute("constrained", "true");
1088                    
1089                    // formula
1090                    str=toString(engine,cfc,prop,meta,"formula");
1091                    if(!StringUtil.isEmpty(str,true)) x2o.setAttribute("formula", str);
1092                    
1093                    // embed-xml
1094                    str=toString(engine,cfc,prop,meta,"embedXml");
1095                    if(!StringUtil.isEmpty(str,true)) x2o.setAttribute("embed-xml", str);
1096                    
1097                    // property-ref
1098                    str=toString(engine,cfc,prop,meta,"mappedBy");
1099                    if(!StringUtil.isEmpty(str,true)) x2o.setAttribute("property-ref", str);
1100                    
1101                    // foreign-key
1102                    str=toString(engine,cfc,prop,meta,"foreignKeyName");
1103                    if(StringUtil.isEmpty(str,true)) str=toString(engine,cfc,prop,meta,"foreignKey");
1104                    if(!StringUtil.isEmpty(str,true)) x2o.setAttribute("foreign-key", str);
1105            
1106                    setForeignEntityName(pc,engine,cfc,prop,meta,x2o,true);
1107                    
1108                    createXMLMappingXToX(engine,x2o, pc,cfc,prop,meta);
1109            }
1110            
1111            
1112            
1113            
1114            
1115            
1116            private static Component loadForeignCFC(PageContext pc,HibernateORMEngine engine,Component cfc,Property prop, Struct meta) throws PageException {
1117                    // entity
1118                    String str=toString(engine,cfc,prop,meta,"entityName");
1119                    Component fcfc=null;
1120                    
1121                    if(!StringUtil.isEmpty(str,true)) {
1122                            fcfc = engine.getEntityByEntityName(str, false);
1123                            if(fcfc!=null) return fcfc;
1124                    }
1125                            
1126                    str = toString(engine,cfc,prop,meta,"cfc",false);
1127                    if(!StringUtil.isEmpty(str,true)){
1128                            return engine.getEntityByCFCName(str, false);
1129                    }
1130                    return null;
1131            }
1132    
1133    
1134    
1135    
1136    
1137    
1138    
1139    
1140    
1141            private static void createXMLMappingCollection(Element clazz, PageContext pc,Component cfc,Property prop,ORMConfiguration ormConf, HibernateORMEngine engine) throws PageException {
1142                    Struct meta = prop.getDynamicAttributes();
1143                    Document doc = XMLUtil.getDocument(clazz);
1144                    Element el=null;
1145                            
1146                    // collection type
1147                    String str=prop.getType();
1148                    if(StringUtil.isEmpty(str,true) || "any".equalsIgnoreCase(str) || "object".equalsIgnoreCase(str))str="array";
1149                    else str=str.trim().toLowerCase();
1150                    
1151                    
1152                    
1153                    // bag
1154                    if("array".equals(str) || "bag".equals(str)){
1155                            el = doc.createElement("bag");
1156                    }
1157                    // map
1158                    else if("struct".equals(str) || "map".equals(str)){
1159                            el = doc.createElement("map");
1160                            
1161                            
1162                            // map-key
1163                            str=toString(engine,cfc,prop,meta,"structKeyColumn",true);
1164                            if(!StringUtil.isEmpty(str,true)) {
1165                                    Element mapKey=doc.createElement("map-key");
1166                                    el.appendChild(mapKey);
1167                                    mapKey.setAttribute("column", str);
1168                                    
1169                                    // type
1170                                    str=toString(engine,cfc,prop,meta,"structKeyType");
1171                                    if(!StringUtil.isEmpty(str,true))mapKey.setAttribute("type", str);
1172                                    else mapKey.setAttribute("type", "string");
1173                            }
1174                    }
1175                    else throw invalidValue(engine,cfc,prop,"collectiontype",str,"array,struct");
1176                    //throw new ORMException(engine,"invalid value ["+str+"] for attribute [collectiontype], valid values are [array,struct]");
1177                    
1178                    setBeforeJoin(clazz,el);
1179                    
1180                    // name 
1181                    el.setAttribute("name", prop.getName());
1182                    
1183                    // table
1184                    str=toString(engine,cfc,prop,meta, "table",true);
1185                    el.setAttribute("table",escape(engine.convertTableName(str)));
1186                    
1187                    // catalog
1188                    str=toString(engine,cfc,prop,meta, "catalog");
1189                    if(!StringUtil.isEmpty(str,true))el.setAttribute("catalog",str);
1190                    
1191                    // schema
1192                    str=toString(engine,cfc,prop,meta, "schema");
1193                    if(!StringUtil.isEmpty(str,true))el.setAttribute("schema",str);
1194                    
1195                    // mutable
1196                    Boolean b=toBoolean(engine,cfc,meta, "readonly");
1197            if(b!=null && b.booleanValue()) el.setAttribute("mutable", "false");
1198                    
1199                    // order-by
1200                    str=toString(engine,cfc,prop,meta, "orderby");
1201                    if(!StringUtil.isEmpty(str,true))el.setAttribute("order-by",str);
1202                    
1203                    // element-column
1204                    str=toString(engine,cfc,prop,meta,"elementcolumn");
1205                    if(!StringUtil.isEmpty(str,true)){
1206                            Element element = doc.createElement("element");
1207                            el.appendChild(element);
1208                            
1209                            // column
1210                            element.setAttribute("column", formatColumn(engine,str));
1211                            
1212                            // type
1213                            str=toString(engine,cfc,prop,meta,"elementtype");
1214                            if(!StringUtil.isEmpty(str,true)) element.setAttribute("type", str);
1215                    }
1216                    
1217            // batch-size
1218            Integer i=toInteger(engine,cfc,meta, "batchsize");
1219            if(i!=null && i.intValue()>1) el.setAttribute("batch-size", Caster.toString(i.intValue()));
1220     
1221                    // column
1222                    str=toString(engine,cfc,prop,meta,"fkcolumn");
1223                    if(StringUtil.isEmpty(str,true)) str=toString(engine,cfc,prop,meta,"column");
1224                    if(!StringUtil.isEmpty(str,true)){
1225                            Element key = doc.createElement("key");
1226                            XMLUtil.setFirst(el,key);
1227                            //el.appendChild(key);
1228                            
1229                            // column
1230                            key.setAttribute("column", formatColumn(engine,str));
1231                            
1232                            // property-ref
1233                            str=toString(engine,cfc,prop,meta,"mappedBy");
1234                            if(!StringUtil.isEmpty(str,true)) key.setAttribute("property-ref", str);
1235                    }
1236                    
1237                    // cache
1238                    setCacheStrategy(engine,cfc,prop,doc, meta, el);
1239                    
1240                    // optimistic-lock
1241                    b=toBoolean(engine,cfc,meta, "optimisticlock");
1242            if(b!=null && !b.booleanValue()) el.setAttribute("optimistic-lock", "false");
1243            
1244           
1245            }
1246            
1247            
1248            private static void setBeforeJoin(Element clazz, Element el) {
1249                    Element join;
1250                    if(clazz.getNodeName().equals("join")) {
1251                            join=clazz;
1252                            clazz = getClazz(clazz);
1253                    }
1254                    else {
1255                            join = getJoin(clazz);
1256                    }
1257                    
1258                    if(join==clazz) clazz.appendChild(el);
1259                    else clazz.insertBefore(el, join);
1260                    
1261                    
1262            }
1263            
1264            private static Element getClazz(Element join) {
1265                    if(join.getNodeName().equals("join")){
1266                            return (Element) join.getParentNode();
1267                    }
1268                    return join;
1269            }
1270    
1271            private static Element getJoin(Element clazz) {
1272                    if(clazz.getNodeName().equals("subclass")){
1273                            NodeList joins = clazz.getElementsByTagName("join");
1274                            if(joins!=null && joins.getLength()>0)
1275                                    return (Element)joins.item(0);
1276                    }
1277                    return clazz;
1278            }
1279    
1280    
1281    
1282    
1283    
1284    
1285    
1286    
1287    
1288    
1289    
1290    
1291            private static void createXMLMappingManyToMany(Component cfc,HibernateORMEngine engine,PropertyCollection propColl,Element clazz, PageContext pc,Property prop,ORMConfiguration ormConf, DatasourceConnection dc) throws PageException {
1292                    Element el = createXMLMappingXToMany(engine,propColl,clazz, pc, cfc,prop);
1293                    Struct meta = prop.getDynamicAttributes();
1294                    Document doc = XMLUtil.getDocument(clazz);
1295                    Element m2m = doc.createElement("many-to-many");
1296                    el.appendChild(m2m);
1297                    
1298                    // link
1299                    setLink(engine,cfc,prop,el,meta,ormConf,true);
1300                    
1301                    setForeignEntityName(pc, engine,cfc,prop, meta, m2m,true);
1302    
1303            // order-by
1304                    String str = toString(engine,cfc,prop,meta,"orderby");
1305                    if(!StringUtil.isEmpty(str,true))m2m.setAttribute("order-by", str);
1306                    
1307                    // column
1308                    str=toString(engine,cfc,prop,meta,"inversejoincolumn");
1309                    
1310                    // build fkcolumn name
1311                    if(StringUtil.isEmpty(str,true)) {
1312                            ComponentPro other = (ComponentPro) loadForeignCFC(pc, engine, cfc, prop, meta);
1313                            if(other!=null){
1314                                    boolean isClass=StringUtil.isEmpty(other.getExtends());
1315                                    Property[] _props=getProperties(pc,engine,other,dc,ormConf,meta,isClass);
1316                                    PropertyCollection _propColl = splitJoins(engine,cfc,new HashMap<String, PropertyCollection>(), _props);
1317                                    _props=_propColl.getProperties();
1318                                    
1319                                    Struct m;
1320                                    Property _prop=null;
1321                                    for(int i=0;i<_props.length;i++){
1322                                            m = _props[i].getDynamicAttributes();
1323                                            // fieldtype
1324                                            String fieldtype = Caster.toString(m.get(FIELD_TYPE,null),null);
1325                                            if("many-to-many".equalsIgnoreCase(fieldtype)) {
1326                                                    // linktable
1327                                                    String currLinkTable=Caster.toString(meta.get(LINK_TABLE,null),null);
1328                                                    String othLinkTable=Caster.toString(m.get(LINK_TABLE,null),null);
1329                                                    if(currLinkTable.equals(othLinkTable)) {
1330                                                            // cfc name
1331                                                            ComponentPro cfcp=ComponentUtil.toComponentPro(cfc);
1332                                                            String cfcName=Caster.toString(m.get(CFC,null),null);
1333                                                            if(cfcp.equalTo(cfcName)){
1334                                                                    _prop=_props[i];
1335                                                            }
1336                                                    }
1337                                            }
1338                                    }
1339                                    str=createM2MFKColumnName(engine, other, _prop, _propColl);
1340                            }
1341                    }
1342                    setColumn(engine,doc, m2m, str);
1343                    
1344                    // not-found
1345                    Boolean b=toBoolean(engine,cfc,meta, "missingrowignored");
1346            if(b!=null && b.booleanValue()) m2m.setAttribute("not-found", "ignore");
1347            
1348            // property-ref
1349                    str=toString(engine,cfc,prop,meta,"mappedby");
1350                    if(!StringUtil.isEmpty(str,true)) m2m.setAttribute("property-ref", str);
1351                    
1352                    // foreign-key
1353                    str=toString(engine,cfc,prop,meta,"foreignKeyName");
1354                    if(StringUtil.isEmpty(str,true)) str=toString(engine,cfc,prop,meta,"foreignKey");
1355                    if(!StringUtil.isEmpty(str,true)) m2m.setAttribute("foreign-key", str);
1356            }
1357            
1358            private static boolean setLink(HibernateORMEngine engine,Component cfc,Property prop,Element el, Struct meta, ORMConfiguration ormConf, boolean linkTableRequired) throws ORMException {
1359                    String str=toString(engine,cfc,prop,meta, "linktable",linkTableRequired);
1360                    
1361                    
1362                    if(!StringUtil.isEmpty(str,true)){
1363    
1364                            el.setAttribute("table", escape(engine.convertTableName(str)));
1365                    
1366                            // schema
1367                            str=toString(engine,cfc,prop,meta, "linkschema");
1368                            if(StringUtil.isEmpty(str,true)) str=ormConf.getSchema();
1369                            if(!StringUtil.isEmpty(str,true)) el.setAttribute("schema", str);
1370                            
1371                            // catalog
1372                            str=toString(engine,cfc,prop,meta, "linkcatalog");
1373                            if(StringUtil.isEmpty(str,true)) str=ormConf.getCatalog();
1374                            if(!StringUtil.isEmpty(str,true)) el.setAttribute("catalog", str);
1375                            return true;
1376                    }
1377                    return false;
1378            }
1379    
1380    
1381    
1382    
1383    
1384    
1385    
1386    
1387    
1388            private static void createXMLMappingOneToMany(Component cfc,HibernateORMEngine engine,PropertyCollection propColl,ORMConfiguration ormConf,Element clazz, PageContext pc,Property prop) throws PageException {
1389                    Element el = createXMLMappingXToMany(engine,propColl,clazz, pc, cfc,prop);
1390                    Struct meta = prop.getDynamicAttributes();
1391                    Document doc = XMLUtil.getDocument(clazz);
1392                    Element x2m;
1393                    
1394                    
1395            // order-by
1396                    String str = toString(engine,cfc,prop,meta,"orderby");
1397                    if(!StringUtil.isEmpty(str,true))el.setAttribute("order-by", str);
1398                    
1399                    // link
1400                    if(setLink(engine,cfc,prop,el,meta,ormConf,false)){
1401                            x2m = doc.createElement("many-to-many");
1402                            x2m.setAttribute("unique","true");
1403                            
1404                            str=toString(engine,cfc,prop,meta,"inversejoincolumn");
1405                            setColumn(engine,doc, x2m, str);
1406                    }
1407                    else {
1408                            x2m = doc.createElement("one-to-many");
1409                    }
1410                    el.appendChild(x2m);
1411                    
1412    
1413                    // entity-name
1414                    
1415                    setForeignEntityName(pc,engine,cfc,prop,meta,x2m,true);
1416                    
1417            }
1418    
1419            
1420    
1421            
1422            
1423            
1424            
1425            
1426            private static Element createXMLMappingXToMany(HibernateORMEngine engine,PropertyCollection propColl,Element clazz, PageContext pc,Component cfc,Property prop) throws PageException {
1427                    final Struct meta = prop.getDynamicAttributes();
1428                    Document doc = XMLUtil.getDocument(clazz);
1429                    Element el=null;
1430                    
1431                    
1432                    
1433            // collection type
1434                    String str=prop.getType();
1435                    if(StringUtil.isEmpty(str,true) || "any".equalsIgnoreCase(str) || "object".equalsIgnoreCase(str))str="array";
1436                    else str=str.trim().toLowerCase();
1437                    
1438                    Element mapKey=null;
1439                    // bag
1440                    if("array".equals(str) || "bag".equals(str)){
1441                            el = doc.createElement("bag");
1442                            
1443                    }
1444                    // map
1445                    else if("struct".equals(str) || "map".equals(str)){
1446                            el = doc.createElement("map");
1447                            
1448                            // map-key
1449                            mapKey = doc.createElement("map-key");
1450                            //el.appendChild(mapKey);
1451                            
1452                            // column
1453                            str=toString(engine,cfc,prop,meta,"structKeyColumn",true);
1454                            mapKey.setAttribute("column", formatColumn(engine,str));
1455                            
1456                            // type
1457                            str=toString(engine,cfc,prop,meta,"structKeyType");
1458                            if(!StringUtil.isEmpty(str,true))mapKey.setAttribute("type", str);
1459                            else mapKey.setAttribute("type", "string");// MUST get type dynamicly
1460                    }
1461                    else throw invalidValue(engine,cfc,prop,"collectiontype",str,"array,struct");
1462                    //throw new ORMException(engine,"invalid value ["+str+"] for attribute [collectiontype], valid values are [array,struct]");
1463                    
1464                    setBeforeJoin(clazz,el);
1465                    
1466    
1467                    
1468                    // batch-size
1469            Integer i=toInteger(engine,cfc,meta, "batchsize");
1470            if(i!=null){
1471                    if(i.intValue()>1) el.setAttribute("batch-size", Caster.toString(i.intValue()));
1472            }
1473     
1474                    // cacheUse
1475            setCacheStrategy(engine,cfc,prop,doc, meta, el);
1476            
1477            // column
1478            str=createFKColumnName(engine,cfc,prop,propColl);
1479                    
1480                    if(!StringUtil.isEmpty(str,true)){
1481                            Element key = doc.createElement("key");
1482                            el.appendChild(key);
1483                            
1484                            // column
1485                            setColumn(engine,doc,key,str);
1486                            
1487                            // property-ref
1488                            str=toString(engine,cfc,prop,meta,"mappedBy");
1489                            if(!StringUtil.isEmpty(str,true)) key.setAttribute("property-ref", str);
1490                    }
1491                    
1492            // inverse
1493                    Boolean b = toBoolean(engine,cfc,meta, "inverse");
1494            if(b!=null && b.booleanValue()) el.setAttribute("inverse", "true");
1495            
1496                    
1497                    
1498                    // mutable 
1499                    b = toBoolean(engine,cfc,meta, "readonly");
1500            if(b!=null && b.booleanValue()) el.setAttribute("mutable", "false");
1501                    
1502                    // optimistic-lock
1503                    b=toBoolean(engine,cfc,meta, "optimisticlock");
1504            if(b!=null && !b.booleanValue()) el.setAttribute("optimistic-lock", "false");
1505            
1506                    // where
1507                    str=toString(engine,cfc,prop,meta,"where");
1508                    if(!StringUtil.isEmpty(str,true)) el.setAttribute("where", str);
1509            
1510                    // add map key
1511            if(mapKey!=null)el.appendChild(mapKey);
1512            
1513            
1514                    createXMLMappingXToX(engine,el, pc,cfc,prop,meta);
1515                    
1516                    return el;
1517            }
1518            
1519            
1520            
1521            private static String createFKColumnName(HibernateORMEngine engine, Component cfc, Property prop, PropertyCollection propColl) throws PageException {
1522                    
1523                    
1524                    // fk column from local defintion
1525                    String str=prop==null?null:toString(engine,cfc,prop,prop.getDynamicAttributes(),"fkcolumn");
1526                    if(!StringUtil.isEmpty(str))
1527                            return str;
1528                    
1529                    // no local defintion, get from Foreign enity
1530                    Struct meta = prop.getDynamicAttributes();
1531                    String type=toString(engine,cfc,prop,meta,"fieldtype",false);
1532                    String otherType;
1533                    if("many-to-one".equalsIgnoreCase(type))                otherType="one-to-many";
1534                    else if("one-to-many".equalsIgnoreCase(type))   otherType="many-to-one";
1535                    else return createM2MFKColumnName(engine, cfc, prop, propColl);
1536                    
1537                    String feName = toString(engine,cfc,prop,meta,"cfc",true);
1538                    ComponentPro feCFC=(ComponentPro) engine.getEntityByCFCName(feName, false);
1539                    Property[] feProps = feCFC.getProperties(true);
1540                    
1541                    Property p;
1542                    ComponentPro _cfc;
1543                    for(int i=0;i<feProps.length;i++){
1544                            p=feProps[i];
1545    
1546                            // compare fieldType
1547                            str=toString(engine,feCFC,p,p.getDynamicAttributes(),"fieldtype",false);
1548                            if(!otherType.equalsIgnoreCase(str)) continue;
1549                            
1550                            // compare cfc
1551                            str=toString(engine,feCFC,p,p.getDynamicAttributes(),"cfc",false);
1552                            if(StringUtil.isEmpty(str)) continue;
1553                            _cfc=(ComponentPro) engine.getEntityByCFCName(str, false);
1554                            if(_cfc==null || !_cfc.equals(cfc))continue;
1555                            
1556                            // get fkcolumn
1557                            str=toString(engine,_cfc,p,p.getDynamicAttributes(),"fkcolumn");
1558                            if(!StringUtil.isEmpty(str)) return str;
1559                            
1560                            
1561                    }
1562                    throw new ORMException(engine, "cannot terminate forgein key column name");
1563            }
1564            
1565            
1566            private static String createM2MFKColumnName(HibernateORMEngine engine, Component cfc, Property prop, PropertyCollection propColl) throws ORMException {
1567                    
1568                    String str=prop==null?null:toString(engine,cfc,prop,prop.getDynamicAttributes(),"fkcolumn");
1569                    if(StringUtil.isEmpty(str)){
1570                            Property[] ids = getIds(engine,cfc,propColl);
1571                            if(ids.length==1) {
1572                                    str=toString(engine,cfc,ids[0],ids[0].getDynamicAttributes(),"column");
1573                            if(StringUtil.isEmpty(str,true)) str=ids[0].getName();
1574                            }
1575                            else if(prop!=null)str=toString(engine,cfc,prop,prop.getDynamicAttributes(),"fkcolumn",true);
1576                            else
1577                                    throw new ORMException(engine, "cannot terminate forgein key column name");
1578                            
1579                            str=HibernateCaster.getEntityName(cfc)+"_"+str;
1580                    }
1581            return str;
1582            }
1583    
1584            private static void setForeignEntityName(PageContext pc,HibernateORMEngine engine,Component cfc,Property prop, Struct meta, Element el, boolean cfcRequired) throws PageException {
1585                    // entity
1586                    String str=cfcRequired?null:toString(engine,cfc,prop,meta,"entityName");
1587                    if(!StringUtil.isEmpty(str,true)) {
1588                            el.setAttribute("entity-name", str);
1589                    }
1590                    else {
1591                            // cfc
1592                            //createFKColumnName(engine, cfc, prop, propColl);
1593                            
1594                            str = toString(engine,cfc,prop,meta,"cfc",cfcRequired);
1595                            if(!StringUtil.isEmpty(str,true)){
1596                                    Component _cfc=engine.getEntityByCFCName(str, false);
1597                                    str=HibernateCaster.getEntityName(_cfc);
1598                                    el.setAttribute("entity-name", str);
1599                            }
1600                    }
1601            }
1602    
1603    
1604    
1605    
1606    
1607    
1608    
1609    
1610    
1611            private static void setCacheStrategy(HibernateORMEngine engine,Component cfc,Property prop,Document doc,Struct meta, Element el) throws ORMException {
1612                    String strategy = toString(engine,cfc,prop,meta,"cacheuse");
1613                    
1614                    if(!StringUtil.isEmpty(strategy,true)){
1615                            strategy=strategy.trim().toLowerCase();
1616                            if("read-only".equals(strategy) || "nonstrict-read-write".equals(strategy) || "read-write".equals(strategy) || "transactional".equals(strategy)){
1617                                    Element cache = doc.createElement("cache");
1618                                    XMLUtil.setFirst(el, cache);
1619                                    el.appendChild(cache);
1620                                    cache.setAttribute("usage", strategy);
1621                                    String name = toString(engine,cfc,prop,meta,"cacheName");
1622                                    if(!StringUtil.isEmpty(name,true)){
1623                                            cache.setAttribute("region", name);
1624                                    }
1625                            }       
1626                            else
1627                                    throw new HibernateException(engine,cfc,"invalid value ["+strategy+"] for attribute [cacheuse], valid values are [read-only,nonstrict-read-write,read-write,transactional]");
1628                    }
1629                    
1630            }
1631    
1632            
1633    
1634    
1635    
1636    
1637    
1638            private static void setColumn(HibernateORMEngine engine,Document doc, Element el, String columnValue) throws PageException {
1639                    if(StringUtil.isEmpty(columnValue,true)) return;
1640                    
1641                    String[] arr = List.toStringArray(List.listToArray(columnValue, ','));
1642                    if(arr.length==1){
1643                            el.setAttribute("column", formatColumn(engine,arr[0]));
1644                    }
1645                    else {
1646                            Element column;
1647                            for(int i=0;i<arr.length;i++){
1648                                    column=doc.createElement("column");
1649                                    el.appendChild(column);
1650                                    column.setAttribute("name", formatColumn(engine,arr[i]));
1651                            }
1652                    }
1653            }
1654    
1655    
1656    
1657    
1658    
1659    
1660    
1661    
1662    
1663            private static void createXMLMappingManyToOne(Element clazz, PageContext pc,Component cfc,Property prop, HibernateORMEngine engine, PropertyCollection propColl) throws PageException {
1664                    Struct meta = prop.getDynamicAttributes();
1665                    Boolean b;
1666                    
1667                    Document doc = XMLUtil.getDocument(clazz);
1668                    clazz=getJoin(clazz);
1669                    
1670                    Element m2o = doc.createElement("many-to-one");
1671                    clazz.appendChild(m2o);
1672                    
1673                    // columns
1674                    String linktable = toString(engine,cfc,prop,meta,"linktable");
1675                    String _columns;
1676                    if(!StringUtil.isEmpty(linktable,true)) _columns=toString(engine,cfc,prop,meta,"inversejoincolumn");
1677                    else _columns=createFKColumnName(engine, cfc, prop, propColl);//toString(engine,cfc,prop,meta,"fkcolumn");
1678                    setColumn(engine,doc, m2o, _columns);
1679                    
1680                    // cfc
1681                    setForeignEntityName(pc,engine,cfc,prop,meta,m2o,true);
1682                    
1683                    // column
1684                    //String str=toString(prop,meta,"column",true);
1685                    //m2o.setAttribute("column", str);
1686                    
1687                    // insert
1688                    b=toBoolean(engine,cfc,meta, "insert");
1689            if(b!=null && !b.booleanValue()) m2o.setAttribute("insert", "false");
1690                    
1691            // update
1692                    b=toBoolean(engine,cfc,meta, "update");
1693            if(b!=null && !b.booleanValue()) m2o.setAttribute("update", "false");
1694                    
1695            // property-ref
1696                    String str=toString(engine,cfc,prop,meta,"mappedBy");
1697                    if(!StringUtil.isEmpty(str,true)) m2o.setAttribute("property-ref", str);
1698    
1699            // update
1700                    b=toBoolean(engine,cfc,meta, "unique");
1701            if(b!=null && b.booleanValue()) m2o.setAttribute("unique", "true");
1702    
1703            // not-null
1704                    b=toBoolean(engine,cfc,meta, "notnull");
1705            if(b!=null && b.booleanValue()) m2o.setAttribute("not-null", "true");
1706                    
1707            // optimistic-lock
1708                    b=toBoolean(engine,cfc,meta, "optimisticLock");
1709            if(b!=null && !b.booleanValue()) m2o.setAttribute("optimistic-lock", "false");
1710            
1711            // not-found
1712                    b=toBoolean(engine,cfc,meta, "missingRowIgnored");
1713            if(b!=null && b.booleanValue()) m2o.setAttribute("not-found", "ignore");
1714            
1715            // index
1716                    str=toString(engine,cfc,prop,meta,"index");
1717                    if(!StringUtil.isEmpty(str,true)) m2o.setAttribute("index", str);
1718            
1719            // unique-key
1720                    str=toString(engine,cfc,prop,meta,"uniqueKeyName");
1721                    if(StringUtil.isEmpty(str,true))str=toString(engine,cfc,prop,meta,"uniqueKey");
1722                    if(!StringUtil.isEmpty(str,true)) m2o.setAttribute("unique-key", str);
1723                    
1724                    // foreign-key
1725                    str=toString(engine,cfc,prop,meta,"foreignKeyName");
1726                    if(StringUtil.isEmpty(str,true)) str=toString(engine,cfc,prop,meta,"foreignKey");
1727                    if(!StringUtil.isEmpty(str,true)) m2o.setAttribute("foreign-key", str);
1728    
1729                    // access
1730                    str=toString(engine,cfc,prop,meta,"access");
1731                    if(!StringUtil.isEmpty(str,true)) m2o.setAttribute("access", str);
1732                    
1733            createXMLMappingXToX(engine,m2o, pc,cfc,prop,meta);
1734            
1735            }
1736            
1737            
1738            
1739            
1740            
1741            
1742            
1743            
1744            private static String formatColumn(HibernateORMEngine engine,String name) {
1745            name=name.trim();
1746                    return escape(engine.convertColumnName(name));
1747        }
1748            
1749            /*
1750    
1751     
1752            <cfproperty 
1753    cfc="Referenced_CFC_Name" 
1754    linktable="Link table name" 
1755    linkcatalog="Catalog for the link table" 
1756    linkschema="Schema for the link table" 
1757    fkcolumn="Foreign Key column name" 
1758    inversejoincolumn="Column name or comma-separated list of primary key columns" 
1759    
1760    
1761    >
1762    
1763            */
1764            private static void createXMLMappingXToX(HibernateORMEngine engine,Element x2x, PageContext pc, Component cfc,Property prop, Struct meta) throws ORMException {
1765                    x2x.setAttribute("name",prop.getName());
1766                    
1767                    // cascade
1768                    String str=toString(engine,cfc,prop,meta,"cascade");
1769                    if(!StringUtil.isEmpty(str,true)) x2x.setAttribute("cascade", str);
1770                    
1771                    // fetch
1772                    str=toString(engine,cfc,prop,meta,"fetch");
1773                    if(!StringUtil.isEmpty(str,true)) {
1774                            str=str.trim().toLowerCase();
1775                            if("join".equals(str) || "select".equals(str))
1776                                    x2x.setAttribute("fetch", str);
1777                            else
1778                                    throw invalidValue(engine,cfc,prop,"fetch",str,"join,select");
1779                            //throw new ORMException(engine,"invalid value ["+str+"] for attribute [fetch], valid values are [join,select]");
1780                    }
1781                    
1782                    // lazy
1783                    setLazy(engine,cfc,prop,meta,x2x);
1784                    
1785            }
1786    
1787    
1788    
1789            
1790    
1791            private static void setLazy(HibernateORMEngine engine, Component cfc,Property prop, Struct meta, Element x2x) throws ORMException {
1792                    String str = toString(engine,cfc,prop,meta, "lazy");
1793                    if(!StringUtil.isEmpty(str,true)){
1794                            str=str.trim();
1795                            String name=x2x.getNodeName();
1796                            Boolean b = Caster.toBoolean(str,null);
1797                            
1798                            // <!ATTLIST many-to-one lazy (false|proxy|no-proxy) #IMPLIED>
1799                            // <!ATTLIST one-to-one lazy (false|proxy|no-proxy) #IMPLIED>
1800                            if("many-to-one".equals(name) || "one-to-one".equals(name)) {
1801                                    if(b!=null) x2x.setAttribute("lazy", b.booleanValue()?"proxy":"false");
1802                                    else if("proxy".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "proxy");
1803                                    else if("no-proxy".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "no-proxy");
1804                                    else throw invalidValue(engine,cfc,prop,"lazy",str,"true,false,proxy,no-proxy");
1805                            }
1806                            
1807    
1808                            // <!ATTLIST many-to-many lazy (false|proxy) #IMPLIED>
1809                            // <!ATTLIST key-many-to-one lazy (false|proxy) #IMPLIED>
1810                            else if("many-to-many".equals(name) || "key-many-to-one".equals(name)) {
1811                                    if(b!=null) x2x.setAttribute("lazy", b.booleanValue()?"proxy":"false");
1812                                    else if("proxy".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "proxy");
1813                                    throw invalidValue(engine,cfc,prop,"lazy",str,"true,false,proxy");
1814                                    
1815                            }
1816                            
1817                            else {
1818                                    if(b!=null)     x2x.setAttribute("lazy", b.booleanValue()?"true":"false");
1819                                    else if("extra".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "extra");
1820                                    else  throw invalidValue(engine,cfc,prop,"lazy",str,"true,false,extra");
1821                            }
1822                    }
1823            }
1824    
1825            private static void createXMLMappingTimestamp(HibernateORMEngine engine,Element clazz, PageContext pc,Component cfc,Property prop) throws PageException {
1826                    Struct meta = prop.getDynamicAttributes();
1827                    String str;
1828                    Boolean b;
1829                    
1830    
1831                    Document doc = XMLUtil.getDocument(clazz);
1832                    Element timestamp = doc.createElement("timestamp");
1833                    clazz.appendChild(timestamp);
1834                    
1835                    timestamp.setAttribute("name",prop.getName());
1836                    
1837                     // access
1838                    str=toString(engine,cfc,prop,meta,"access");
1839                    if(!StringUtil.isEmpty(str,true))timestamp.setAttribute("access", str);
1840                    
1841                    // column
1842                    str=toString(engine,cfc,prop,meta,"column");
1843                    if(StringUtil.isEmpty(str,true)) str=prop.getName();
1844                    timestamp.setAttribute("column",formatColumn(engine,str));
1845    
1846                    // generated
1847                    b=toBoolean(engine,cfc,meta, "generated");
1848            if(b!=null) timestamp.setAttribute("generated", b.booleanValue()?"always":"never");
1849            
1850            // source
1851            str=toString(engine,cfc,prop,meta,"source");
1852                    if(!StringUtil.isEmpty(str,true)) {
1853                            str=str.trim().toLowerCase();
1854                            if("db".equals(str) || "vm".equals(str))
1855                                    timestamp.setAttribute("source", str);
1856                            else 
1857                                    throw invalidValue(engine,cfc,prop,"source",str,"db,vm");
1858                    }
1859                    
1860                    // unsavedValue
1861            str=toString(engine,cfc,prop,meta,"unsavedValue");
1862                    if(!StringUtil.isEmpty(str,true)) {
1863                            str=str.trim().toLowerCase();
1864                            if("null".equals(str) || "undefined".equals(str))
1865                                    timestamp.setAttribute("unsaved-value", str);
1866                            else 
1867                                    throw invalidValue(engine,cfc,prop,"unsavedValue",str,"null, undefined");
1868                                    //throw new ORMException(engine,"invalid value ["+str+"] for attribute [unsavedValue], valid values are [null, undefined]");
1869                    }
1870            }
1871    
1872            
1873            private static ORMException invalidValue(HibernateORMEngine engine,Component cfc,Property prop, String attrName, String invalid, String valid) {
1874                    String owner = prop.getOwnerName();
1875                    if(StringUtil.isEmpty(owner))return new HibernateException(engine,cfc,"invalid value ["+invalid+"] for attribute ["+attrName+"] of property ["+prop.getName()+"], valid values are ["+valid+"]");
1876                    return new HibernateException(engine,cfc,"invalid value ["+invalid+"] for attribute ["+attrName+"] of property ["+prop.getName()+"] of Component ["+List.last(owner,'.')+"], valid values are ["+valid+"]");
1877            }
1878    
1879    
1880    
1881    
1882    
1883    
1884            private static void createXMLMappingVersion(HibernateORMEngine engine,Element clazz, PageContext pc,Component cfc,Property prop) throws PageException {
1885                    Struct meta = prop.getDynamicAttributes();
1886                    
1887                    Document doc = XMLUtil.getDocument(clazz);
1888                    Element version = doc.createElement("version");
1889                    clazz.appendChild(version);
1890                    
1891                    
1892                    version.setAttribute("name",prop.getName());
1893                    
1894                    // column
1895                    String str = toString(engine,cfc,prop,meta,"column");
1896                    if(StringUtil.isEmpty(str,true)) str=prop.getName();
1897                    version.setAttribute("column",formatColumn(engine,str));
1898                    
1899                     // access
1900            str=toString(engine,cfc,prop,meta,"access");
1901                    if(!StringUtil.isEmpty(str,true))version.setAttribute("access", str);
1902                    
1903                    // generated
1904                    Object o=meta.get(GENERATED,null);
1905                    if(o!=null){
1906                            Boolean b = Caster.toBoolean(o,null); 
1907                            str=null;
1908                            if(b!=null) {
1909                                    str=b.booleanValue()?"always":"never";
1910                            }
1911                            else {
1912                                    str=Caster.toString(o,null);
1913                                    if("always".equalsIgnoreCase(str))str="always";
1914                                    else if("never".equalsIgnoreCase(str))str="never";
1915                                    else throw invalidValue(engine,cfc,prop,"generated",o.toString(),"true,false,always,never");
1916                                    //throw new ORMException(engine,"invalid value ["+o+"] for attribute [generated] of property ["+prop.getName()+"], valid values are [true,false,always,never]");
1917                            }
1918                            version.setAttribute( "generated", str);
1919                    }
1920                    
1921            // insert
1922            Boolean b = toBoolean(engine,cfc,meta, "insert");
1923            if(b!=null && !b.booleanValue()) version.setAttribute("insert", "false");
1924            
1925            // type
1926            String typeName="dataType";
1927                    str=toString(engine,cfc,prop,meta,typeName);
1928                    if(StringUtil.isEmpty(str,true)){
1929                            typeName="ormType";
1930                            str=toString(engine,cfc,prop,meta,typeName);
1931                    }
1932                    if(!StringUtil.isEmpty(str,true)) {
1933                            str=str.trim().toLowerCase();
1934                            if("int".equals(str) || "integer".equals(str))
1935                                    version.setAttribute("type", "integer");
1936                            else if("long".equals(str))
1937                                    version.setAttribute("type", "long");
1938                            else if("short".equals(str))
1939                                    version.setAttribute("type", "short");
1940                            else 
1941                                    throw invalidValue(engine,cfc,prop,typeName,str,"int,integer,long,short");
1942                            //throw new ORMException(engine,"invalid value ["+str+"] for attribute ["+typeName+"], valid values are [int,integer,long,short]");
1943                    }
1944                    else 
1945                            version.setAttribute("type", "integer");
1946                    
1947                    // unsavedValue
1948            str=toString(engine,cfc,prop,meta,"unsavedValue");
1949                    if(!StringUtil.isEmpty(str,true)) {
1950                            str=str.trim().toLowerCase();
1951                            if("null".equals(str) || "negative".equals(str) || "undefined".equals(str))
1952                                    version.setAttribute("unsaved-value", str);
1953                            else 
1954                                    throw invalidValue(engine,cfc,prop,"unsavedValue",str,"null, negative, undefined");
1955                            //throw new ORMException(engine,"invalid value ["+str+"] for attribute [unsavedValue], valid values are [null, negative, undefined]");
1956                    }
1957            }   
1958            
1959            
1960            public static Struct convertToSimpleMap(String paramsStr) {
1961                    paramsStr=paramsStr.trim();
1962            if(!StringUtil.startsWith(paramsStr, '{') || !StringUtil.endsWith(paramsStr, '}'))
1963                    return null;
1964                    
1965                    paramsStr = paramsStr.substring(1, paramsStr.length() - 1);
1966                    String items[] = List.listToStringArray(paramsStr, ','); 
1967                    
1968                    Struct params=new StructImpl();
1969                    String arr$[] = items;
1970                    int index;
1971            for(int i = 0; i < arr$.length; i++) {
1972                String pair = arr$[i];
1973                index = pair.indexOf('=');
1974                if(index == -1) return null;
1975                
1976                params.setEL(
1977                            KeyImpl.init(deleteQuotes(pair.substring(0, index).trim()).trim()), 
1978                            deleteQuotes(pair.substring(index + 1).trim()));
1979            }
1980    
1981            return params;
1982        }
1983            
1984            private static String deleteQuotes(String str)  {
1985            if(StringUtil.isEmpty(str,true))return "";
1986            char first=str.charAt(0);
1987            if((first=='\'' || first=='"') && StringUtil.endsWith(str, first))
1988                    return str.substring(1, str.length() - 1);
1989            return str;
1990        }
1991            
1992            
1993            private static String toString(HibernateORMEngine engine,Component cfc,Property prop,Struct sct, String key) throws ORMException {
1994                    return toString(engine,cfc,prop,sct, key, false);
1995            }
1996    
1997            private static String toString(HibernateORMEngine engine,Component cfc,Property prop,Struct sct, String key, boolean throwErrorWhenNotExist) throws ORMException {
1998                    return toString(engine,cfc,prop,sct, KeyImpl.init(key), throwErrorWhenNotExist);
1999            }
2000            
2001            private static String toString(HibernateORMEngine engine,Component cfc,Property prop,Struct sct, Collection.Key key, boolean throwErrorWhenNotExist) throws ORMException {
2002                    Object value = sct.get(key,null);
2003                    if(value==null) {
2004                            if(throwErrorWhenNotExist){
2005                                    if(prop==null)throw new HibernateException(engine,cfc,"attribute ["+key+"] is required");
2006                                    throw new HibernateException(engine,cfc,"attribute ["+key+"] of property ["+prop.getName()+"] of Component ["+_getCFCName(prop)+"] is required");
2007                            }
2008                            return null;
2009                    }
2010                    
2011                    String str=Caster.toString(value,null);
2012                    if(str==null) {
2013                            if(prop==null)
2014                                    throw new HibernateException(engine,cfc,"invalid type ["+Caster.toTypeName(value)+"] for attribute ["+key+"], value must be a string");
2015                            throw new HibernateException(engine,cfc,"invalid type ["+Caster.toTypeName(value)+"] for attribute ["+key+"] of property ["+prop.getName()+"] of Component ["+_getCFCName(prop)+"], value must be a string");
2016                            }
2017                    return str;
2018            }
2019            
2020            private static String _getCFCName(Property prop) {
2021                    String owner = prop.getOwnerName();
2022                    return List.last(owner,'.');
2023            }
2024            
2025            
2026            
2027            
2028            private static Boolean toBoolean(HibernateORMEngine engine,Component cfc,Struct sct, String key) throws ORMException {
2029                    Object value = sct.get(KeyImpl.init(key),null);
2030                    if(value==null) return null;
2031                    
2032                    Boolean b=Caster.toBoolean(value,null);
2033                    if(b==null) throw new HibernateException(engine,cfc,"invalid type ["+Caster.toTypeName(value)+"] for attribute ["+key+"], value must be a boolean");
2034                    return b;
2035            }
2036    
2037            private static Integer toInteger(HibernateORMEngine engine,Component cfc,Struct sct, String key) throws ORMException {
2038                    Object value = sct.get(KeyImpl.init(key),null);
2039                    if(value==null) return null;
2040                    
2041                    Integer i=Caster.toInteger(value,null);
2042                    if(i==null) throw new HibernateException(engine,cfc,"invalid type ["+Caster.toTypeName(value)+"] for attribute ["+key+"], value must be a numeric value");
2043                    return i;
2044            }
2045            
2046            
2047    }
2048            
2049            class PropertyCollection {
2050                    private Property[] properties;
2051                    private String tableName;
2052                    public PropertyCollection(String tableName,Property[] properties) {
2053                            this.tableName=tableName;
2054                            this.properties=properties;
2055                    }
2056                    public PropertyCollection(String tableName, java.util.List<Property> properties) {
2057                            this.tableName=tableName;
2058                            this.properties=properties.toArray(new Property[properties.size()]);
2059                    }
2060                    public Property[] getProperties() {
2061                            return properties;
2062                    }
2063                    public String getTableName() {
2064                            return tableName;
2065                    }
2066    
2067            }