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    }