com.ikon.dao.HibernateUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.ikon.dao.HibernateUtil.java

Source

/**
 *  openkm, Open Document Management System (http://www.openkm.com)
 *  Copyright (c) 2006-2013  Paco Avila & Josep Llort
 *
 *  No bytes were intentionally harmed during the development of this application.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package com.ikon.dao;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.URISyntaxException;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.hql.QueryTranslator;
import org.hibernate.hql.QueryTranslatorFactory;
import org.hibernate.hql.ast.ASTQueryTranslatorFactory;
import org.hibernate.jdbc.Work;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ikon.core.Config;
import com.ikon.core.DatabaseException;
import com.ikon.dao.bean.Activity;
import com.ikon.dao.bean.Annotation;
import com.ikon.dao.bean.AutomationAction;
import com.ikon.dao.bean.AutomationMetadata;
import com.ikon.dao.bean.AutomationRule;
import com.ikon.dao.bean.AutomationValidation;
import com.ikon.dao.bean.Bookmark;
import com.ikon.dao.bean.Css;
import com.ikon.dao.bean.DatabaseMetadataSequence;
import com.ikon.dao.bean.DatabaseMetadataType;
import com.ikon.dao.bean.DatabaseMetadataValue;
import com.ikon.dao.bean.DigitalSignature;
import com.ikon.dao.bean.HotFolders;
import com.ikon.dao.bean.Language;
import com.ikon.dao.bean.MimeType;
import com.ikon.dao.bean.NodeBase;
import com.ikon.dao.bean.NodeDocument;
import com.ikon.dao.bean.NodeDocumentVersion;
import com.ikon.dao.bean.NodeFolder;
import com.ikon.dao.bean.NodeLock;
import com.ikon.dao.bean.NodeMail;
import com.ikon.dao.bean.NodeNote;
import com.ikon.dao.bean.NodeProperty;
import com.ikon.dao.bean.RegisteredPropertyGroup;
import com.ikon.dao.bean.Omr;
import com.ikon.dao.bean.RetentionPolicy;
import com.ikon.dao.bean.SMTPConfig;
import com.ikon.dao.bean.Translation;
import com.ikon.dao.bean.cache.UserItems;
import com.ikon.dao.bean.cache.UserNodeKeywords;
import com.ikon.dao.bean.extension.DropboxToken;
import com.ikon.util.ConfigUtils;
import com.ikon.util.DatabaseDialectAdapter;
import com.ikon.util.EnvironmentDetector;
import com.ikon.util.FileUtils;

/**
 * Show SQL => Logger.getLogger("org.hibernate.SQL").setThreshold(Level.INFO);
 * JBPM Integration => org.jbpm.db.JbpmSessionFactory
 * 
 * @author pavila
 */
//@SuppressWarnings(HibernateUtil.UNUSED)
public class HibernateUtil {
    static final String UNUSED = "unused";
    private static Logger log = LoggerFactory.getLogger(HibernateUtil.class);
    private static SessionFactory sessionFactory;
    public static String HBM2DDL_CREATE = "create";
    public static String HBM2DDL_UPDATE = "update";
    public static String HBM2DDL_NONE = "none";

    /**
     * Disable constructor to guaranty a single instance
     */
    private HibernateUtil() {
    }

    /**
     * Get instance
     */
    public static SessionFactory getSessionFactory() {
        return getSessionFactory(Config.HIBERNATE_HBM2DDL);
    }

