001 package railo.runtime.orm.hibernate; 002 003 import java.io.BufferedReader; 004 import java.io.IOException; 005 import java.sql.SQLException; 006 import java.sql.Statement; 007 import java.util.ArrayList; 008 import java.util.HashSet; 009 import java.util.Iterator; 010 import java.util.List; 011 import java.util.Map; 012 import java.util.Map.Entry; 013 import java.util.Set; 014 015 import org.hibernate.MappingException; 016 import org.hibernate.cfg.Configuration; 017 import org.hibernate.tool.hbm2ddl.SchemaExport; 018 import org.hibernate.tool.hbm2ddl.SchemaUpdate; 019 import org.w3c.dom.Document; 020 021 import railo.commons.io.IOUtil; 022 import railo.commons.io.res.Resource; 023 import railo.commons.io.res.filter.ExtensionResourceFilter; 024 import railo.commons.io.res.util.ResourceUtil; 025 import railo.commons.lang.StringUtil; 026 import railo.commons.sql.SQLUtil; 027 import railo.runtime.Component; 028 import railo.runtime.InterfacePage; 029 import railo.runtime.Mapping; 030 import railo.runtime.MappingImpl; 031 import railo.runtime.Page; 032 import railo.runtime.PageContext; 033 import railo.runtime.PageSource; 034 import railo.runtime.component.ComponentLoader; 035 import railo.runtime.config.ConfigImpl; 036 import railo.runtime.config.Constants; 037 import railo.runtime.db.DataSource; 038 import railo.runtime.db.DatasourceConnection; 039 import railo.runtime.exp.PageException; 040 import railo.runtime.listener.ApplicationContext; 041 import railo.runtime.op.Caster; 042 import railo.runtime.orm.ORMConfiguration; 043 import railo.runtime.orm.ORMException; 044 import railo.runtime.orm.ORMUtil; 045 import railo.runtime.text.xml.XMLUtil; 046 import railo.runtime.type.cfc.ComponentAccess; 047 import railo.runtime.type.util.ArrayUtil; 048 049 public class HibernateSessionFactory { 050 051 052 public static final String HIBERNATE_3_PUBLIC_ID = "-//Hibernate/Hibernate Mapping DTD 3.0//EN"; 053 public static final String HIBERNATE_3_SYSTEM_ID = "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"; 054 public static final String HIBERNATE_3_ENCODING = "UTF-8"; 055 public static final String HIBERNATE_3_DOCTYPE_DEFINITION = "<!DOCTYPE hibernate-mapping PUBLIC \""+HIBERNATE_3_PUBLIC_ID+"\" \""+HIBERNATE_3_SYSTEM_ID+"\">"; 056 057 058 public static Configuration createConfiguration(HibernateORMEngine engine,String mappings, DatasourceConnection dc, ORMConfiguration ormConf) throws SQLException, IOException, PageException { 059 /* 060 autogenmap 061 cacheconfig 062 cacheprovider 063 cfclocation 064 datasource 065 dbcreate 066 eventHandling 067 flushatrequestend 068 ormconfig 069 sqlscript 070 useDBForMapping 071 */ 072 073 // dialect 074 DataSource ds = dc.getDatasource(); 075 String dialect=null; 076 try { 077 if (Class.forName(ormConf.getDialect()) != null) { 078 dialect = ormConf.getDialect(); 079 } 080 } 081 catch (Exception e) { 082 // MZ: The dialect value could not be bound to a classname or instantiation causes an exception - ignore and use the default dialect entries 083 } 084 if (dialect == null) { 085 dialect = Dialect.getDialect(ormConf.getDialect()); 086 if(StringUtil.isEmpty(dialect)) dialect=Dialect.getDialect(ds); 087 } 088 if(StringUtil.isEmpty(dialect)) 089 throw new ORMException(engine,"A valid dialect definition inside the "+Constants.APP_CFC+"/"+Constants.CFAPP_NAME+" is missing. The dialect cannot be determinated automatically"); 090 091 // Cache Provider 092 String cacheProvider = ormConf.getCacheProvider(); 093 if(StringUtil.isEmpty(cacheProvider) || "EHCache".equalsIgnoreCase(cacheProvider)) 094 cacheProvider="org.hibernate.cache.EhCacheProvider"; 095 else if("JBossCache".equalsIgnoreCase(cacheProvider)) cacheProvider="org.hibernate.cache.TreeCacheProvider"; 096 else if("HashTable".equalsIgnoreCase(cacheProvider)) cacheProvider="org.hibernate.cache.HashtableCacheProvider"; 097 else if("SwarmCache".equalsIgnoreCase(cacheProvider)) cacheProvider="org.hibernate.cache.SwarmCacheProvider"; 098 else if("OSCache".equalsIgnoreCase(cacheProvider)) cacheProvider="org.hibernate.cache.OSCacheProvider"; 099 100 Resource cacheConfig = ormConf.getCacheConfig(); 101 Configuration configuration = new Configuration(); 102 103 // ormConfig 104 Resource conf = ormConf.getOrmConfig(); 105 if(conf!=null){ 106 try { 107 Document doc = XMLUtil.parse(XMLUtil.toInputSource(conf), null, false); 108 configuration.configure(doc); 109 } 110 catch (Throwable t) { 111 ORMUtil.printError(t, engine); 112 113 } 114 } 115 116 try{ 117 configuration.addXML(mappings); 118 } 119 catch(MappingException me){ 120 throw HibernateException.toPageException(engine, me); 121 } 122 123 configuration 124 125 // Database connection settings 126 .setProperty("hibernate.connection.driver_class", ds.getClazz().getName()) 127 .setProperty("hibernate.connection.url", ds.getDsnTranslated()) 128 .setProperty("hibernate.connection.username", ds.getUsername()) 129 .setProperty("hibernate.connection.password", ds.getPassword()) 130 //.setProperty("hibernate.connection.release_mode", "after_transaction") 131 .setProperty("hibernate.transaction.flush_before_completion", "false") 132 .setProperty("hibernate.transaction.auto_close_session", "false") 133 134 // JDBC connection pool (use the built-in) 135 //.setProperty("hibernate.connection.pool_size", "2")//MUST 136 137 138 // SQL dialect 139 .setProperty("hibernate.dialect", dialect) 140 // Enable Hibernate's current session context 141 .setProperty("hibernate.current_session_context_class", "thread") 142 143 // Echo all executed SQL to stdout 144 .setProperty("hibernate.show_sql", Caster.toString(ormConf.logSQL())) 145 .setProperty("hibernate.format_sql", Caster.toString(ormConf.logSQL())) 146 // Specifies whether secondary caching should be enabled 147 .setProperty("hibernate.cache.use_second_level_cache", Caster.toString(ormConf.secondaryCacheEnabled())) 148 // Drop and re-create the database schema on startup 149 .setProperty("hibernate.exposeTransactionAwareSessionFactory", "false") 150 //.setProperty("hibernate.hbm2ddl.auto", "create") 151 .setProperty("hibernate.default_entity_mode", "dynamic-map"); 152 153 if(!StringUtil.isEmpty(ormConf.getCatalog())) 154 configuration.setProperty("hibernate.default_catalog", ormConf.getCatalog()); 155 if(!StringUtil.isEmpty(ormConf.getSchema())) 156 configuration.setProperty("hibernate.default_schema",ormConf.getSchema()); 157 158 if(ormConf.secondaryCacheEnabled()){ 159 if(cacheConfig!=null && cacheConfig.isFile()) 160 configuration.setProperty("hibernate.cache.provider_configuration_file_resource_path",cacheConfig.getAbsolutePath()); 161 configuration.setProperty("hibernate.cache.provider_class", cacheProvider); 162 163 configuration.setProperty("hibernate.cache.use_query_cache", "true"); 164 } 165 166 /* 167 <!ELEMENT tuplizer EMPTY> 168 <!ATTLIST tuplizer entity-mode (pojo|dom4j|dynamic-map) #IMPLIED> <!-- entity mode for which tuplizer is in effect --> 169 <!ATTLIST tuplizer class CDATA #REQUIRED> <!-- the tuplizer class to use --> 170 */ 171 172 schemaExport(engine,configuration,ormConf,dc); 173 174 return configuration; 175 } 176 177 private static void schemaExport(HibernateORMEngine engine,Configuration configuration, ORMConfiguration ormConf,DatasourceConnection dc) throws PageException,ORMException, SQLException, IOException { 178 if(ORMConfiguration.DBCREATE_NONE==ormConf.getDbCreate()) { 179 return; 180 } 181 else if(ORMConfiguration.DBCREATE_DROP_CREATE==ormConf.getDbCreate()) { 182 SchemaExport export = new SchemaExport(configuration); 183 export.setHaltOnError(true); 184 185 export.execute(false,true,false,false); 186 printError(engine,export.getExceptions(),false); 187 executeSQLScript(ormConf,dc); 188 } 189 else if(ORMConfiguration.DBCREATE_UPDATE==ormConf.getDbCreate()) { 190 SchemaUpdate update = new SchemaUpdate(configuration); 191 update.setHaltOnError(true); 192 update.execute(false, true); 193 printError(engine,update.getExceptions(),false); 194 } 195 } 196 197 private static void printError(HibernateORMEngine engine, List<Exception> exceptions,boolean throwException) throws PageException { 198 if(ArrayUtil.isEmpty(exceptions)) return; 199 Iterator<Exception> it = exceptions.iterator(); 200 if(!throwException || exceptions.size()>1){ 201 while(it.hasNext()) { 202 ORMUtil.printError(it.next(), engine); 203 } 204 } 205 if(!throwException) return; 206 207 it = exceptions.iterator(); 208 while(it.hasNext()) { 209 throw HibernateException.toPageException(engine, it.next()); 210 } 211 } 212 213 private static void executeSQLScript(ORMConfiguration ormConf,DatasourceConnection dc) throws SQLException, IOException { 214 Resource sqlScript = ormConf.getSqlScript(); 215 if(sqlScript!=null && sqlScript.isFile()) { 216 BufferedReader br = IOUtil.toBufferedReader(IOUtil.getReader(sqlScript,null)); 217 String line; 218 StringBuilder sql=new StringBuilder(); 219 String str; 220 Statement stat = dc.getConnection().createStatement(); 221 try{ 222 while((line=br.readLine())!=null){ 223 line=line.trim(); 224 if(line.startsWith("//") || line.startsWith("--")) continue; 225 if(line.endsWith(";")){ 226 sql.append(line.substring(0,line.length()-1)); 227 str=sql.toString().trim(); 228 if(str.length()>0)stat.execute(str); 229 sql=new StringBuilder(); 230 } 231 else { 232 sql.append(line).append(" "); 233 } 234 } 235 str=sql.toString().trim(); 236 if(str.length()>0){ 237 stat.execute(str); 238 } 239 } 240 finally { 241 SQLUtil.closeEL(stat); 242 } 243 } 244 } 245 246 247 public static String createMappings(HibernateORMEngine engine, Map<String, CFCInfo> cfcs) { 248 249 Set<String> done=new HashSet<String>(); 250 StringBuffer mappings=new StringBuffer(); 251 mappings.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 252 mappings.append(HIBERNATE_3_DOCTYPE_DEFINITION+"\n"); 253 mappings.append("<hibernate-mapping>\n"); 254 Iterator<Entry<String, CFCInfo>> it = cfcs.entrySet().iterator(); 255 Entry<String, CFCInfo> entry; 256 while(it.hasNext()){ 257 entry = it.next(); 258 createMappings(engine,cfcs,entry.getKey(),entry.getValue(),done,mappings); 259 260 } 261 mappings.append("</hibernate-mapping>"); 262 return mappings.toString(); 263 } 264 265 private static void createMappings(HibernateORMEngine engine, Map<String, CFCInfo> cfcs,String key, CFCInfo value,Set<String> done,StringBuffer mappings) { 266 if(done.contains(key)) return; 267 CFCInfo v; 268 String ext = value.getCFC().getExtends(); 269 if(!StringUtil.isEmpty(ext)){ 270 try { 271 Component base = engine.getEntityByCFCName(ext, false); 272 ext=HibernateCaster.getEntityName(base); 273 } catch (Throwable t) {} 274 275 276 ext=HibernateORMEngine.id(railo.runtime.type.util.ListUtil.last(ext, '.').trim()); 277 if(!done.contains(ext)) { 278 v = cfcs.get(ext); 279 if(v!=null)createMappings(engine,cfcs, ext, v, done, mappings); 280 } 281 } 282 283 mappings.append(value.getXML()); 284 done.add(key); 285 } 286 287 public static List<Component> loadComponents(PageContext pc,HibernateORMEngine engine, ORMConfiguration ormConf) throws PageException { 288 ExtensionResourceFilter filter = new ExtensionResourceFilter(pc.getConfig().getCFCExtension(),true); 289 List<Component> components=new ArrayList<Component>(); 290 loadComponents(pc,engine,components,ormConf.getCfcLocations(),filter,ormConf); 291 return components; 292 } 293 294 private static void loadComponents(PageContext pc, HibernateORMEngine engine,List<Component> components,Resource[] reses,ExtensionResourceFilter filter,ORMConfiguration ormConf) throws PageException { 295 Mapping[] mappings = createMappings(pc, reses); 296 ApplicationContext ac=pc.getApplicationContext(); 297 Mapping[] existing = ac.getComponentMappings(); 298 if(existing==null) existing=new Mapping[0]; 299 try{ 300 Mapping[] tmp = new Mapping[existing.length+1]; 301 for(int i=1;i<tmp.length;i++){ 302 tmp[i]=existing[i-1]; 303 } 304 ac.setComponentMappings(tmp); 305 for(int i=0;i<reses.length;i++){ 306 if(reses[i]!=null && reses[i].isDirectory()){ 307 tmp[0] = mappings[i]; 308 ac.setComponentMappings(tmp); 309 loadComponents(pc,engine,mappings[i],components,reses[i], filter,ormConf); 310 } 311 } 312 } 313 finally { 314 ac.setComponentMappings(existing); 315 } 316 } 317 318 private static void loadComponents(PageContext pc, HibernateORMEngine engine,Mapping cfclocation,List<Component> components,Resource res,ExtensionResourceFilter filter,ORMConfiguration ormConf) throws PageException { 319 if(res==null) return; 320 321 if(res.isDirectory()){ 322 Resource[] children = res.listResources(filter); 323 324 // first load all files 325 for(int i=0;i<children.length;i++){ 326 if(children[i].isFile())loadComponents(pc,engine,cfclocation,components,children[i], filter,ormConf); 327 } 328 329 // and then invoke subfiles 330 for(int i=0;i<children.length;i++){ 331 if(children[i].isDirectory())loadComponents(pc,engine,cfclocation,components,children[i], filter,ormConf); 332 } 333 } 334 else if(res.isFile()){ 335 if(!res.getName().equalsIgnoreCase(Constants.APP_CFC)) { 336 try { 337 338 // MUST still a bad solution 339 PageSource ps = pc.toPageSource(res,null); 340 if(ps==null || ps.getComponentName().indexOf("..")!=-1) { 341 PageSource ps2=null; 342 Resource root = cfclocation.getPhysical(); 343 String path = ResourceUtil.getPathToChild(res, root); 344 if(!StringUtil.isEmpty(path,true)) { 345 ps2=cfclocation.getPageSource(path); 346 } 347 if(ps2!=null)ps=ps2; 348 } 349 350 351 //Page p = ps.loadPage(pc.getConfig()); 352 String name=res.getName(); 353 name=name.substring(0,name.length()-4); 354 Page p = ComponentLoader.loadPage(pc, ps,true); 355 if(!(p instanceof InterfacePage)){ 356 ComponentAccess cfc = ComponentLoader.loadComponent(pc, p, ps, name, true,true); 357 if(cfc.isPersistent()){ 358 components.add(cfc); 359 } 360 } 361 } 362 catch (PageException e) { 363 if(!ormConf.skipCFCWithError())throw e; 364 //e.printStackTrace(); 365 } 366 } 367 } 368 } 369 370 371 public static Mapping[] createMappings(PageContext pc,Resource[] resources) { 372 373 MappingImpl[] mappings=new MappingImpl[resources.length]; 374 ConfigImpl config=(ConfigImpl) pc.getConfig(); 375 for(int i=0;i<mappings.length;i++) { 376 mappings[i]=new MappingImpl(config, 377 "/", 378 resources[i].getAbsolutePath(), 379 null,ConfigImpl.INSPECT_UNDEFINED,true,false,false,false,true,true,null 380 ); 381 } 382 return mappings; 383 } 384 }