001/*
002 * #%L
003 * Netarchivesuite - wayback
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023package dk.netarkivet.wayback.indexer;
024
025import org.hibernate.Session;
026import org.hibernate.SessionFactory;
027import org.hibernate.cfg.AnnotationConfiguration;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031import dk.netarkivet.common.utils.Settings;
032import dk.netarkivet.wayback.WaybackSettings;
033
034/**
035 * This class contains a single static utility method which returns a Hibernate session: HibernateUtil.getSession().
036 * <p>
037 * The configuration for the session is read from settings.xml in the elements nested under settings/wayback/hibernate.
038 */
039public class HibernateUtil {
040
041    /** Logger for this class. */
042    private static final Logger log = LoggerFactory.getLogger(HibernateUtil.class);
043
044    /** Key indicating the connection provider to be used by hibernate. */
045    private static final String CONNECTION_PROVIDER_CLASS = "connection.provider_class";
046
047    /**
048     * Value indicating use of the c3p0 as connection provider. This is hard coded and no other connection providers
049     * have been tested.
050     */
051    private static final String ORG_HIBERNATE_CONNECTION_C3_P0_CONNECTION_PROVIDER = "org.hibernate.connection.C3P0ConnectionProvider";
052
053    // For documentation of these values see the corresponding constants in
054    // the WaybackSettings class
055    private static final String C3P0_ACQUIRE_INCREMENT = "c3p0.acquire_increment";
056    private static final String C3P0_IDLE_TEST_PERIOD = "c3p0.idle_test_period";
057    private static final String C3P0_MAX_SIZE = "c3p0.max_size";
058    private static final String C3P0_MAX_STATEMENTS = "c3p0.max_statements";
059    private static final String C3P0_MIN_SIZE = "c3p0.min_size";
060    private static final String C3P0_TIMEOUT = "c3p0.timeout";
061    private static final String HIBERNATE_CONNECTION_DRIVER_CLASS = "hibernate.connection.driver_class";
062    private static final String HIBERNATE_CONNECTION_URL = "hibernate.connection.url";
063    private static final String HIBERNATE_DIALECT = "hibernate.dialect";
064    private static final String HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
065    private static final String HIBERNATE_BYTECODE_USE_REFLECTION_OPTIMIZER = "hibernate.bytecode.use_reflection_optimizer";
066    private static final String HIBERNATE_HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";
067    private static final String HIBERNATE_TRANSACTION_FACTORY_CLASS = "hibernate.transaction.factory_class";
068    private static final String HIBERNATE_SHOW_SQL = "hibernate.show_sql";
069    private static final String HIBERNATE_CONNECTION_USERNAME = "hibernate.connection.username";
070    private static final String HIBERNATE_CONNECTION_PASSWORD = "hibernate.connection.password";
071
072    /**
073     * Private constructor as this class is never instantiated.
074     */
075    private HibernateUtil() {
076    }
077
078    /**
079     * The session factory from which sessions are obtained. There is no accessor supplied for this factory as a
080     * reference to it can be obtained if necessary (e.g. during a cleanup operation) from the Session itself.
081     */
082    private static SessionFactory sessionFactory;
083
084    /**
085     * Properties of the hibernate session are loaded from settings.xml. There is therefore no need for a separate
086     * hibernate configuration file.
087     */
088    private static void initialiseFactory() {
089        if (sessionFactory == null || sessionFactory.isClosed()) {
090            try {
091                log.info("Initialisefactory process initiated");
092                AnnotationConfiguration config = new AnnotationConfiguration();
093                config.setProperty(CONNECTION_PROVIDER_CLASS, ORG_HIBERNATE_CONNECTION_C3_P0_CONNECTION_PROVIDER);
094                config.setProperty(C3P0_ACQUIRE_INCREMENT, Settings.get(WaybackSettings.C3P0_ACQUIRE_INCREMENT));
095                config.setProperty(C3P0_IDLE_TEST_PERIOD, Settings.get(WaybackSettings.C3P0_IDLE_PERIOD));
096                config.setProperty(C3P0_MAX_SIZE, Settings.get(WaybackSettings.C3P0_MAX_SIZE));
097                config.setProperty(C3P0_MAX_STATEMENTS, Settings.get(WaybackSettings.C3P0_MAX_STATEMENTS));
098                config.setProperty(C3P0_MIN_SIZE, Settings.get(WaybackSettings.C3P0_MIN_SIZE));
099                config.setProperty(C3P0_TIMEOUT, Settings.get(WaybackSettings.C3P0_TIMEOUT));
100                config.setProperty(HIBERNATE_CONNECTION_DRIVER_CLASS, Settings.get(WaybackSettings.HIBERNATE_DB_DRIVER));
101                config.setProperty(HIBERNATE_CONNECTION_URL, Settings.get(WaybackSettings.HIBERNATE_DB_URL));
102                config.setProperty(HIBERNATE_DIALECT, Settings.get(WaybackSettings.HIBERNATE_DIALECT));
103                config.setProperty(HIBERNATE_FORMAT_SQL, Settings.get(WaybackSettings.HIBERNATE_FORMAT_SQL));
104                config.setProperty(HIBERNATE_BYTECODE_USE_REFLECTION_OPTIMIZER,
105                        Settings.get(WaybackSettings.HIBERNATE_REFLECTION_OPTIMIZER));
106                config.setProperty(HIBERNATE_HBM2DDL_AUTO, Settings.get(WaybackSettings.HIBERNATE_HBM2DDL_AUTO));
107                config.setProperty(HIBERNATE_TRANSACTION_FACTORY_CLASS,
108                        Settings.get(WaybackSettings.HIBERNATE_TRANSACTION_FACTORY));
109                config.setProperty(HIBERNATE_SHOW_SQL, Settings.get(WaybackSettings.HIBERNATE_SHOW_SQL));
110                log.info("Hibernate properties used: " + CONNECTION_PROVIDER_CLASS + " = "
111                        + ORG_HIBERNATE_CONNECTION_C3_P0_CONNECTION_PROVIDER + ", " + C3P0_ACQUIRE_INCREMENT + " = "
112                        + Settings.get(WaybackSettings.C3P0_ACQUIRE_INCREMENT) + ", " + C3P0_IDLE_TEST_PERIOD + " = "
113                        + Settings.get(WaybackSettings.C3P0_IDLE_PERIOD) + ", " + C3P0_MAX_SIZE + " = "
114                        + Settings.get(WaybackSettings.C3P0_MAX_SIZE) + ", " + C3P0_MAX_STATEMENTS + " = "
115                        + Settings.get(WaybackSettings.C3P0_MAX_STATEMENTS) + ", " + C3P0_MIN_SIZE + " = "
116                        + Settings.get(WaybackSettings.C3P0_MIN_SIZE) + ", " + C3P0_TIMEOUT + " = "
117                        + Settings.get(WaybackSettings.C3P0_TIMEOUT) + ", " + HIBERNATE_CONNECTION_DRIVER_CLASS + " = "
118                        + Settings.get(WaybackSettings.HIBERNATE_DB_DRIVER) + ", " + HIBERNATE_CONNECTION_URL + " = "
119                        + Settings.get(WaybackSettings.HIBERNATE_DB_URL) + ", " + HIBERNATE_DIALECT + " = "
120                        + Settings.get(WaybackSettings.HIBERNATE_DIALECT) + ", " + HIBERNATE_FORMAT_SQL + " = "
121                        + Settings.get(WaybackSettings.HIBERNATE_FORMAT_SQL) + ", "
122                        + HIBERNATE_BYTECODE_USE_REFLECTION_OPTIMIZER + " = "
123                        + Settings.get(WaybackSettings.HIBERNATE_REFLECTION_OPTIMIZER) + ", " + HIBERNATE_HBM2DDL_AUTO
124                        + " = " + Settings.get(WaybackSettings.HIBERNATE_HBM2DDL_AUTO) + ", "
125                        + HIBERNATE_TRANSACTION_FACTORY_CLASS + " = "
126                        + Settings.get(WaybackSettings.HIBERNATE_TRANSACTION_FACTORY) + ", " + HIBERNATE_SHOW_SQL
127                        + " = " + Settings.get(WaybackSettings.HIBERNATE_SHOW_SQL));
128
129                // Specifically allow unset username/password for the database
130                // so that we can use database without authentication, e.g. in
131                // testing.
132                if (!Settings.get(WaybackSettings.HIBERNATE_USERNAME).isEmpty()) {
133                    config.setProperty(HIBERNATE_CONNECTION_USERNAME, Settings.get(WaybackSettings.HIBERNATE_USERNAME));
134                }
135                if (!Settings.get(WaybackSettings.HIBERNATE_PASSWORD).isEmpty()) {
136                    config.setProperty(HIBERNATE_CONNECTION_PASSWORD, Settings.get(WaybackSettings.HIBERNATE_PASSWORD));
137                }
138                config.addAnnotatedClass(ArchiveFile.class);
139                sessionFactory = config.buildSessionFactory();
140            } catch (Throwable ex) {
141                log.error("Could not connect to hibernate object store - exiting", ex);
142                throw new IllegalStateException("Could not connect to hibernate object store - exiting", ex);
143            }
144        }
145    }
146
147    /**
148     * Get a hibernate session for communicating with the object store for the wayback indexer. This method has the side
149     * effect of creating and initialising a SessionFactory object if there is no current open SessionFactory.
150     *
151     * @return the above mentioned hibernate session.
152     */
153    public static Session getSession() {
154        initialiseFactory();
155        return sessionFactory.openSession();
156    }
157
158}