    /**
     * Construct annotation configuration
     */
    private static Configuration getConfiguration() {
        Configuration cfg = new Configuration();

        // Add annotated beans
        cfg.addAnnotatedClass(Activity.class);
        cfg.addAnnotatedClass(Bookmark.class);
        cfg.addAnnotatedClass(MimeType.class);
        cfg.addAnnotatedClass(DatabaseMetadataType.class);
        cfg.addAnnotatedClass(DatabaseMetadataValue.class);
        cfg.addAnnotatedClass(DatabaseMetadataSequence.class);
        cfg.addAnnotatedClass(com.ikon.dao.bean.Config.class);
        cfg.addAnnotatedClass(Css.class);

        // Extensions
        cfg.addAnnotatedClass(DropboxToken.class);

        // Cache
        cfg.addAnnotatedClass(UserItems.class);
        cfg.addAnnotatedClass(UserNodeKeywords.class);

        // Automation
        cfg.addAnnotatedClass(AutomationRule.class);
        cfg.addAnnotatedClass(AutomationValidation.class);
        cfg.addAnnotatedClass(AutomationAction.class);
        cfg.addAnnotatedClass(AutomationMetadata.class);

        // New Persistence Model
        cfg.addAnnotatedClass(NodeBase.class);
        cfg.addAnnotatedClass(NodeDocument.class);
        cfg.addAnnotatedClass(NodeDocumentVersion.class);
        cfg.addAnnotatedClass(NodeFolder.class);
        cfg.addAnnotatedClass(NodeMail.class);
        cfg.addAnnotatedClass(NodeNote.class);
        cfg.addAnnotatedClass(NodeLock.class);
        cfg.addAnnotatedClass(NodeProperty.class);
        cfg.addAnnotatedClass(RegisteredPropertyGroup.class);
        cfg.addAnnotatedClass(Omr.class);
        cfg.addAnnotatedClass(DigitalSignature.class);
        cfg.addAnnotatedClass(RetentionPolicy.class);
        cfg.addAnnotatedClass(SMTPConfig.class);
        cfg.addAnnotatedClass(HotFolders.class);
        cfg.addAnnotatedClass(Annotation.class);

        return cfg;
    }

    /**
     * Get instance
     */
    public static SessionFactory getSessionFactory(String hbm2ddl) {
        if (sessionFactory == null) {
            try {
                // Configure Hibernate
                Configuration cfg = getConfiguration().configure();
                cfg.setProperty("hibernate.dialect", Config.HIBERNATE_DIALECT);
                cfg.setProperty("hibernate.connection.datasource", Config.HIBERNATE_DATASOURCE);
                cfg.setProperty("hibernate.hbm2ddl.auto", hbm2ddl);
                cfg.setProperty("hibernate.show_sql", Config.HIBERNATE_SHOW_SQL);
                cfg.setProperty("hibernate.generate_statistics", Config.HIBERNATE_STATISTICS);
                cfg.setProperty("hibernate.search.analyzer", Config.HIBERNATE_SEARCH_ANALYZER);
                cfg.setProperty("hibernate.search.default.directory_provider",
                        "org.hibernate.search.store.FSDirectoryProvider");
                cfg.setProperty("hibernate.search.default.indexBase", Config.HIBERNATE_SEARCH_INDEX_HOME);
                cfg.setProperty("hibernate.search.default.optimizer.operation_limit.max", "500");
                cfg.setProperty("hibernate.search.default.optimizer.transaction_limit.max", "75");
                cfg.setProperty("hibernate.worker.execution", "async");

                // http://relation.to/Bloggers/PostgreSQLAndBLOBs
                // cfg.setProperty("hibernate.jdbc.use_streams_for_binary", "false");

                // Show configuration
                log.info("Hibernate 'hibernate.dialect' = {}", cfg.getProperty("hibernate.dialect"));
                log.info("Hibernate 'hibernate.connection.datasource' = {}",
                        cfg.getProperty("hibernate.connection.datasource"));
                log.info("Hibernate 'hibernate.hbm2ddl.auto' = {}", cfg.getProperty("hibernate.hbm2ddl.auto"));
                log.info("Hibernate 'hibernate.show_sql' = {}", cfg.getProperty("hibernate.show_sql"));
                log.info("Hibernate 'hibernate.generate_statistics' = {}",
                        cfg.getProperty("hibernate.generate_statistics"));
                log.info("Hibernate 'hibernate.search.default.directory_provider' = {}",
                        cfg.getProperty("hibernate.search.default.directory_provider"));
                log.info("Hibernate 'hibernate.search.default.indexBase' = {}",
                        cfg.getProperty("hibernate.search.default.indexBase"));

                if (HBM2DDL_CREATE.equals(hbm2ddl)) {
                    // In case of database schema creation, also clean filesystem data.
                    // This means, conversion cache, file datastore and Lucene indexes. 
                    log.info("Cleaning filesystem data from: {}", Config.REPOSITORY_HOME);
                    FileUtils.deleteQuietly(new File(Config.REPOSITORY_HOME));
                }

                // Create database schema, if needed
                sessionFactory = cfg.buildSessionFactory();

                if (HBM2DDL_CREATE.equals(hbm2ddl)) {
                    log.info("Executing specific import for: {}", Config.HIBERNATE_DIALECT);
                    InputStream is = ConfigUtils.getResourceAsStream("default.sql");
                    String adapted = DatabaseDialectAdapter.dialectAdapter(is, Config.HIBERNATE_DIALECT);
                    executeImport(new StringReader(adapted));
                    IOUtils.closeQuietly(is);
                }

                if (HBM2DDL_CREATE.equals(hbm2ddl) || HBM2DDL_UPDATE.equals(hbm2ddl)) {
                    // Create or update translations
                    for (String res : ConfigUtils.getResources("i18n")) {
                        String oldTrans = null;
                        String langId = null;

                        // Preserve translation changes
                        if (HBM2DDL_UPDATE.equals(hbm2ddl)) {
                            langId = FileUtils.getFileName(res);
                            log.info("Preserving translations for: {}", langId);
                            oldTrans = preserveTranslations(langId);
                        }

                        InputStream isLang = ConfigUtils.getResourceAsStream("i18n/" + res);
                        log.info("Importing translation: {}", res);
                        executeImport(new InputStreamReader(isLang));
                        IOUtils.closeQuietly(isLang);

                        // Apply previous translation changes
                        if (HBM2DDL_UPDATE.equals(hbm2ddl)) {
                            if (oldTrans != null) {
                                log.info("Restoring translations for: {}", langId);
                                executeImport(new StringReader(oldTrans));
                            }
                        }
                    }

                    // Replace "create" or "update" by "none" to prevent repository reset on restart
                    if (Boolean.parseBoolean(Config.HIBERNATE_CREATE_AUTOFIX)) {
                        log.info("Executing Hibernate create autofix");
                        hibernateCreateAutofix(Config.HOME_DIR + "/" + Config.ikon_CONFIG);
                    } else {
                        log.info("Hibernate create autofix not executed because of {}={}",
                                Config.PROPERTY_HIBERNATE_CREATE_AUTOFIX, Config.HIBERNATE_CREATE_AUTOFIX);
                    }
                }
            } catch (HibernateException e) {
                log.error(e.getMessage(), e);
                throw new ExceptionInInitializerError(e);
            } catch (URISyntaxException e) {
                log.error(e.getMessage(), e);
                throw new ExceptionInInitializerError(e);
            } catch (IOException e) {
                log.error(e.getMessage(), e);
                throw new ExceptionInInitializerError(e);
            }
        }

        return sessionFactory;
    }

