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