001    /*
002     * Databinder: a simple bridge from Wicket to Hibernate
003     * Copyright (C) 2006  Nathan Hamblen nathan@technically.us
004     *
005     * This library is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU Lesser General Public
007     * License as published by the Free Software Foundation; either
008     * version 2.1 of the License, or (at your option) any later version.
009     * 
010     * This library is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013     * Lesser General Public License for more details.
014     * 
015     * You should have received a copy of the GNU Lesser General Public
016     * License along with this library; if not, write to the Free Software
017     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
018     */
019    
020    package net.databinder.hib;
021    
022    import java.util.HashMap;
023    
024    import net.databinder.DataApplicationBase;
025    import net.databinder.components.hib.DataBrowser;
026    
027    import org.apache.wicket.Application;
028    import org.apache.wicket.Request;
029    import org.apache.wicket.RequestCycle;
030    import org.apache.wicket.Response;
031    import org.apache.wicket.WicketRuntimeException;
032    import org.apache.wicket.protocol.http.WebRequest;
033    import org.hibernate.SessionFactory;
034    import org.hibernate.cfg.AnnotationConfiguration;
035    
036    /**
037     * Optional Databinder base Application class for configuration and session management. 
038     * Supports multiple session factories with key objects.
039     * @author Nathan Hamblen
040     */
041    public abstract class DataApplication extends DataApplicationBase implements HibernateApplication {
042            
043            /** App-wide session factories */
044            private HashMap<Object, SessionFactory> hibernateSessionFactories = new HashMap<Object, SessionFactory>();
045            
046            
047            /**
048             * Initializes a default Hibernate session factory and mounts a page for
049             * the data browser. This is called automatically during start-up. Applications 
050             * with one session factory will not normally need to override this method; 
051             * see related methods to override specific tasks.
052             * @see #buildHibernateSessionFactory(Object) aoe
053             * @see #mountDataBrowser() 
054             */
055            protected void dataInit() {
056                    buildHibernateSessionFactory(null);
057                    if (isDataBrowserAllowed())
058                            mountDataBrowser();
059            }
060            
061            /**
062             * Bookmarkable subclass of DataBrowser page. Access to the page is permitted
063             * only if the current application is assignable to DataApplication
064             * and returns true for isDataBrowserAllowed().
065             * @see DataBrowser
066             */
067            public static class BmarkDataBrowser extends DataBrowser {
068                    public BmarkDataBrowser() {
069                            super(((DataApplication)Application.get()).isDataBrowserAllowed());
070                    }
071            }
072            
073            /**
074             * Mounts Data Diver to /dbrowse. Override to mount elsewhere, or not mount at all.
075             * This method is only called if isDataBrowserAllowed() returns true in init().
076             */
077            protected void mountDataBrowser() {
078                    mountBookmarkablePage("/dbrowse", BmarkDataBrowser.class);
079            }
080    
081            /**
082             * Called by init to create Hibernate session factory and load a configuration. Passes
083             * an empty new AnnotationConfiguration to buildHibernateSessionFactory(key, config) by 
084             * default. Override if creating a configuration externally.
085             * @param key session factory key; the default key is null
086             */
087            public void buildHibernateSessionFactory(Object key) {
088                    buildHibernateSessionFactory(key, new AnnotationConfiguration());
089            }
090            
091            /**
092             * Builds and  a session factory with the given configuration. Passes config
093             * through configureHibernate methods.
094             * @param key session factory key; the default key is null
095             * @param config annotation conifuration
096             * @see #configureHibernateEssentials(AnnotationConfiguration)
097             * @see #configureHibernate(AnnotationConfiguration, Object) 
098             */
099            final public void buildHibernateSessionFactory(Object key, AnnotationConfiguration config) {
100                    configureHibernateEssentials(config);
101                    configureHibernate(config, key);
102                    setHibernateSessionFactory(key, config.buildSessionFactory());
103            }
104            
105            /**
106             * Configures the session factory associated with the key. The default implementation
107             * calls the configureHibernate(config) method and ignores the key.
108             * For applications with multiple session factories, override this method to
109             * perform key-specific configuration here instead.
110             * @param config configuration to update
111             * @param key object, or null for the default factory
112             */
113            protected  void configureHibernate(AnnotationConfiguration config, Object key) {
114                    configureHibernate(config);
115            }
116            
117            /**
118             * For Hibernate settings that should not normally be overriden by client
119             * applications. Specifically, this method sets Hibernate for a ManagedSessionContext,
120             * the session lookup method used by DataRequestCycle.
121             * @param config Hibernate configuration
122             */
123            protected void configureHibernateEssentials(AnnotationConfiguration config) {
124                    config.setProperty("hibernate.current_session_context_class","managed");
125            }
126                    
127            /**
128             * Configures the default session factory; override to add annotated classes 
129             * but don't forget to call this super-implementation if you want its defaults.
130             * When running in development the session factory is set for 
131             * hbm2ddl auto-updating to create and add columns to tables 
132             * as required. For deployment it is configured for C3P0 connection pooling.
133             * @param config used to build Hibernate session factory
134             */
135            protected  void configureHibernate(AnnotationConfiguration config) {
136            if (isDevelopment())
137                    config.setProperty("hibernate.hbm2ddl.auto", "update");
138            else {
139                    config.setProperty("hibernate.c3p0.max_size", "20")
140                    .setProperty("hibernate.c3p0.timeout","3000")
141                    .setProperty("hibernate.c3p0.idle_test_period", "300");
142            }
143            }
144            
145            /**
146             * @param key object, or null for the default factory
147             * @return the retained session factory
148             */
149            public SessionFactory getHibernateSessionFactory(Object key) {
150                    SessionFactory sf = hibernateSessionFactories.get(key);
151                    if (sf == null)
152                            if (key == null)
153                                    throw new WicketRuntimeException("The default Hibernate session factory has not been " +
154                                                    "initialized. This is normally done in DataApplication.init().");
155                            else
156                                    throw new WicketRuntimeException("Session factory not found for key: " + key);
157                    return sf;
158            }
159            
160            /**
161             * @param key object, or null for the default factory
162             * @param sf session factory to retain
163             */
164            protected void setHibernateSessionFactory(Object key, SessionFactory sf) {
165                    hibernateSessionFactories.put(key, sf);
166            }
167    
168            
169            /**
170             * @return a DataRequestCycle
171             * @see DataRequestCycle
172             */
173            @Override
174            public RequestCycle newRequestCycle(Request request, Response response) {
175                    return new DataRequestCycle(this, (WebRequest) request, response);
176            }
177            
178            /**
179             * Returns true if development mode is enabled. Override for other behavior.
180             * @return true if the Data Browser page should be enabled
181             */
182            protected boolean isDataBrowserAllowed() {
183                    return isDevelopment();
184            }
185    }