com.manydesigns.portofino.persistence.hibernate.HibernateConfig.java Source code

Java tutorial

Introduction

Here is the source code for com.manydesigns.portofino.persistence.hibernate.HibernateConfig.java

Source

/*
 * Copyright (C) 2005-2013 ManyDesigns srl.  All rights reserved.
 * http://www.manydesigns.com/
 *
 * This 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.
 *
 * This software 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 this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package com.manydesigns.portofino.persistence.hibernate;

import com.manydesigns.elements.reflection.JavaClassAccessor;
import com.manydesigns.elements.reflection.PropertyAccessor;
import com.manydesigns.portofino.database.StringBooleanType;
import com.manydesigns.portofino.model.database.*;
import com.manydesigns.portofino.model.database.ForeignKey;
import liquibase.database.structure.ForeignKeyConstraintType;
import org.hibernate.FetchMode;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Mappings;
import org.hibernate.id.IncrementGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.id.enhanced.TableGenerator;
import org.hibernate.mapping.*;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.PrimaryKey;
import org.hibernate.mapping.Table;
import org.hibernate.type.*;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Types;
import java.text.MessageFormat;
import java.util.*;
import java.util.List;

/**
 * @author Giampiero Granatella - giampiero.granatella@manydesigns.com
 * @author Angelo    Lupo       - angelo.lupo@manydesigns.com
 * @author Paolo     Predonzani - paolo.predonzani@manydesigns.com
 */
public class HibernateConfig {

    protected final ConnectionProvider connectionProvider;
    protected final org.apache.commons.configuration.Configuration portofinoConfiguration;
    private static final boolean LAZY = true;
    public static final Logger logger = LoggerFactory.getLogger(HibernateConfig.class);

    //String values for the mapping of boolean values to CHAR/VARCHAR columns
    private String trueString = "T";
    private String falseString = "F";

    public HibernateConfig(ConnectionProvider connectionProvider,
            org.apache.commons.configuration.Configuration portofinoConfiguration) {
        this.connectionProvider = connectionProvider;
        this.portofinoConfiguration = portofinoConfiguration;
    }

