org.olat.core.commons.persistence.DatabaseSetup.java Source code

Java tutorial

Introduction

Here is the source code for org.olat.core.commons.persistence.DatabaseSetup.java

Source

/**
 * OLAT - Online Learning and Training<br>
 * http://www.olat.org
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); <br>
 * you may not use this file except in compliance with the License.<br>
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing,<br>
 * software distributed under the License is distributed on an "AS IS" BASIS, <br>
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
 * See the License for the specific language governing permissions and <br>
 * limitations under the License.
 * <p>
 * Copyright (c) 1999-2006 at Multimedia- & E-Learning Services (MELS),<br>
 * University of Zurich, Switzerland.
 * <p>
 */

package org.olat.core.commons.persistence;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.MappingException;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
import org.olat.core.CoreSpringFactory;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.springframework.core.io.Resource;

/**
 * Initial Date: 25.10.2002
 * 
 * @author Florian Gnaegi Comment: Use this class to create the initial OLAT database
 */
public class DatabaseSetup {
    private static final OLog log = Tracing.createLoggerFor(DatabaseSetup.class);

    private static Configuration cf;

    /**
     * Method datastoreConfiguration is the central mapping definition of all OLAT objects and their mapping to a relational database. When a new mapping is accomplished,
     * it has to be added here.
     * 
     * @return Datastore
     * @throws MappingException
     */
    public static Configuration datastoreConfiguration() throws MappingException {
        cf = new Configuration();
        List<String> filesAlreadyAdded = new ArrayList<String>();
        List<String> ignoredFiles = new ArrayList<String>();

        // TODO
        // loading hbm files out of a jar needs an start root directory. So change it to:
        // CoreSpringFactory.getResources("classpath*:org/**/*.hbm.xml");
        // If you do the fix above you also need to ensure that no *hbm.xml files are
        // present both in .jars and in WEB-INF/classes, otherwise the startup process
        // will fail.

        ignoredFiles.add("LoggingObject.hbm.xml");
        ignoredFiles.add("UserCommentImpl.hbm.xml");
        ignoredFiles.add("UserRatingImpl.hbm.xml");
        addHibernateFilesMatching("classpath*:**/*.hbm.xml", filesAlreadyAdded, ignoredFiles);

        // OLAT-4109 : the LoggingAction.hbm.xml file is in the core jar and is not found
        // since it's not in the classes directory but in the jar.
        // as documented above, when you want to have hbm.xml files
        // found by the CoreSpringFactory.getResources() method
        // you can't just specify "classpath*:**/*.hbm.xml"
        // but need to specify at least the first path segment,
        // i.e. it will work when you do this: "classpath*:org/**/*.hbm.xml"
        // Now the problem with this is that it will find too
        // many - i.e. it will find duplicates if you have some in a jar
        // and some in the classpath
        // To fix this we now just restrict it to loggingObject -
        // plus adding the ignoredFiles "trick"
        // TODO
        // Might be an idea to generalize this whole way we deal with this
        // i.e. we have the core jar which can contain any htm.xml or spring.xml files
        // so for production we want to add load them here - but for
        // development we have the core java directory mounted so we have
        // under classes as well - hence the whole problem
        addHibernateFilesMatching("classpath*:org/**/LoggingObject.hbm.xml", filesAlreadyAdded,
                new ArrayList<String>());
        addHibernateFilesMatching("classpath*:org/**/UserCommentImpl.hbm.xml", filesAlreadyAdded,
                new ArrayList<String>());
        addHibernateFilesMatching("classpath*:org/**/UserRatingImpl.hbm.xml", filesAlreadyAdded,
                new ArrayList<String>());

        return cf;
    }

    private static void addHibernateFilesMatching(final String resourcePath, List<String> filesAlreadyAdded,
            List<String> ignoredFiles) {
        Resource[] ress = CoreSpringFactory.getResources(resourcePath);
        for (int i = 0; i < ress.length; i++) {
            Resource res = ress[i];
            InputStream is;
            String fileName = res.getFilename();
            if (ignoredFiles.contains(fileName)) {
                // then ignore it - dont log either
                continue;
            }
            if (!filesAlreadyAdded.contains(fileName)) {
                filesAlreadyAdded.add(fileName);
                try {
                    log.info("Start adding hibernate mapping (xml mapping stream): " + res.getDescription());
                    is = res.getInputStream();
                    cf.addInputStream(is);
                    log.info("Loaded hibernate mapping (xml mapping stream): " + res.getDescription());
                } catch (IOException e) {
                    throw new AssertException(
                            "i/o error while getting inputstream of resource:" + res.getDescription());
                }
            } else {
                log.warn("Douplicate hibernate mapping file::" + fileName + " found on classpath, skipping "
                        + res.toString());
            }
        }
    }

    /**
     * Execute commands from the command line: 'setup' or 'drop' currently available
     * 
     * @param args One of createTables, dropTables, toFile, updateDDL
     * @throws Exception e.g. DatabaseSetup org.hibernate.dialect.MySQLDialect createScript
     */
    public static void main(String[] args) throws Exception {
        if (args.length == 2) {
            cf = datastoreConfiguration();
            cf.setProperty("hibernate.dialect", args[0]);
            if (args[1].equals("createTables"))
                createTables();
            else if (args[1].equals("dropTables"))
                dropTables();
            else if (args[1].equals("createScript"))
                exportDDLtoFile();
            else if (args[1].equals("updateDDL"))
                updateDatabaseDDL();
        } else { // write to file as default see database/setupDatabase.sql
            System.out.println(
                    "Usage: DatabaseSetup DIALECT ACTION\nwhere ACTION is one of: createTables | dropTables | createScript | updateDLL");
        }
    }

    /**
     * Setup OLAT database. This will drop all tables first if available.
     * 
     * @throws Exception
     */
    public static void createTables() throws Exception {
        log.info("Creating tables");
        new SchemaExport(cf).create(false, true); // set first bolean to true for debugging.
    }

    /**
     * Drop all OLAT tables
     * 
     * @throws Exception
     */
    public static void dropTables() throws Exception {
        log.info("Dropping tables");
        new SchemaExport(cf).drop(false, true);
    }

    /**
     * Generates alter database DDL and EXECUTES it.
     */
    private static void updateDatabaseDDL() {
        boolean printToOut = true; // write to System.out
        boolean updateDatabase = false;
        try {
            new SchemaUpdate(cf).execute(printToOut, updateDatabase);
        } catch (Exception e) {
            log.error("DDL export to file failed: Reason: ", e);
        }
    }

    /**
     * Write database configuration to file. Includes differences to existing database. Filename: "database/setupDatabase.sql"
     */
    private static void exportDDLtoFile() {
        String outputFile = "database/setupDatabase.sql";

        boolean script = true; // write DDL
        boolean export = false; // don't update databse
        try {
            SchemaExport se = new SchemaExport(cf);
            se.setOutputFile(outputFile);
            se.setDelimiter(";");
            se.create(script, export);
        } catch (Exception e) {
            log.error("DDL export to file failed: Reason: ", e);
        }
    }
}