Package org.beangle.model.persist.hibernate

Source Code of org.beangle.model.persist.hibernate.SchemaValidator

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

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.collection.CollectUtils;
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;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;

/**
* @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 LocalSessionFactoryBean 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");
      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" })
  // 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(LocalSessionFactoryBean sessionFactoryBean) {
    this.sessionFactoryBean = sessionFactoryBean;
  }

}
TOP

Related Classes of org.beangle.model.persist.hibernate.SchemaValidator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.