org.beangle.orm.hibernate.internal.OverrideConfiguration.java Source code

Java tutorial

Introduction

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

Source

/*
 * Beangle, Agile Java/Scala Development Scaffold and Toolkit
 *
 * Copyright (c) 2005-2013, Beangle Software.
 *
 * Beangle is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Beangle 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Beangle.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.beangle.orm.hibernate.internal;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.beangle.commons.collection.CollectUtils;
import org.beangle.orm.hibernate.RailsNamingStrategy;
import org.beangle.orm.hibernate.TableNamingStrategy;
import org.beangle.orm.hibernate.TableSeqGenerator;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.hibernate.DuplicateMappingException;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Mappings;
import org.hibernate.cfg.SettingsFactory;
import org.hibernate.internal.util.xml.ErrorLogger;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.IdGenerator;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Table;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;

/**
 * Provide schema reconfig and overriderable class mapping in sessionFactory
 * 
 * @author chaostone
 * @since 2.1
 */
@SuppressWarnings("serial")
public class OverrideConfiguration extends Configuration {

    private static Logger logger = LoggerFactory.getLogger(OverrideConfiguration.class);

    private int dynaupdateMinColumn = 7;

    public OverrideConfiguration() {
        super();
    }

    public OverrideConfiguration(SettingsFactory settingsFactory) {
        super(settingsFactory);
    }

    /**
     * Just disable xml file validation.
     */
    @Override
    protected Configuration doConfigure(InputStream stream, String resourceName) throws HibernateException {
        try {
            ErrorLogger errorLogger = new ErrorLogger(resourceName);
            SAXReader reader = xmlHelper.createSAXReader(errorLogger, getEntityResolver());
            reader.setValidation(false);
            Document document = reader.read(new InputSource(stream));
            if (errorLogger.hasErrors()) {
                throw new MappingException("invalid configuration", errorLogger.getErrors().get(0));
            }
            doConfigure(document);
        } catch (DocumentException e) {
            throw new HibernateException("Could not parse configuration: " + resourceName, e);
        } finally {
            try {
                stream.close();
            } catch (IOException ioe) {
                logger.error("Could not close input stream for {}", resourceName);
            }
        }
        return this;
    }

    @Override
    public Mappings createMappings() {
        return new OverrideMappings();
    }

    /**
     * Config table's schema by TableNamingStrategy
     */
    private void configSchema() {
        TableNamingStrategy namingStrategy = null;
        if (getNamingStrategy() instanceof RailsNamingStrategy) {
            namingStrategy = ((RailsNamingStrategy) getNamingStrategy()).getTableNamingStrategy();
        }

        if (null == namingStrategy)
            return;
        else {
            // Update SeqGenerator's static variable.
            // Because generator is init by hibernate,cannot inject namingStrategy.
            TableSeqGenerator.namingStrategy = namingStrategy;
        }

        if (namingStrategy.isMultiSchema()) {
            for (PersistentClass clazz : classes.values()) {
                String schema = namingStrategy.getSchema(clazz.getEntityName());
                if (null != schema)
                    clazz.getTable().setSchema(schema);
            }

            for (Collection collection : collections.values()) {
                final Table table = collection.getCollectionTable();
                if (null == table)
                    continue;
                String schema = namingStrategy.getSchema(collection.getRole());
                if (null != schema)
                    table.setSchema(schema);
            }
        }
    }

    /**
     * Update persistentclass and collection's schema.
     * 
     * @see #addClass(Class)
     */
    @Override
    protected void secondPassCompile() throws MappingException {
        super.secondPassCompile();
        configSchema();
        // remove duplicated persistentClass register in classes map.
        Set<String> hackedEntityNames = CollectUtils.newHashSet();
        for (Map.Entry<String, PersistentClass> entry : classes.entrySet()) {
            if (!entry.getKey().equals(entry.getValue().getEntityName()))
                hackedEntityNames.add(entry.getKey());
        }
        for (String entityName : hackedEntityNames) {
            classes.remove(entityName);
        }
    }

    protected class OverrideMappings extends MappingsImpl {
        private final Map<String, List<Collection>> tmpColls = CollectUtils.newHashMap();

        /**
         * ?sequence?
         */
        public OverrideMappings() {
            super();
            IdGenerator idGen = new IdGenerator();
            idGen.setName("table_sequence");
            idGen.setIdentifierGeneratorStrategy(TableSeqGenerator.class.getName());
            this.addDefaultGenerator(idGen);
        }

        /**
         * 1.First change jpaName to entityName
         * 2.Duplicate register persistent class
         */
        @SuppressWarnings("unchecked")
        @Override
        public void addClass(PersistentClass pClass) throws DuplicateMappingException {
            // trigger dynamic update
            if (!pClass.useDynamicUpdate() && pClass.getTable().getColumnSpan() >= dynaupdateMinColumn)
                pClass.setDynamicUpdate(true);

            String jpaEntityName = pClass.getJpaEntityName();
            String entityName = pClass.getEntityName();
            String className = entityName;
            boolean entityNameChanged = false;
            // Set real entityname using jpaEntityname
            if (null != jpaEntityName && jpaEntityName.contains(".")) {
                entityName = jpaEntityName;
                pClass.setEntityName(entityName);
                entityNameChanged = true;
            }
            // register class
            PersistentClass old = (PersistentClass) classes.get(entityName);
            if (old == null) {
                classes.put(entityName, pClass);
            } else if (old.getMappedClass().isAssignableFrom(pClass.getMappedClass())) {
                classes.put(entityName, pClass);
                logger.info("{} override {} for entity configuration", pClass.getClassName(), old.getClassName());
            }
            // hibernateToOneFkSecondPass?,isInPrimaryKey??classNamepersistentClass??entityName
            if (entityNameChanged)
                classes.put(className, pClass);

            // add entitis collections
            List<Collection> cols = tmpColls.remove(entityName);
            if (null == cols)
                cols = tmpColls.remove(className);
            if (null != cols) {
                for (Collection col : cols) {
                    String colName = null;
                    if (col.getRole().startsWith(className))
                        colName = col.getRole().substring(className.length() + 1);
                    else
                        colName = col.getRole().substring(entityName.length() + 1);
                    col.setRole(entityName + "." + colName);
                    collections.put(col.getRole(), col);
                }
            }
        }

        @Override
        public void addImport(String entityName, String rename) throws DuplicateMappingException {
            String existing = imports.get(rename);
            if (null == existing) {
                imports.put(rename, entityName);
            } else {
                if (ClassLoaders.loadClass(existing).isAssignableFrom(ClassLoaders.loadClass(entityName))) {
                    imports.put(rename, entityName);
                } else
                    throw new DuplicateMappingException("duplicate import: " + rename + " refers to both "
                            + entityName + " and " + existing + " (try using auto-import=\"false\")", "import",
                            rename);
            }
        }

        /**
         * <ul>
         * <li>Provide override collections with same rolename.
         * <li>Delay register collection,register by addClass method
         * </ul>
         */
        @Override
        public void addCollection(Collection collection) throws DuplicateMappingException {
            String entityName = collection.getOwnerEntityName();
            List<Collection> cols = tmpColls.get(entityName);
            if (null == cols) {
                cols = CollectUtils.newArrayList();
                tmpColls.put(entityName, cols);
            }
            cols.add(collection);
        }
    }

    public int getDynaupdateMinColumn() {
        return dynaupdateMinColumn;
    }

    public void setDynaupdateMinColumn(int dynaupdateMinColumn) {
        this.dynaupdateMinColumn = dynaupdateMinColumn;
    }

}