001    package railo.runtime.orm.hibernate;
002    
003    import java.sql.DatabaseMetaData;
004    import java.sql.ResultSet;
005    import java.util.ArrayList;
006    import java.util.HashSet;
007    import java.util.Iterator;
008    import java.util.Set;
009    
010    import org.hibernate.HibernateException;
011    import org.hibernate.metadata.ClassMetadata;
012    import org.hibernate.type.Type;
013    
014    import railo.commons.lang.StringUtil;
015    import railo.runtime.ComponentPro;
016    import railo.runtime.component.Property;
017    import railo.runtime.db.DatasourceConnection;
018    import railo.runtime.exp.PageException;
019    import railo.runtime.op.Caster;
020    import railo.runtime.orm.ORMException;
021    import railo.runtime.type.Array;
022    import railo.runtime.type.Collection.Key;
023    import railo.runtime.type.KeyImpl;
024    import railo.runtime.type.List;
025    import railo.runtime.type.Struct;
026    import railo.runtime.type.StructImpl;
027    
028    
029    public class HibernateUtil {
030    
031            public static final short FIELDTYPE_ID=0;
032            public static final short FIELDTYPE_COLUMN=1;
033            public static final short FIELDTYPE_TIMESTAMP=2;
034            public static final short FIELDTYPE_RELATION=4;
035            public static final short FIELDTYPE_VERSION=8;
036            public static final short FIELDTYPE_COLLECTION=16;
037            
038            private static final String KEYWORDS="absolute,access,accessible,action,add,after,alias,all,allocate,allow,alter,analyze,and,any,application,are,array,as,asc,asensitive,assertion,associate,asutime,asymmetric,at,atomic,audit,authorization,aux,auxiliary,avg,backup,before,begin,between,bigint,binary,bit,bit_length,blob,boolean,both,breadth,break,browse,bufferpool,bulk,by,cache,call,called,capture,cardinality,cascade,cascaded,case,cast,catalog,ccsid,change,char,char_length,character,character_length,check,checkpoint,clob,close,cluster,clustered,coalesce,collate,collation,collection,collid,column,comment,commit,compress,compute,concat,condition,connect,connection,constraint,constraints,constructor,contains,containstable,continue,convert,corresponding,count,count_big,create,cross,cube,current,current_date,current_default_transform_group,current_lc_ctype,current_path,current_role,current_server,current_time,current_timestamp,current_timezone,current_transform_group_for_type,current_user,cursor,cycle,data,database,databases,date,day,day_hour,day_microsecond,day_minute,day_second,days,db2general,db2genrl,db2sql,dbcc,dbinfo,deallocate,dec,decimal,declare,default,defaults,deferrable,deferred,delayed,delete,deny,depth,deref,desc,describe,descriptor,deterministic,diagnostics,disallow,disconnect,disk,distinct,distinctrow,distributed,div,do,domain,double,drop,dsnhattr,dssize,dual,dummy,dump,dynamic,each,editproc,else,elseif,enclosed,encoding,end,end-exec,end-exec1,endexec,equals,erase,errlvl,escape,escaped,except,exception,excluding,exclusive,exec,execute,exists,exit,explain,external,extract,false,fenced,fetch,fieldproc,file,fillfactor,filter,final,first,float,float4,float8,for,force,foreign,found,free,freetext,freetexttable,from,full,fulltext,function,general,generated,get,get_current_connection,global,go,goto,grant,graphic,group,grouping,handler,having,high_priority,hold,holdlock,hour,hour_microsecond,hour_minute,hour_second,hours,identified,identity,identity_insert,identitycol,if,ignore,immediate,in,including,increment,index,indicator,infile,inherit,initial,initially,inner,inout,input,insensitive,insert,int,int1,int2,int3,int4,int8,integer,integrity,intersect,interval,into,is,isobid,isolation,iterate,jar,java,join,key,keys,kill,language,large,last,lateral,leading,leave,left,level,like,limit,linear,lineno,lines,linktype,load,local,locale,localtime,localtimestamp,locator,locators,lock,lockmax,locksize,long,longblob,longint,longtext,loop,low_priority,lower,ltrim,map,master_ssl_verify_server_cert,match,max,maxextents,maxvalue,mediumblob,mediumint,mediumtext,method,microsecond,microseconds,middleint,min,minus,minute,minute_microsecond,minute_second,minutes,minvalue,mlslabel,mod,mode,modifies,modify,module,month,months,names,national,natural,nchar,nclob,new,new_table,next,no,no_write_to_binlog,noaudit,nocache,nocheck,nocompress,nocycle,nodename,nodenumber,nomaxvalue,nominvalue,nonclustered,none,noorder,not,nowait,null,nullif,nulls,number,numeric,numparts,nvarchar,obid,object,octet_length,of,off,offline,offsets,old,old_table,on,online,only,open,opendatasource,openquery,openrowset,openxml,optimization,optimize,option,optionally,or,order,ordinality,out,outer,outfile,output,over,overlaps,overriding,package,pad,parameter,part,partial,partition,path,pctfree,percent,piecesize,plan,position,precision,prepare,preserve,primary,print,prior,priqty,privileges,proc,procedure,program,psid,public,purge,queryno,raiserror,range,raw,read,read_write,reads,readtext,real,reconfigure,recovery,recursive,ref,references,referencing,regexp,relative,release,rename,repeat,replace,replication,require,resignal,resource,restart,restore,restrict,result,result_set_locator,return,returns,revoke,right,rlike,role,rollback,rollup,routine,row,rowcount,rowguidcol,rowid,rownum,rows,rrn,rtrim,rule,run,runtimestatistics,save,savepoint,schema,schemas,scope,scratchpad,scroll,search,second,second_microsecond,seconds,secqty,section,security,select,sensitive,separator,session,session_user,set,sets,setuser,share,show,shutdown,signal,similar,simple,size,smallint,some,source,space,spatial,specific,specifictype,sql,sql_big_result,sql_calc_found_rows,sql_small_result,sqlcode,sqlerror,sqlexception,sqlid,sqlstate,sqlwarning,ssl,standard,start,starting,state,static,statistics,stay,stogroup,stores,straight_join,style,subpages,substr,substring,successful,sum,symmetric,synonym,sysdate,sysfun,sysibm,sysproc,system,system_user,table,tablespace,temporary,terminated,textsize,then,time,timestamp,timezone_hour,timezone_minute,tinyblob,tinyint,tinytext,to,top,trailing,tran,transaction,translate,translation,treat,trigger,trim,true,truncate,tsequal,type,uid,under,undo,union,unique,unknown,unlock,unnest,unsigned,until,update,updatetext,upper,usage,use,user,using,utc_date,utc_time,utc_timestamp,validate,validproc,value,values,varbinary,varchar,varchar2,varcharacter,variable,variant,varying,vcat,view,volumes,waitfor,when,whenever,where,while,window,with,within,without,wlm,work,write,writetext,xor,year,year_month,zerofill,zone";
039            private static final Set<String> keywords=new HashSet<String>();
040            private static final Key FIELDTYPE = KeyImpl.intern("fieldtype");
041            static {
042                    Array arr = List.listToArray(KEYWORDS, ',');
043                    Iterator<String> it = arr.valueIterator();
044                    while(it.hasNext()){
045                            keywords.add(it.next());
046                    }
047            }
048            
049            
050            public static boolean isKeyword(String word){
051                    if(word==null) return false;
052                    return keywords.contains(word.trim().toLowerCase());
053            }
054            
055            
056            public static Type getPropertyType(ClassMetadata metaData, String name) throws HibernateException {
057                    try{
058                            return  metaData.getPropertyType(name);
059                    }
060                    catch(HibernateException he){
061                            if(name.equalsIgnoreCase(metaData.getIdentifierPropertyName())) 
062                                    return metaData.getIdentifierType();
063                            
064                            String[] names = metaData.getPropertyNames();
065                            for(int i=0;i<names.length;i++){
066                                    if(names[i].equalsIgnoreCase(name))
067                                            return metaData.getPropertyType(names[i]);
068                            }
069                            throw he;
070                    }
071            }
072            public static Type getPropertyType(ClassMetadata metaData, String name, Type defaultValue) {
073                    try{
074                            return  metaData.getPropertyType(name);
075                    }
076                    catch(HibernateException he){
077                            if(name.equalsIgnoreCase(metaData.getIdentifierPropertyName())) 
078                                    return metaData.getIdentifierType();
079                            
080                            String[] names = metaData.getPropertyNames();
081                            for(int i=0;i<names.length;i++){
082                                    if(names[i].equalsIgnoreCase(name))
083                                            return metaData.getPropertyType(names[i]);
084                            }
085                            return defaultValue;
086                    }
087            }
088            
089            public static String validateColumnName(ClassMetadata metaData, String name) throws ORMException {
090                    String res = validateColumnName(metaData, name,null);
091                    if(res!=null) return res;
092                    throw new ORMException("invalid name, there is no property with name ["+name+"] in the entity ["+metaData.getEntityName()+"]",
093                                    "valid properties names are ["+railo.runtime.type.List.arrayToList(metaData.getPropertyNames(), ", ")+"]");
094                    
095            }
096            
097    
098            public static String validateColumnName(ClassMetadata metaData, String name, String defaultValue) {
099                    if(name.equalsIgnoreCase(metaData.getIdentifierPropertyName())) 
100                            return metaData.getIdentifierPropertyName();
101                    
102                    String[] names = metaData.getPropertyNames();
103                    for(int i=0;i<names.length;i++){
104                            if(names[i].equalsIgnoreCase(name))
105                                    return names[i];
106                    }
107                    return defaultValue;
108            }
109            
110            // 
111            
112            public static Property[] createPropertiesFromTable(DatasourceConnection dc, String tableName) throws ORMException, PageException {
113                    Struct properties = new StructImpl();
114                    try {
115                            DatabaseMetaData md = dc.getConnection().getMetaData();
116                            String dbName=dc.getDatasource().getDatabase();
117                            String name;
118                            
119                            
120                            // get all columns
121                            ResultSet res = md.getColumns(dbName, null, tableName, null);
122                            Property p;
123                            while(res.next()) {
124                                    name=res.getString("COLUMN_NAME");
125                                    p=new Property();
126                                    p.setName(name);
127                                    p.setType(res.getString("TYPE_NAME"));
128                                    properties.setEL(name, p);
129                            }
130                            
131                            // ids
132                            res = md.getPrimaryKeys(null, null, tableName);
133                            while(res.next()) {
134                                    name=res.getString("COLUMN_NAME");
135                                    p=(Property) properties.get(name,null);
136                                    if(p!=null) p.getDynamicAttributes().setEL("fieldtype", "id");
137                            }
138                            
139                            // MUST foreign-key relation
140                    
141                    }
142                    catch(Throwable t){
143                            return new Property[0];
144                    }
145                    
146                    Iterator it = properties.valueIterator();
147                    Property[] rtn=new Property[properties.size()];
148                    for(int i=0;i<rtn.length;i++){
149                            rtn[i]=(Property) it.next();
150                    }
151                    
152            return rtn;
153            }
154    
155    
156            public static Property[] getProperties(ComponentPro component,int fieldType, Property[] defaultValue) {
157                    Property[] props = component.getProperties(true);
158                    java.util.List<Property> rtn=new ArrayList<Property>();
159                    
160                    if(props!=null) {
161                            for(int i=0;i<props.length;i++){
162                                    if(fieldType==getFieldType(props[i],FIELDTYPE_COLUMN))
163                                            rtn.add(props[i]);
164                            }
165                    }
166                    return rtn.toArray(new Property[rtn.size()]);
167            }
168    
169    
170            private static int getFieldType(Property property, int defaultValue) {
171                    return getFieldType(Caster.toString(property.getDynamicAttributes().get(FIELDTYPE, null),null),defaultValue);
172                            
173            }
174            
175            private static int getFieldType(String fieldType, int defaultValue) {
176                    if(StringUtil.isEmpty(fieldType,true)) return defaultValue;
177                    fieldType=fieldType.trim().toLowerCase();
178                    
179    
180                    if("id".equals(fieldType)) return FIELDTYPE_ID;
181                    if("column".equals(fieldType)) return FIELDTYPE_COLUMN;
182                    if("timestamp".equals(fieldType)) return FIELDTYPE_TIMESTAMP;
183                    if("relation".equals(fieldType)) return FIELDTYPE_RELATION;
184                    if("version".equals(fieldType)) return FIELDTYPE_VERSION;
185                    if("collection".equals(fieldType)) return FIELDTYPE_COLLECTION;
186                    return defaultValue;
187            }
188            
189    }