org.beangle.commons.orm.hibernate.internal.SchemaValidator.java Source code

Java tutorial

Introduction

Here is the source code for org.beangle.commons.orm.hibernate.internal.SchemaValidator.java

Source

/* Copyright c 2005-2012.
 * Licensed under GNU  LESSER General Public License, Version 3.
 * http://www.gnu.org/licenses
 */
package org.beangle.commons.orm.hibernate.internal;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.beangle.commons.collection.CollectUtils;
import org.beangle.commons.orm.hibernate.SessionFactoryBean;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.Mapping;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.IdentifierGeneratorAggregator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.IdentifierCollection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.Table;
import org.hibernate.tool.hbm2ddl.ColumnMetadata;
import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
import org.hibernate.tool.hbm2ddl.TableMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author chaostone
 * @version $Id: SchemaValidator.java Aug 9, 2011 7:45:32 PM chaostone $
 */
public class SchemaValidator {

    private static final Logger logger = LoggerFactory.getLogger(SchemaValidator.class);
    private SessionFactoryBean sessionFactoryBean;

    private StringBuilder reporter = new StringBuilder();

    public String validate() {
        Connection connection = null;
        try {
            connection = sessionFactoryBean.getDataSource().getConnection();
            DatabaseMetadata meta;
            logger.info("fetching database metadata");
            Configuration config = sessionFactoryBean.getConfiguration();
            Dialect dialect = Dialect.getDialect(sessionFactoryBean.getHibernateProperties());
            meta = new DatabaseMetadata(connection, dialect, false);
            return validateSchema(config, dialect, meta);
        } catch (SQLException sqle) {
            logger.error("could not get database metadata", sqle);
            throw new RuntimeException(sqle);
        } finally {
            if (null != connection)
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
        }
    }

    public String validateSchema(Configuration config, Dialect dialect, DatabaseMetadata databaseMetadata) {
        String defaultCatalog = sessionFactoryBean.getHibernateProperties()
                .getProperty(Environment.DEFAULT_CATALOG);
        String defaultSchema = sessionFactoryBean.getHibernateProperties().getProperty(Environment.DEFAULT_SCHEMA);

        Mapping mapping = config.buildMapping();

        Iterator<?> iter = config.getTableMappings();
        while (iter.hasNext()) {
            Table table = (Table) iter.next();
            if (table.isPhysicalTable()) {
                TableMetadata tableInfo = databaseMetadata.getTableMetadata(table.getName(),
                        (table.getSchema() == null) ? defaultSchema : table.getSchema(),
                        (table.getCatalog() == null) ? defaultCatalog : table.getCatalog(), table.isQuoted());
                if (tableInfo == null) {
                    reporter.append("Missing table: " + table.getName() + "\n");
                } else {
                    validateColumns(table, dialect, mapping, tableInfo);
                }
            }
        }

        iter = iterateGenerators(config, dialect);
        while (iter.hasNext()) {
            PersistentIdentifierGenerator generator = (PersistentIdentifierGenerator) iter.next();
            Object key = generator.generatorKey();
            if (!databaseMetadata.isSequence(key) && !databaseMetadata.isTable(key)) {
                throw new HibernateException("Missing sequence or table: " + key);
            }
        }

        return null;
    }

    private void validateColumns(Table table, Dialect dialect, Mapping mapping, TableMetadata tableInfo) {
        Iterator<?> iter = table.getColumnIterator();
        Set<ColumnMetadata> processed = CollectUtils.newHashSet();
        String tableName = Table.qualify(tableInfo.getCatalog(), tableInfo.getSchema(), tableInfo.getName());
        while (iter.hasNext()) {
            Column col = (Column) iter.next();
            ColumnMetadata columnInfo = tableInfo.getColumnMetadata(col.getName());
            if (columnInfo == null) {
                reporter.append("Missing column: " + col.getName() + " in " + tableName);
            } else {
                final boolean typesMatch = col.getSqlType(dialect, mapping).toLowerCase()
                        .startsWith(columnInfo.getTypeName().toLowerCase())
                        || columnInfo.getTypeCode() == col.getSqlTypeCode(mapping);
                if (!typesMatch) {
                    reporter.append("Wrong column type in " + tableName + " for column " + col.getName()
                            + ". Found: " + columnInfo.getTypeName().toLowerCase() + ", expected: "
                            + col.getSqlType(dialect, mapping));
                }
                processed.add(columnInfo);
            }
        }
        // 
        try {
            Field field = tableInfo.getClass().getField("columns");
            @SuppressWarnings("unchecked")
            Set<ColumnMetadata> allColumns = CollectUtils
                    .newHashSet(((Map<String, ColumnMetadata>) field.get(tableInfo)).values());
            allColumns.removeAll(processed);
            if (!allColumns.isEmpty()) {
                for (ColumnMetadata col : allColumns) {
                    reporter.append("Extra column " + col.getName() + " in " + tableName);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    // borrow from Configuration code
    private Iterator<IdentifierGenerator> iterateGenerators(Configuration config, Dialect dialect)
            throws MappingException {

        TreeMap generators = new TreeMap();
        String defaultCatalog = sessionFactoryBean.getHibernateProperties()
                .getProperty(Environment.DEFAULT_CATALOG);
        String defaultSchema = sessionFactoryBean.getHibernateProperties().getProperty(Environment.DEFAULT_SCHEMA);

        for (Iterator<PersistentClass> pcIter = config.getClassMappings(); pcIter.hasNext();) {
            PersistentClass pc = pcIter.next();
            if (!pc.isInherited()) {
                IdentifierGenerator ig = pc.getIdentifier().createIdentifierGenerator(
                        config.getIdentifierGeneratorFactory(), dialect, defaultCatalog, defaultSchema,
                        (RootClass) pc);

                if (ig instanceof PersistentIdentifierGenerator) {
                    generators.put(((PersistentIdentifierGenerator) ig).generatorKey(), ig);
                } else if (ig instanceof IdentifierGeneratorAggregator) {
                    ((IdentifierGeneratorAggregator) ig).registerPersistentGenerators(generators);
                }
            }
        }

        for (Iterator<Collection> collIter = config.getCollectionMappings(); collIter.hasNext();) {
            Collection collection = collIter.next();
            if (collection.isIdentified()) {
                IdentifierGenerator ig = ((IdentifierCollection) collection).getIdentifier()
                        .createIdentifierGenerator(config.getIdentifierGeneratorFactory(), dialect, defaultCatalog,
                                defaultSchema, null);

                if (ig instanceof PersistentIdentifierGenerator) {
                    generators.put(((PersistentIdentifierGenerator) ig).generatorKey(), ig);
                }
            }
        }

        return generators.values().iterator();
    }

    public void setSessionFactoryBean(SessionFactoryBean sessionFactoryBean) {
        this.sessionFactoryBean = sessionFactoryBean;
    }

}