    /**
     * Preserve current translations
     */
    private static String preserveTranslations(String lgId) {
        log.debug("preserveTranslations({})", lgId);

        try {
            Language language = LanguageDAO.findByPk(lgId);
            StringBuffer sb = new StringBuffer();

            for (Translation translation : language.getTranslations()) {
                sb.append("UPDATE ikon_TRANSLATION SET ");
                sb.append("TR_TEXT='").append(translation.getText().replaceAll("'", "''")).append("' ");
                sb.append("WHERE ");
                sb.append("TR_MODULE='").append(translation.getTranslationId().getModule()).append("' AND ");
                sb.append("TR_KEY='").append(translation.getTranslationId().getKey()).append("' AND ");
                sb.append("TR_LANGUAGE='").append(language.getId()).append("';");
                sb.append("\n");
            }

            return sb.toString();
        } catch (DatabaseException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * Get instance
     */
    public static SessionFactory getSessionFactory(Configuration cfg) {
        if (sessionFactory == null) {
            sessionFactory = cfg.buildSessionFactory();
        }

        return sessionFactory;
    }

    /**
     * Close factory
     */
    public static void closeSessionFactory() {
        if (sessionFactory != null) {
            sessionFactory.close();
            sessionFactory = null;
        }
    }

    /**
     * Close session
     */
    public static void close(Session session) {
        if (session != null && session.isOpen()) {
            session.close();
        }
    }

    /**
     * Commit transaction
     */
    public static void commit(Transaction tx) {
        if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
            tx.commit();
        }
    }

    /**
     * Rollback transaction
     */
    public static void rollback(Transaction tx) {
        if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
            tx.rollback();
        }
    }

