package railo.runtime.orm.hibernate; import java.io.BufferedReader; import java.io.IOException; import java.nio.charset.Charset; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.Set; import org.hibernate.MappingException; import org.hibernate.cache.RegionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.w3c.dom.Document; import railo.commons.io.res.Resource; import railo.commons.io.res.filter.ExtensionResourceFilter; import railo.commons.io.res.util.ResourceUtil; import railo.commons.sql.SQLUtil; import railo.loader.util.Util; import railo.runtime.Component; import railo.runtime.InterfacePage; import railo.runtime.Mapping; import railo.runtime.Page; import railo.runtime.PageContext; import railo.runtime.PageSource; import railo.runtime.component.ComponentLoader; import railo.runtime.config.Config; import railo.runtime.config.Constants; import railo.runtime.db.DataSource; import railo.runtime.db.DatasourceConnection; import railo.runtime.exp.PageException; import railo.runtime.listener.ApplicationContext; import railo.runtime.orm.ORMConfiguration; import railo.runtime.orm.ORMUtil; import railo.runtime.reflection.Reflector; import railo.runtime.type.cfc.ComponentAccess; import railo.runtime.type.util.ArrayUtil; public class HibernateSessionFactory { public static final String HIBERNATE_3_PUBLIC_ID = "-//Hibernate/Hibernate Mapping DTD 3.0//EN"; public static final String HIBERNATE_3_SYSTEM_ID = "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"; public static final Charset HIBERNATE_3_CHARSET = CommonUtil.UTF8; public static final String HIBERNATE_3_DOCTYPE_DEFINITION = "<!DOCTYPE hibernate-mapping PUBLIC \""+HIBERNATE_3_PUBLIC_ID+"\" \""+HIBERNATE_3_SYSTEM_ID+"\">"; public static Configuration createConfiguration(String mappings, DatasourceConnection dc, SessionFactoryData data) throws SQLException, IOException, PageException { /* autogenmap cacheconfig cacheprovider cfclocation datasource dbcreate eventHandling flushatrequestend ormconfig sqlscript useDBForMapping */ ORMConfiguration ormConf = data.getORMConfiguration(); // dialect DataSource ds = dc.getDatasource(); String dialect=null; try { if (Class.forName(ormConf.getDialect()) != null) { dialect = ormConf.getDialect(); } } catch (Exception e) { // MZ: The dialect value could not be bound to a classname or instantiation causes an exception - ignore and use the default dialect entries } if (dialect == null) { dialect = Dialect.getDialect(ormConf.getDialect()); if(Util.isEmpty(dialect)) dialect=Dialect.getDialect(ds); } if(Util.isEmpty(dialect)) throw ExceptionUtil.createException(data,null,"A valid dialect definition inside the "+Constants.APP_CFC+"/"+Constants.CFAPP_NAME+" is missing. The dialect cannot be determinated automatically",null); // Cache Provider String cacheProvider = ormConf.getCacheProvider(); Class<? extends RegionFactory> regionFactory=null; if(Util.isEmpty(cacheProvider) || "EHCache".equalsIgnoreCase(cacheProvider)) { regionFactory=net.sf.ehcache.hibernate.EhCacheRegionFactory.class; cacheProvider=regionFactory.getName();//"org.hibernate.cache.EhCacheProvider"; } else if("JBossCache".equalsIgnoreCase(cacheProvider)) cacheProvider="org.hibernate.cache.TreeCacheProvider"; else if("HashTable".equalsIgnoreCase(cacheProvider)) cacheProvider="org.hibernate.cache.HashtableCacheProvider"; else if("SwarmCache".equalsIgnoreCase(cacheProvider)) cacheProvider="org.hibernate.cache.SwarmCacheProvider"; else if("OSCache".equalsIgnoreCase(cacheProvider)) cacheProvider="org.hibernate.cache.OSCacheProvider"; Resource cacheConfig = ormConf.getCacheConfig(); Configuration configuration = new Configuration(); // ormConfig Resource conf = ormConf.getOrmConfig(); if(conf!=null){ try { Document doc = CommonUtil.toDocument(conf); configuration.configure(doc); } catch (Throwable t) { ORMUtil.printError(t); } } try{ configuration.addXML(mappings); } catch(MappingException me){ throw ExceptionUtil.createException(data,null, me); } configuration // Database connection settings .setProperty("hibernate.connection.driver_class", ds.getClazz().getName()) .setProperty("hibernate.connection.url", ds.getDsnTranslated()) .setProperty("hibernate.connection.username", ds.getUsername()) .setProperty("hibernate.connection.password", ds.getPassword()) //.setProperty("hibernate.connection.release_mode", "after_transaction") .setProperty("hibernate.transaction.flush_before_completion", "false") .setProperty("hibernate.transaction.auto_close_session", "false") // JDBC connection pool (use the built-in) //.setProperty("hibernate.connection.pool_size", "2")//MUST // SQL dialect .setProperty("hibernate.dialect", dialect) // Enable Hibernate's current session context .setProperty("hibernate.current_session_context_class", "thread") // Echo all executed SQL to stdout .setProperty("hibernate.show_sql", CommonUtil.toString(ormConf.logSQL())) .setProperty("hibernate.format_sql", CommonUtil.toString(ormConf.logSQL())) // Specifies whether secondary caching should be enabled .setProperty("hibernate.cache.use_second_level_cache", CommonUtil.toString(ormConf.secondaryCacheEnabled())) // Drop and re-create the database schema on startup .setProperty("hibernate.exposeTransactionAwareSessionFactory", "false") //.setProperty("hibernate.hbm2ddl.auto", "create") .setProperty("hibernate.default_entity_mode", "dynamic-map"); if(!Util.isEmpty(ormConf.getCatalog())) configuration.setProperty("hibernate.default_catalog", ormConf.getCatalog()); if(!Util.isEmpty(ormConf.getSchema())) configuration.setProperty("hibernate.default_schema",ormConf.getSchema()); if(ormConf.secondaryCacheEnabled()){ if(cacheConfig!=null && cacheConfig.isFile()) configuration.setProperty("hibernate.cache.provider_configuration_file_resource_path",cacheConfig.getAbsolutePath()); if(regionFactory!=null || Reflector.isInstaneOf(cacheProvider, RegionFactory.class)) configuration.setProperty("hibernate.cache.region.factory_class", cacheProvider); else configuration.setProperty("hibernate.cache.provider_class", cacheProvider); configuration.setProperty("hibernate.cache.use_query_cache", "true"); //hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider } /* <!ELEMENT tuplizer EMPTY> <!ATTLIST tuplizer entity-mode (pojo|dom4j|dynamic-map) #IMPLIED> <!-- entity mode for which tuplizer is in effect --> <!ATTLIST tuplizer class CDATA #REQUIRED> <!-- the tuplizer class to use --> */ schemaExport(configuration,dc,data); return configuration; } private static void schemaExport(Configuration configuration, DatasourceConnection dc, SessionFactoryData data) throws PageException, SQLException, IOException { ORMConfiguration ormConf = data.getORMConfiguration(); if(ORMConfiguration.DBCREATE_NONE==ormConf.getDbCreate()) { return; } else if(ORMConfiguration.DBCREATE_DROP_CREATE==ormConf.getDbCreate()) { SchemaExport export = new SchemaExport(configuration); export.setHaltOnError(true); export.execute(false,true,false,false); printError(data,export.getExceptions(),false); executeSQLScript(ormConf,dc); } else if(ORMConfiguration.DBCREATE_UPDATE==ormConf.getDbCreate()) { SchemaUpdate update = new SchemaUpdate(configuration); update.setHaltOnError(true); update.execute(false, true); printError(data,update.getExceptions(),false); } } private static void printError(SessionFactoryData data, List<Exception> exceptions,boolean throwException) throws PageException { if(ArrayUtil.isEmpty(exceptions)) return; Iterator<Exception> it = exceptions.iterator(); if(!throwException || exceptions.size()>1){ while(it.hasNext()) { ORMUtil.printError(it.next()); } } if(!throwException) return; it = exceptions.iterator(); while(it.hasNext()) { throw ExceptionUtil.createException(data,null,it.next()); } } private static void executeSQLScript(ORMConfiguration ormConf,DatasourceConnection dc) throws SQLException, IOException { Resource sqlScript = ormConf.getSqlScript(); if(sqlScript!=null && sqlScript.isFile()) { BufferedReader br = CommonUtil.toBufferedReader(sqlScript,(Charset)null); String line; StringBuilder sql=new StringBuilder(); String str; Statement stat = dc.getConnection().createStatement(); try{ while((line=br.readLine())!=null){ line=line.trim(); if(line.startsWith("//") || line.startsWith("--")) continue; if(line.endsWith(";")){ sql.append(line.substring(0,line.length()-1)); str=sql.toString().trim(); if(str.length()>0)stat.execute(str); sql=new StringBuilder(); } else { sql.append(line).append(" "); } } str=sql.toString().trim(); if(str.length()>0){ stat.execute(str); } } finally { SQLUtil.closeEL(stat); } } } public static String createMappings(ORMConfiguration ormConf, SessionFactoryData data) { Set<String> done=new HashSet<String>(); StringBuffer mappings=new StringBuffer(); mappings.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); mappings.append(HIBERNATE_3_DOCTYPE_DEFINITION+"\n"); mappings.append("<hibernate-mapping>\n"); Iterator<Entry<String, CFCInfo>> it = data.cfcs.entrySet().iterator(); Entry<String, CFCInfo> entry; while(it.hasNext()){ entry = it.next(); createMappings(ormConf,entry.getKey(),entry.getValue(),done,mappings,data); } mappings.append("</hibernate-mapping>"); return mappings.toString(); } private static void createMappings(ORMConfiguration ormConf, String key, CFCInfo value,Set<String> done,StringBuffer mappings, SessionFactoryData data) { if(done.contains(key)) return; CFCInfo v; String ext = value.getCFC().getExtends(); if(!Util.isEmpty(ext)){ try { Component base = data.getEntityByCFCName(ext, false); ext=HibernateCaster.getEntityName(base); } catch (Throwable t) {} ext=HibernateUtil.id(CommonUtil.last(ext, '.').trim()); if(!done.contains(ext)) { v = data.cfcs.get(ext); if(v!=null)createMappings(ormConf, ext, v, done, mappings,data); } } mappings.append(value.getXML()); done.add(key); } public static List<Component> loadComponents(PageContext pc,HibernateORMEngine engine, ORMConfiguration ormConf) throws PageException { ExtensionResourceFilter filter = new ExtensionResourceFilter(pc.getConfig().getCFCExtension(),true); List<Component> components=new ArrayList<Component>(); loadComponents(pc,engine,components,ormConf.getCfcLocations(),filter,ormConf); return components; } private static void loadComponents(PageContext pc, HibernateORMEngine engine,List<Component> components,Resource[] reses,ExtensionResourceFilter filter,ORMConfiguration ormConf) throws PageException { Mapping[] mappings = createMappings(pc, reses); ApplicationContext ac=pc.getApplicationContext(); Mapping[] existing = ac.getComponentMappings(); if(existing==null) existing=new Mapping[0]; try{ Mapping[] tmp = new Mapping[existing.length+1]; for(int i=1;i<tmp.length;i++){ tmp[i]=existing[i-1]; } ac.setComponentMappings(tmp); for(int i=0;i<reses.length;i++){ if(reses[i]!=null && reses[i].isDirectory()){ tmp[0] = mappings[i]; ac.setComponentMappings(tmp); loadComponents(pc,engine,mappings[i],components,reses[i], filter,ormConf); } } } finally { ac.setComponentMappings(existing); } } private static void loadComponents(PageContext pc, HibernateORMEngine engine,Mapping cfclocation,List<Component> components,Resource res,ExtensionResourceFilter filter,ORMConfiguration ormConf) throws PageException { if(res==null) return; if(res.isDirectory()){ Resource[] children = res.listResources(filter); // first load all files for(int i=0;i<children.length;i++){ if(children[i].isFile())loadComponents(pc,engine,cfclocation,components,children[i], filter,ormConf); } // and then invoke subfiles for(int i=0;i<children.length;i++){ if(children[i].isDirectory())loadComponents(pc,engine,cfclocation,components,children[i], filter,ormConf); } } else if(res.isFile()){ if(!res.getName().equalsIgnoreCase(Constants.APP_CFC)) { try { // MUST still a bad solution PageSource ps = pc.toPageSource(res,null); if(ps==null || ps.getComponentName().indexOf("..")!=-1) { PageSource ps2=null; Resource root = cfclocation.getPhysical(); String path = ResourceUtil.getPathToChild(res, root); if(!Util.isEmpty(path,true)) { ps2=cfclocation.getPageSource(path); } if(ps2!=null)ps=ps2; } //Page p = ps.loadPage(pc.getConfig()); String name=res.getName(); name=name.substring(0,name.length()-4); Page p = ComponentLoader.loadPage(pc, ps,true); if(!(p instanceof InterfacePage)){ ComponentAccess cfc = ComponentLoader.loadComponent(pc, p, ps, name, true,true); if(cfc.isPersistent()){ components.add(cfc); } } } catch (PageException e) { if(!ormConf.skipCFCWithError())throw e; //e.printStackTrace(); } } } } public static Mapping[] createMappings(PageContext pc,Resource[] resources) { Mapping[] mappings=new Mapping[resources.length]; Config config=pc.getConfig(); for(int i=0;i<mappings.length;i++) { mappings[i]=CommonUtil.createMapping(config, "/", resources[i].getAbsolutePath() ); } return mappings; } }