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