    /**
     * Convert from Blob to byte array
     */
    public static byte[] toByteArray(Blob fromImageBlob) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            byte buf[] = new byte[4000];
            int dataSize;
            InputStream is = fromImageBlob.getBinaryStream();

            try {
                while ((dataSize = is.read(buf)) != -1) {
                    baos.write(buf, 0, dataSize);
                }
            } finally {
                if (is != null) {
                    is.close();
                }
            }

            return baos.toByteArray();
        } catch (Exception e) {
        }

        return null;
    }

    /**
     * HQL to SQL translator
     */
    public static String toSql(String hql) {
        if (hql != null && hql.trim().length() > 0) {
            final QueryTranslatorFactory qtf = new ASTQueryTranslatorFactory();
            final SessionFactoryImplementor sfi = (SessionFactoryImplementor) sessionFactory;
            final QueryTranslator translator = qtf.createQueryTranslator(hql, hql, Collections.EMPTY_MAP, sfi);
            translator.compile(Collections.EMPTY_MAP, false);
            return translator.getSQLString();
        }

        return null;
    }

    /**
     * Load specific database import
     */
    private static void executeImport(final Reader rd) {
        Session session = null;
        Transaction tx = null;

        try {
            session = sessionFactory.openSession();
            tx = session.beginTransaction();

            session.doWork(new Work() {
                @Override
                public void execute(Connection con) throws SQLException {
                    try {
                        for (HashMap<String, String> error : LegacyDAO.executeScript(con, rd)) {
                            log.error("Error during import script execution at line {}: {} [ {} ]",
                                    new Object[] { error.get("ln"), error.get("msg"), error.get("sql") });
                        }
                    } catch (IOException e) {
                        log.error(e.getMessage(), e);
                    } finally {
                        IOUtils.closeQuietly(rd);
                    }
                }
            });

            commit(tx);
        } catch (Exception e) {
            rollback(tx);
            log.error(e.getMessage(), e);
        }
    }

    /**
     * Generate database schema and initial data for a defined dialect
     */
    public static void generateDatabase(String dialect) throws IOException {
        // Configure Hibernate
        log.info("Exporting Database Schema...");
        String dbSchema = EnvironmentDetector.getUserHome() + "/schema.sql";
        Configuration cfg = getConfiguration().configure();
        cfg.setProperty("hibernate.dialect", dialect);
        SchemaExport se = new SchemaExport(cfg);
        se.setOutputFile(dbSchema);
        se.setDelimiter(";");
        se.setFormat(false);
        se.create(false, false);
        log.info("Database Schema exported to {}", dbSchema);

        String initialData = new File("").getAbsolutePath() + "/src/main/resources/default.sql";
        log.info("Exporting Initial Data from '{}'...", initialData);
        String initData = EnvironmentDetector.getUserHome() + "/data.sql";
        FileInputStream fis = new FileInputStream(initialData);
        String ret = DatabaseDialectAdapter.dialectAdapter(fis, dialect);
        FileWriter fw = new FileWriter(initData);
        IOUtils.write(ret, fw);
        fw.flush();
        fw.close();
        log.info("Initial Data exported to {}", initData);
    }

    /**
     * Replace "create" or "update" by "none" to prevent repository reset on restart
     */
    @SuppressWarnings("unchecked")
    public static void hibernateCreateAutofix(String configFile) throws IOException {
        FileReader fr = null;
        FileWriter fw = null;

        try {
            // Open and close reader
            fr = new FileReader(configFile);
            List<String> lines = IOUtils.readLines(fr);
            IOUtils.closeQuietly(fr);

            // Modify configuration file
            fw = new FileWriter(configFile);

            for (String line : lines) {
                line = line.trim();
                int idx = line.indexOf("=");

                if (idx > -1) {
                    String key = line.substring(0, idx).trim();
                    String value = line.substring(idx + 1, line.length()).trim();

                    if (Config.PROPERTY_HIBERNATE_HBM2DDL.equals(key)) {
                        value = HBM2DDL_NONE;
                    }

                    fw.write(key + "=" + value + "\n");
                } else {
                    fw.write(line + "\n");
                }
            }

            fw.flush();
        } finally {
            IOUtils.closeQuietly(fr);
            IOUtils.closeQuietly(fw);
        }
    }
}