    public Configuration buildSessionFactory(Database database) {
        try {
            Configuration configuration = new Configuration();

            setupConnection(configuration);
            setupConfigurationProperties(configuration);

            Mappings mappings = configuration.createMappings();

            //Class Mapping
            classMapping(database, mappings);
            //One2Many Mapping
            o2mMapping(database, configuration, mappings);
            //Many2One Mapping
            m2oMapping(database, configuration, mappings);

            return configuration;
        } catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            ex.printStackTrace();
            throw new ExceptionInInitializerError(ex);
        }
    }

    protected void setupConfigurationProperties(Configuration configuration) {
        configuration
                .setProperty("hibernate.current_session_context_class",
                        "org.hibernate.context.ThreadLocalSessionContext") //hb4: "org.hibernate.context.internal.ThreadLocalSessionContext"
                .setProperty("org.hibernate.hql.ast.AST", "true")
                .setProperty("hibernate.globally_quoted_identifiers", "false");
        // mettendo la modalit dynamic map, non funzionano le entit mappate su bean.
        // configuration.setProperty("hibernate.default_entity_mode", "dynamic-map");
    }

    protected void setupConnection(Configuration configuration) {
        if (!connectionProvider.getDatabasePlatform().isDialectAutodetected()) {
            configuration.setProperty("hibernate.dialect",
                    connectionProvider.getDatabasePlatform().getHibernateDialect().getClass().getName());
        }
        if (connectionProvider instanceof JdbcConnectionProvider) {
            JdbcConnectionProvider jdbcConnectionProvider = (JdbcConnectionProvider) connectionProvider;
            configuration.setProperty("hibernate.connection.url", jdbcConnectionProvider.getActualUrl());
            configuration.setProperty("hibernate.connection.driver_class", jdbcConnectionProvider.getDriver());
            if (jdbcConnectionProvider.getUsername() != null) {
                configuration.setProperty("hibernate.connection.username", jdbcConnectionProvider.getUsername());
            }
            if (jdbcConnectionProvider.getPassword() != null) {
                configuration.setProperty("hibernate.connection.password", jdbcConnectionProvider.getPassword());
            }
        } else if (connectionProvider instanceof JndiConnectionProvider) {
            JndiConnectionProvider jndiConnectionProvider = (JndiConnectionProvider) connectionProvider;
            configuration.setProperty("hibernate.connection.datasource", jndiConnectionProvider.getJndiResource());
        } else {
            throw new Error("Unsupported connection provider: " + connectionProvider);
        }
    }

    private Mappings classMapping(Database database, Mappings mappings) {

        for (Schema schema : database.getSchemas()) {
            for (com.manydesigns.portofino.model.database.Table aTable : schema.getTables()) {
                logger.debug("Class - {}", aTable.getQualifiedName());
                com.manydesigns.portofino.model.database.PrimaryKey primaryKey = aTable.getPrimaryKey();
                if (primaryKey == null) {
                    logger.debug("Skipping table without primary key: {}", aTable.getQualifiedName());
                    continue;
                }
                if (!primaryKey.isValid()) {
                    logger.debug("Skipping table with invalid primary key: {}", aTable.getQualifiedName());
                    continue;
                }
                RootClass clazz = createTableMapping(mappings, aTable);
                if (clazz != null) {
                    mappings.addClass(clazz);
                    mappings.addImport(clazz.getEntityName(), clazz.getEntityName());
                }
            }
        }
        return mappings;
    }

    private void m2oMapping(Database database, Configuration configuration, Mappings mappings) {
        for (Schema schema : database.getSchemas()) {
            for (com.manydesigns.portofino.model.database.Table aTable : schema.getTables()) {
                for (ForeignKey rel : aTable.getForeignKeys()) {
                    logger.debug(MessageFormat.format("Many to one - {0} {1}", aTable.getQualifiedName(),
                            rel.getName()));
                    createM2O(configuration, mappings, rel);
                }
            }
        }
    }

    private void o2mMapping(Database database, Configuration configuration, Mappings mappings) {
        for (Schema schema : database.getSchemas()) {
            for (com.manydesigns.portofino.model.database.Table aTable : schema.getTables()) {
                for (ForeignKey rel : aTable.getOneToManyRelationships()) {
                    logger.debug(MessageFormat.format("One to many - {0} {1}", aTable.getQualifiedName(),
                            rel.getName()));
                    createO2M(configuration, mappings, rel);
                }
            }
        }
    }

    protected RootClass createTableMapping(Mappings mappings,
            com.manydesigns.portofino.model.database.Table aTable) {

        Table tab = mappings.addTable(escapeName(aTable.getSchemaName()), null, escapeName(aTable.getTableName()),
                null, false);
        //tab.setName(escapeName(aTable.getTableName()));
        //tab.setSchema(escapeName(aTable.getSchemaName()));
        mappings.addTableBinding(aTable.getSchemaName(), null, aTable.getTableName(), aTable.getTableName(), null);

        RootClass clazz = new RootClass();
        clazz.setEntityName(aTable.getActualEntityName());
        clazz.setJpaEntityName(aTable.getActualEntityName());
        if (aTable.getJavaClass() != null) {
            clazz.setClassName(aTable.getJavaClass());
            clazz.setProxyInterfaceName(aTable.getJavaClass());
        }
        clazz.setLazy(LAZY);
        clazz.setTable(tab);
        //clazz.setNodeName(aTable.getTableName());

        List<com.manydesigns.portofino.model.database.Column> columnList = new ArrayList<com.manydesigns.portofino.model.database.Column>();

        for (com.manydesigns.portofino.model.database.Column modelColumn : aTable.getColumns()) {
            int jdbcType = modelColumn.getJdbcType();
            Class javaType = modelColumn.getActualJavaType();

            //First param = null ==> doesn't really set anything, just check
            boolean hibernateTypeOk = setHibernateType(null, modelColumn, javaType, jdbcType);
            if (hibernateTypeOk) {
                columnList.add(modelColumn);
            } else {
                logger.error(
                        "Cannot find Hibernate type for table: {}, column: {}, jdbc type: {}, type name: {}. Skipping column.",
                        new Object[] { aTable.getQualifiedName(), modelColumn.getColumnName(), jdbcType,
                                javaType != null ? javaType.getName() : null });
            }
        }

        //Primary keys
        List<com.manydesigns.portofino.model.database.Column> columnPKList = aTable.getPrimaryKey().getColumns();

        if (!columnList.containsAll(columnPKList)) {
            logger.error("Primary key refers to some invalid columns, skipping table {}",
                    aTable.getQualifiedName());
            return null;
        }

        if (columnPKList.size() > 1) {
            createPKComposite(mappings, aTable, aTable.getPrimaryKey().getPrimaryKeyName(), clazz, tab,
                    columnPKList);
        } else {
            createPKSingle(mappings, aTable, aTable.getPrimaryKey().getPrimaryKeyName(), clazz, tab, columnPKList);
        }

        //Other columns
        columnList.removeAll(columnPKList);

        for (com.manydesigns.portofino.model.database.Column column : columnList) {
            Column col = createColumn(mappings, tab, column);
            if (col != null) {
                clazz.addProperty(createProperty(column, col.getValue()));
            }
        }

        return clazz;
    }

    protected Column createColumn(Mappings mappings, Table tab,
            com.manydesigns.portofino.model.database.Column column) {
        Column col = new Column();
        col.setName(escapeName(column.getColumnName()));
        col.setLength(column.getLength());
        col.setPrecision(column.getLength());
        col.setScale(column.getScale());
        col.setNullable(column.isNullable());
        String columnType = column.getColumnType();
        int jdbcType = column.getJdbcType();

        col.setSqlTypeCode(jdbcType);
        col.setSqlType(columnType);

        SimpleValue value = new SimpleValue(mappings, tab);
        if (!setHibernateType(value, column, column.getActualJavaType(), jdbcType)) {
            logger.error("Skipping column {}", column.getQualifiedName());
            return null;
        }

        value.addColumn(col);
        tab.addColumn(col);
        mappings.addColumnBinding(column.getColumnName(), col, tab);

        return col;
    }

    protected Property createProperty(com.manydesigns.portofino.model.database.Column column, Value value) {
        Property prop = new Property();
        prop.setName(column.getActualPropertyName());
        //prop.setNodeName(column.getActualPropertyName());
        prop.setValue(value);
        return prop;
    }

    protected void createPKComposite(Mappings mappings, com.manydesigns.portofino.model.database.Table mdTable,
            String pkName, RootClass clazz, Table tab,
            List<com.manydesigns.portofino.model.database.Column> columnPKList) {

        PrimaryKey primaryKey = new PrimaryKey();
        primaryKey.setName(pkName);
        primaryKey.setTable(tab);

        clazz.setEmbeddedIdentifier(true);
        Component component = new Component(mappings, clazz);
        component.setDynamic(mdTable.getActualJavaClass() == null);
        String name;
        name = mdTable.getQualifiedName();

        component.setRoleName(name + ".id");
        component.setEmbedded(true);
        //component.setNodeName("id");
        component.setKey(true);
        component.setNullValue("undefined");

        if (!component.isDynamic()) {
            component.setComponentClassName(mdTable.getJavaClass()); //TODO verificare se non si intende actualJavaClass
        }

        boolean hasErrors = false;
        for (com.manydesigns.portofino.model.database.Column column : columnPKList) {
            if (column == null) {
                throw new InternalError("Null column");
            }

            Column col = createColumn(mappings, tab, column);

            hasErrors = col == null || hasErrors;

            if (col != null) {
                primaryKey.addColumn(col);
                Property prop = createProperty(column, col.getValue());
                prop.setCascade("none");
                //prop.setPropertyAccessorName("property"); interferisce con il generator pi sotto
                prop.setPersistentClass(clazz);
                component.addProperty(prop);

                //Generator not supported for embedded map identifier
                //See https://forum.hibernate.org/viewtopic.php?t=945273
                //See Component.buildIdentifierGenerator()
                /*String columnName = column.getColumnName();
                PrimaryKeyColumn pkCol = mdTable.getPrimaryKey().findPrimaryKeyColumnByName(columnName);
                if(pkCol == null) {
                logger.error("Column without corresponding PrimaryKeyColumn: {}", columnName);
                hasErrors = true;
                continue;
                }
                Generator generator = pkCol.getGenerator();
                setPKColumnGenerator(mappings, clazz, tab, column, value, generator);*/
            }
        }
        if (hasErrors) {
            // TODO PAOLO: se la PK non e' buona, tutta la tabella dovrebbe saltare
            logger.error("Skipping primary key");
            return;
        }

        tab.setIdentifierValue(component);
        clazz.setIdentifier(component);
        clazz.setDiscriminatorValue(name);

        tab.setPrimaryKey(primaryKey);
    }

    protected void createPKSingle(Mappings mappings, com.manydesigns.portofino.model.database.Table mdTable,
            String pkName, RootClass clazz, Table tab,
            List<com.manydesigns.portofino.model.database.Column> columnPKList) {
        PrimaryKeyColumn pkcol = mdTable.getPrimaryKey().getPrimaryKeyColumns().get(0);
        com.manydesigns.portofino.model.database.Column column = columnPKList.get(0);
        final PrimaryKey primaryKey = new PrimaryKey();
        primaryKey.setName(pkName);
        primaryKey.setTable(tab);
        tab.setPrimaryKey(primaryKey);

        Column col = createColumn(mappings, tab, column);

        if (col == null) {
            // TODO PAOLO: se la PK non e' buona, tutta la tabella dovrebbe saltare
            logger.error("Skipping primary key");
            return;
        }

        SimpleValue id = (SimpleValue) col.getValue();
        //Make the defaults explicit. See section 5.1.4.5. Assigned identifiers in the Hibernate reference
        //(http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html)
        id.setIdentifierGeneratorStrategy("assigned");
        id.setNullValue("undefined");

        tab.getPrimaryKey().addColumn(col);

        Property prop = createProperty(column, id);
        clazz.addProperty(prop);
        prop.setPropertyAccessorName(mappings.getDefaultAccess());
        //PropertyGeneration generation = PropertyGeneration.parse(null);
        //prop.setGeneration(generation);

        prop.setInsertable(false);
        prop.setUpdateable(false);

        Generator generator = pkcol.getGenerator();

        setPKColumnGenerator(mappings, clazz, tab, column, id, generator);

        tab.setIdentifierValue(id);
        clazz.setIdentifier(id);
        clazz.setIdentifierProperty(prop);
        clazz.setDiscriminatorValue(mdTable.getQualifiedName());

    }

    protected void setPKColumnGenerator(Mappings mappings, RootClass clazz, Table tab,
            com.manydesigns.portofino.model.database.Column column, SimpleValue id, Generator generator) {
        if (column.isAutoincrement()) {
            manageIdentityGenerator(mappings, tab, id);
        } else if (generator != null) {
            if (generator instanceof SequenceGenerator) {
                manageSequenceGenerator(mappings, tab, id, (SequenceGenerator) generator);
            } else if (generator instanceof com.manydesigns.portofino.model.database.TableGenerator) {
                manageTableGenerator(mappings, tab, id,
                        (com.manydesigns.portofino.model.database.TableGenerator) generator);
            } else if (generator instanceof com.manydesigns.portofino.model.database.IncrementGenerator) {
                manageIncrementGenerator(mappings, tab, id, clazz.getEntityName());
            }
        }
    }

    private void manageIdentityGenerator(Mappings mappings, Table tab, SimpleValue id) {
        id.setIdentifierGeneratorStrategy("identity");
        Properties params = new Properties();
        params.put(PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, mappings.getObjectNameNormalizer());

        params.setProperty(PersistentIdentifierGenerator.SCHEMA, escapeName(tab.getSchema()));
        id.setIdentifierGeneratorProperties(params);
        id.setNullValue(null);
    }

    private void manageSequenceGenerator(Mappings mappings, Table tab, SimpleValue id,
            SequenceGenerator generator) {
        id.setIdentifierGeneratorStrategy("enhanced-sequence");
        Properties params = new Properties();
        params.put(PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, mappings.getObjectNameNormalizer());
        params.put(SequenceStyleGenerator.SEQUENCE_PARAM, escapeName(generator.getName()));
        params.setProperty(SequenceStyleGenerator.SCHEMA, escapeName(tab.getSchema()));
        id.setIdentifierGeneratorProperties(params);
        id.setNullValue(null);
    }

    private void manageTableGenerator(Mappings mappings, Table tab, SimpleValue id,
            com.manydesigns.portofino.model.database.TableGenerator generator) {
        id.setIdentifierGeneratorStrategy("enhanced-table");
        Properties params = new Properties();
        params.put(TableGenerator.TABLE, tab);
        params.put(TableGenerator.TABLE_PARAM, escapeName(generator.getTable()));
        params.put(PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, mappings.getObjectNameNormalizer());
        params.put(TableGenerator.SEGMENT_COLUMN_PARAM, escapeName(generator.getKeyColumn()));
        params.put(TableGenerator.SEGMENT_VALUE_PARAM, generator.getKeyValue());
        params.put(TableGenerator.VALUE_COLUMN_PARAM, escapeName(generator.getValueColumn()));
        params.setProperty(TableGenerator.SCHEMA, escapeName(tab.getSchema()));
        id.setIdentifierGeneratorProperties(params);
        id.setNullValue(null);
    }

    private void manageIncrementGenerator(Mappings mappings, Table tab, SimpleValue id, String entityName) {
        id.setIdentifierGeneratorStrategy("increment");
        Properties params = new Properties();
        params.put(PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, mappings.getObjectNameNormalizer());
        params.setProperty(PersistentIdentifierGenerator.SCHEMA, escapeName(tab.getSchema()));
        params.put(IncrementGenerator.ENTITY_NAME, entityName);
        id.setIdentifierGeneratorProperties(params);
        id.setNullValue(null);
    }

    protected void createO2M(Configuration config, Mappings mappings, ForeignKey relationship) {

        com.manydesigns.portofino.model.database.Table manyMDTable = relationship.getFromTable();
        com.manydesigns.portofino.model.database.Table oneMDTable = relationship.getToTable();

        //Se la classe One non e' dinamica e
        // non ha la proprieta' non inserisco la relazione
        if (oneMDTable.getJavaClass() != null) {
            try {
                Class oneClass = oneMDTable.getActualJavaClass();
                JavaClassAccessor accessor = JavaClassAccessor.getClassAccessor(oneClass);
                PropertyAccessor[] propertyAccessors = accessor.getProperties();
                boolean found = false;
                for (PropertyAccessor propertyAccessor : propertyAccessors) {
                    if (propertyAccessor.getName().equals(relationship.getActualManyPropertyName())) {
                        found = true;
                    }
                }
                if (!found) {
                    logger.warn("Property '{}' not found, skipping relationship {}",
                            relationship.getActualManyPropertyName(), relationship.getQualifiedName());
                    return;
                }
            } catch (Exception e) {
                //se non c'e' non inserisco la relazione
                logger.warn("Property not found, skipping relationship ", e);
                return;
            }
        }
        //relazione virtuali fra Database differenti
        if (!manyMDTable.getDatabaseName().equalsIgnoreCase(oneMDTable.getDatabaseName())) {
            logger.warn("Relationship crosses databases, skipping: {}", relationship.getQualifiedName());
            return;
        }

        String manyMDQualifiedTableName = manyMDTable.getActualEntityName();
        String oneMDQualifiedTableName = oneMDTable.getActualEntityName();

        PersistentClass clazzOne = config.getClassMapping(oneMDQualifiedTableName);
        if (clazzOne == null) {
            logger.error("Cannot find table '{}' as 'one' side of foreign key '{}'. Skipping relationship.",
                    oneMDQualifiedTableName, relationship.getName());
            return;
        }

        PersistentClass clazzMany = config.getClassMapping(manyMDQualifiedTableName);
        if (clazzMany == null) {
            logger.error("Cannot find table '{}' as 'many' side of foreign key '{}'. Skipping relationship.",
                    manyMDQualifiedTableName, relationship.getName());
            return;
        }

        //Uso i Bag perche' i set non funzionano con i componenti dinamici
        Bag set = new Bag(mappings, clazzOne);
        // Mettere Lazy in debug a false per ottenere subito eventuali errori
        // nelle relazioni
        set.setLazy(LAZY);

        set.setRole(
                relationship.getToTable().getActualEntityName() + "." + relationship.getActualManyPropertyName());
        //set.setNodeName(relationship.getActualManyPropertyName());
        set.setCollectionTable(clazzMany.getTable());
        OneToMany oneToMany = new OneToMany(mappings, set.getOwner());
        set.setElement(oneToMany);

        oneToMany.setReferencedEntityName(manyMDQualifiedTableName);

        oneToMany.setAssociatedClass(clazzMany);
        oneToMany.setEmbedded(true);

        set.setSorted(false);
        set.setFetchMode(FetchMode.DEFAULT);
        //Riferimenti alle colonne

        DependantValue dv;
        Table tableMany = clazzMany.getTable();
        Table tableOne = clazzOne.getTable();
        List<Column> oneColumns = new ArrayList<Column>();
        List<Column> manyColumns = new ArrayList<Column>();
        //Chiave multipla
        final List<Reference> refs = relationship.getReferences();
        if (refs.size() > 1) {
            dv = createFKComposite(mappings, relationship, manyMDTable, clazzOne, clazzMany, set, tableMany,
                    tableOne, oneColumns, manyColumns);
        } else { //chiave straniera singola
            dv = createFKSingle(mappings, clazzOne, clazzMany, tableOne, oneColumns, manyColumns, refs);
        }

        tableMany.createForeignKey(relationship.getName(), manyColumns, oneMDQualifiedTableName, oneColumns);

        dv.setNullable(false);
        set.setKey(dv);
        mappings.addCollection(set);

        Property prop = new Property();
        prop.setName(relationship.getActualManyPropertyName());
        //prop.setNodeName(relationship.getActualManyPropertyName());
        prop.setValue(set);
        if (ForeignKeyConstraintType.importedKeyCascade.name().equalsIgnoreCase(relationship.getOnDelete())) {
            prop.setCascade("delete");
        } else {
            prop.setCascade("none");
        }
        clazzOne.addProperty(prop);

        //if(!StringUtils.)
    }

    private DependantValue createFKComposite(Mappings mappings,
            com.manydesigns.portofino.model.database.ForeignKey relationship,
            com.manydesigns.portofino.model.database.Table manyMDTable, PersistentClass clazzOne,
            PersistentClass clazzMany, Bag set, Table tableMany, Table tableOne, List<Column> oneColumns,
            List<Column> manyColumns) {
        DependantValue dv;
        Component component = new Component(mappings, set);
        component.setDynamic(manyMDTable.getActualJavaClass() == null);
        component.setEmbedded(true);
        dv = new DependantValue(mappings, clazzMany.getTable(), component);
        dv.setNullable(true);
        dv.setUpdateable(true);

        for (Reference ref : relationship.getReferences()) {
            String colToName = ref.getToColumn();
            String colToPropertyName = ref.getActualToColumn().getActualPropertyName();
            String colFromName = ref.getFromColumn();
            Iterator it = tableMany.getColumnIterator();
            while (it.hasNext()) {
                Column col = (Column) it.next();
                if (col.getName().equals(colFromName)) {
                    dv.addColumn(col);
                    manyColumns.add(col);
                    break;
                }
            }

            Iterator it2 = tableOne.getColumnIterator();
            while (it2.hasNext()) {
                Column col = (Column) it2.next();
                if (col.getName().equals(colToName)) {
                    oneColumns.add(col);
                    break;
                }
            }
            Property refProp;
            refProp = getRefProperty(clazzOne, colToPropertyName);
            component.addProperty(refProp);
        }
        return dv;
    }

    private DependantValue createFKSingle(Mappings mappings, PersistentClass clazzOne, PersistentClass clazzMany,
            Table tableOne, List<Column> oneColumns, List<Column> manyColumns, List<Reference> refs) {
        DependantValue dv;
        Property refProp;

        Reference reference = refs.get(0);
        String colFromName = reference.getFromColumn();
        String colToName = reference.getToColumn();
        String colToPropertyName = reference.getActualToColumn().getActualPropertyName();
        refProp = getRefProperty(clazzOne, colToPropertyName);
        dv = new DependantValue(mappings, clazzMany.getTable(), refProp.getPersistentClass().getKey());
        dv.setNullable(true);
        dv.setUpdateable(true);

        Iterator it = clazzMany.getTable().getColumnIterator();
        while (it.hasNext()) {
            Column col = (Column) it.next();
            if (col.getName().equals(colFromName)) {
                dv.addColumn(col);
                manyColumns.add(col);
                break;
            }
        }

        Iterator it2 = tableOne.getColumnIterator();
        while (it2.hasNext()) {
            Column col = (Column) it2.next();
            if (col.getName().equals(colToName)) {
                oneColumns.add(col);
                break;
            }
        }
        return dv;
    }

    protected void createM2O(Configuration config, Mappings mappings, ForeignKey relationship) {
        com.manydesigns.portofino.model.database.Table manyMDTable = relationship.getFromTable();
        com.manydesigns.portofino.model.database.Table oneMDTable = relationship.getToTable();
        String manyMDQualifiedTableName = manyMDTable.getActualEntityName();
        String oneMDQualifiedTableName = oneMDTable.getActualEntityName();

        RootClass clazz = (RootClass) mappings.getClass(manyMDQualifiedTableName);
        if (clazz == null) {
            logger.error("Cannot find table '{}' as 'many' side of foreign key '{}'. Skipping relationship.",
                    manyMDQualifiedTableName, relationship.getName());
            return;
        }

        Table tab = clazz.getTable();
        List<String> columnNames = new ArrayList<String>();

        for (Reference ref : relationship.getReferences()) {
            if (ref.getActualFromColumn() == null) {
                logger.error("Missing from column {}, skipping relationship", ref.getFromColumn());
                return;
            }
            columnNames.add(ref.getFromColumn());
        }

        ManyToOne m2o = new ManyToOne(mappings, tab);
        m2o.setLazy(LAZY);
        final HashMap<String, PersistentClass> persistentClasses = new HashMap<String, PersistentClass>();
        persistentClasses.put(oneMDQualifiedTableName, config.getClassMapping(oneMDQualifiedTableName));
        m2o.setReferencedEntityName(oneMDQualifiedTableName);
        m2o.createPropertyRefConstraints(persistentClasses);

        PersistentClass manyClass = config.getClassMapping(manyMDQualifiedTableName);
        for (String columnName : columnNames) {
            Column col = new Column();
            col.setName(escapeName(columnName));
            //Recupero la colonna precedentemente associata alla tabella:
            //essa ha uno uniqueIdentifier generato al momento dell'associazione alla tabella;
            //questo viene utilizzato per disambiguare l'alias della colonna nelle query
            //SQL generate da Hibernate.
            col = manyClass.getTable().getColumn(col);
            if (col == null) {
                logger.error("Column not found in 'many' entity {}: {}, " + "skipping relationship",
                        manyClass.getEntityName(), columnName);
                return;
            }
            m2o.addColumn(col);
        }

        Property prop = new Property();
        prop.setName(relationship.getActualOnePropertyName());
        //prop.setNodeName(relationship.getActualOnePropertyName());
        prop.setValue(m2o);
        prop.setCascade("none"); //TODO era "all", capire
        prop.setInsertable(false);
        prop.setUpdateable(false);
        clazz.addProperty(prop);
    }

    private Property getRefProperty(PersistentClass clazzOne, String propertyName) {
        Property refProp;
        //TODO alessio ha senso questo automatismo?
        if (null != clazzOne.getIdentifierProperty()) {
            refProp = clazzOne.getIdentifierProperty();
        } else if (null != clazzOne.getIdentifier()) {
            refProp = ((Component) clazzOne.getIdentifier()).getProperty(propertyName);
        } else {
            refProp = clazzOne.getProperty(propertyName);
        }
        return refProp;
    }

    private String escapeName(String name) {
        // Portofino handles all tables in a case-sensitive way
        return "`" + name + "`";
    }

    public boolean setHibernateType(@Nullable SimpleValue value,
            com.manydesigns.portofino.model.database.Column column, Class javaType, final int jdbcType) {
        String typeName;
        Properties typeParams = null;
        if (javaType == null) {
            return false;
        }
        if (javaType == Long.class) {
            typeName = LongType.INSTANCE.getName();
        } else if (javaType == Short.class) {
            typeName = ShortType.INSTANCE.getName();
        } else if (javaType == Integer.class) {
            typeName = IntegerType.INSTANCE.getName();
        } else if (javaType == Byte.class) {
            typeName = ByteType.INSTANCE.getName();
        } else if (javaType == Float.class) {
            typeName = FloatType.INSTANCE.getName();
        } else if (javaType == Double.class) {
            typeName = DoubleType.INSTANCE.getName();
        } else if (javaType == Character.class) {
            typeName = CharacterType.INSTANCE.getName();
        } else if (javaType == String.class) {
            typeName = StringType.INSTANCE.getName();
        } else if (java.util.Date.class.isAssignableFrom(javaType)) {
            switch (jdbcType) {
            case Types.DATE:
                typeName = DateType.INSTANCE.getName();
                break;
            case Types.TIME:
                typeName = TimeType.INSTANCE.getName();
                break;
            case Types.TIMESTAMP:
                typeName = TimestampType.INSTANCE.getName();
                break;
            default:
                typeName = null;
            }
        } else if (javaType == Boolean.class) {
            if (jdbcType == Types.BIT || jdbcType == Types.BOOLEAN) {
                typeName = BooleanType.INSTANCE.getName();
            } else if (jdbcType == Types.NUMERIC || jdbcType == Types.DECIMAL || jdbcType == Types.INTEGER
                    || jdbcType == Types.SMALLINT || jdbcType == Types.TINYINT || jdbcType == Types.BIGINT) {
                typeName = NumericBooleanType.INSTANCE.getName();
            } else if (jdbcType == Types.CHAR || jdbcType == Types.VARCHAR) {
                typeName = StringBooleanType.class.getName();
                typeParams = new Properties();
                typeParams.setProperty("true", trueString != null ? trueString : StringBooleanType.NULL);
                typeParams.setProperty("false", falseString != null ? falseString : StringBooleanType.NULL);
                typeParams.setProperty("sqlType", String.valueOf(jdbcType));
            } else {
                typeName = null;
            }
        } else if (javaType == BigDecimal.class) {
            typeName = BigDecimalType.INSTANCE.getName();
        } else if (javaType == BigInteger.class) {
            typeName = BigIntegerType.INSTANCE.getName();
        } else if (javaType == byte[].class) {
            typeName = BlobType.INSTANCE.getName();
        } else {
            typeName = null;
        }

        if (typeName == null) {
            logger.error("Unsupported type (java type: {}, jdbc type: {}) " + "for column '{}'.",
                    new Object[] { javaType, jdbcType, column.getColumnName() });
            return false;
        }

        if (value != null) {
            value.setTypeName(typeName);
            if (typeParams != null) {
                value.setTypeParameters(typeParams);
            }
        }
        return true;
    }

    public String getTrueString() {
        return trueString;
    }

    public void setTrueString(String trueString) {
        this.trueString = trueString;
    }

    public String getFalseString() {
        return falseString;
    }

    public void setFalseString(String falseString) {
        this.falseString = falseString;
    }
}