All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.impetus.kundera.configure.SchemaConfiguration Maven / Gradle / Ivy

There is a newer version: 2.9
Show newest version
/*******************************************************************************
 * * Copyright 2012 Impetus Infotech.
 *  *
 *  * Licensed under the Apache License, Version 2.0 (the "License");
 *  * you may not use this file except in compliance with the License.
 *  * You may obtain a copy of the License at
 *  *
 *  *      http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  * Unless required by applicable law or agreed to in writing, software
 *  * distributed under the License is distributed on an "AS IS" BASIS,
 *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  * See the License for the specific language governing permissions and
 *  * limitations under the License.
 ******************************************************************************/
package com.impetus.kundera.configure;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.DiscriminatorColumn;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;
import javax.persistence.metamodel.SingularAttribute;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.impetus.kundera.PersistenceProperties;
import com.impetus.kundera.client.ClientResolver;
import com.impetus.kundera.configure.schema.CollectionColumnInfo;
import com.impetus.kundera.configure.schema.ColumnInfo;
import com.impetus.kundera.configure.schema.EmbeddedColumnInfo;
import com.impetus.kundera.configure.schema.IndexInfo;
import com.impetus.kundera.configure.schema.SchemaGenerationException;
import com.impetus.kundera.configure.schema.TableInfo;
import com.impetus.kundera.configure.schema.api.SchemaManager;
import com.impetus.kundera.loader.ClientFactory;
import com.impetus.kundera.metadata.KunderaMetadataManager;
import com.impetus.kundera.metadata.MetadataUtils;
import com.impetus.kundera.metadata.model.ApplicationMetadata;
import com.impetus.kundera.metadata.model.EntityMetadata;
import com.impetus.kundera.metadata.model.EntityMetadata.Type;
import com.impetus.kundera.metadata.model.IdDiscriptor;
import com.impetus.kundera.metadata.model.JoinTableMetadata;
import com.impetus.kundera.metadata.model.KunderaMetadata;
import com.impetus.kundera.metadata.model.MetamodelImpl;
import com.impetus.kundera.metadata.model.PersistenceUnitMetadata;
import com.impetus.kundera.metadata.model.PropertyIndex;
import com.impetus.kundera.metadata.model.Relation;
import com.impetus.kundera.metadata.model.Relation.ForeignKey;
import com.impetus.kundera.metadata.model.attributes.AbstractAttribute;
import com.impetus.kundera.metadata.model.type.AbstractManagedType;
import com.impetus.kundera.metadata.processor.IndexProcessor;
import com.impetus.kundera.metadata.validator.EntityValidator;
import com.impetus.kundera.metadata.validator.EntityValidatorImpl;
import com.impetus.kundera.property.PropertyAccessorHelper;
import com.impetus.kundera.utils.KunderaCoreUtils;

/**
 * Schema configuration implementation to support ddl_schema_creation
 * functionality. e.g. kundera_ddl_auto_prepare
 * (create,create-drop,validate,update)
 * 
 * @author Kuldeep.Kumar
 * 
 */
public class SchemaConfiguration extends AbstractSchemaConfiguration implements Configuration
{
    /** The log. */
    private static Logger log = LoggerFactory.getLogger(SchemaConfiguration.class);

    /**
     * pu to schema metadata map .
     */
    private Map> puToSchemaMetadata = new HashMap>();

    /**
     * Constructor using persistence units as parameter.
     * 
     * @param persistenceUnits
     *            persistence units.
     */
    public SchemaConfiguration(Map externalProperties, String... persistenceUnits)
    {
        super(persistenceUnits, externalProperties);
    }

    @Override
    /**
     * configure method responsible for creating pu to schema metadata map for each entity in class path.
     * 
     */
    public void configure()
    {
        ApplicationMetadata appMetadata = KunderaMetadata.INSTANCE.getApplicationMetadata();

        EntityValidator validator = new EntityValidatorImpl(externalPropertyMap);

        // TODO, FIXME: Refactoring is required.
        for (String persistenceUnit : persistenceUnits)
        {
            log.info("Configuring schema export for : " + persistenceUnit);
            List tableInfos = getSchemaInfo(persistenceUnit);

            Map entityMetadataMap = getEntityMetadataCol(appMetadata, persistenceUnit);

            PersistenceUnitMetadata puMetadata = appMetadata.getPersistenceUnitMetadata(persistenceUnit);

            // Iterate each entity metadata.
            for (EntityMetadata entityMetadata : entityMetadataMap.values())
            {
                // get entity metadata(table info as well as columns)
                // if table info exists, get it from map.
                boolean found = false;
                
                Type type = entityMetadata.getType();
                Class idClassName = entityMetadata.getIdAttribute() != null ? entityMetadata.getIdAttribute()
                        .getJavaType() : null;

                String idName = entityMetadata.getIdAttribute() != null ? ((AbstractAttribute) entityMetadata
                        .getIdAttribute()).getJPAColumnName() : null;

                TableInfo tableInfo = new TableInfo(entityMetadata.getTableName(), type.name(), idClassName, idName);

                // check for tableInfos not empty and contains the present
                // tableInfo.
                if (!tableInfos.isEmpty() && tableInfos.contains(tableInfo))
                {
                    found = true;
                    int idx = tableInfos.indexOf(tableInfo);
                    tableInfo = tableInfos.get(idx);
                    addColumnToTableInfo(entityMetadata, type, tableInfo);
                }
                else
                {
                    addColumnToTableInfo(entityMetadata, type, tableInfo);
                }

                List relations = entityMetadata.getRelations();

                parseRelations(persistenceUnit, tableInfos, entityMetadata, tableInfo, relations);

                if (!found)
                {
                    tableInfos.add(tableInfo);
                }
                // Add table for GeneratedValue if opted TableStrategy
                addTableGenerator(appMetadata, persistenceUnit, tableInfos, entityMetadata, idClassName, idName);

                // Validating entity against counter column family.
                validator.validateEntity(entityMetadata.getEntityClazz());
            }

            puToSchemaMetadata.put(persistenceUnit, tableInfos);

        }

        // Need to iterate, as in case of non unary relations
        for (String persistenceUnit : persistenceUnits)
        {
            PersistenceUnitMetadata puMetadata = appMetadata.getPersistenceUnitMetadata(persistenceUnit);

            Map externalPuMap = externalPropertyMap;

            // in case of polyglot.
            if (persistenceUnits.length > 1 && externalPropertyMap != null)
            {
                externalPuMap = (Map) externalPropertyMap.get(persistenceUnit);
            }
            if (externalPuMap != null && externalPuMap.get(PersistenceProperties.KUNDERA_DDL_AUTO_PREPARE) != null
                    || puMetadata.getProperty(PersistenceProperties.KUNDERA_DDL_AUTO_PREPARE) != null)
            {
                SchemaManager schemaManager = getSchemaManagerForPu(persistenceUnit);

                if (schemaManager != null)
                {
                    schemaManager.exportSchema(persistenceUnit, puToSchemaMetadata.get(persistenceUnit));
                }
            }
        }
    }

    /**
     * Return schema manager for pu.
     * 
     * @param persistenceUnit
     * @return
     */
    private SchemaManager getSchemaManagerForPu(final String persistenceUnit)
    {
        SchemaManager schemaManager = null;
        Map externalProperties = KunderaCoreUtils.getExternalProperties(persistenceUnit,
                externalPropertyMap, persistenceUnits);
        if (getSchemaProperty(persistenceUnit, externalProperties) != null
                && !getSchemaProperty(persistenceUnit, externalProperties).isEmpty())
        {
            ClientFactory clientFactory = ClientResolver.getClientFactory(persistenceUnit);
            schemaManager = clientFactory != null ? clientFactory.getSchemaManager(externalProperties) : null;
        }
        return schemaManager;
    }

    /**
     * Add tableGenerator to table info.
     * 
     * @param appMetadata
     * @param persistenceUnit
     * @param tableInfos
     * @param entityMetadata
     * @param idClassName
     * @param idName
     * @param isCompositeId
     */
    private void addTableGenerator(ApplicationMetadata appMetadata, String persistenceUnit, List tableInfos,
            EntityMetadata entityMetadata, Class idClassName, String idName)
    {
        Metamodel metamodel = appMetadata.getMetamodel(persistenceUnit);
        IdDiscriptor keyValue = ((MetamodelImpl) metamodel).getKeyValue(entityMetadata.getEntityClazz().getName());
        if (keyValue != null && keyValue.getTableDiscriptor() != null)
        {
            TableInfo tableGeneratorDiscriptor = new TableInfo(keyValue.getTableDiscriptor().getTable(),
                    "CounterColumnType", String.class, idName);
            if (!tableInfos.contains(tableGeneratorDiscriptor))
            {
                tableGeneratorDiscriptor.addColumnInfo(getJoinColumn(tableGeneratorDiscriptor, keyValue
                        .getTableDiscriptor().getValueColumnName(), Long.class));
                tableInfos.add(tableGeneratorDiscriptor);
            }
        }
    }

    /**
     * parse the relations of entites .
     * 
     * @param persistenceUnit
     * @param tableInfos
     * @param entityMetadata
     * @param tableInfo
     * @param relations
     */
    private void parseRelations(String persistenceUnit, List tableInfos, EntityMetadata entityMetadata,
            TableInfo tableInfo, List relations)
    {
        for (Relation relation : relations)
        {
            Class entityClass = relation.getTargetEntity();
            EntityMetadata targetEntityMetadata = KunderaMetadataManager.getEntityMetadata(entityClass);
            if (targetEntityMetadata == null)
            {
                log.error("Persistence unit for class : " + entityClass + " is not loaded");
                throw new SchemaGenerationException("Persistence unit for class : " + entityClass + " is not loaded");
            }
            ForeignKey relationType = relation.getType();

            // if relation type is one to many or join by primary key
            if (targetEntityMetadata != null && relationType.equals(ForeignKey.ONE_TO_MANY)
                    && relation.getJoinColumnName() != null)
            {
                // if self association
                if (targetEntityMetadata.equals(entityMetadata))
                {
                    tableInfo.addColumnInfo(getJoinColumn(tableInfo, relation.getJoinColumnName(), entityMetadata
                            .getIdAttribute().getJavaType()));
                }
                else
                {
                    String pu = targetEntityMetadata.getPersistenceUnit();
                    Type targetEntityType = targetEntityMetadata.getType();
                    Class idClass = targetEntityMetadata.getIdAttribute().getJavaType();
                    String idName = ((AbstractAttribute) targetEntityMetadata.getIdAttribute()).getJPAColumnName();
                    TableInfo targetTableInfo = new TableInfo(targetEntityMetadata.getTableName(),
                            targetEntityType.name(), idClass, idName);

                    // In case of different persistence unit. case for poly glot
                    // persistence.
                    if (!pu.equals(persistenceUnit))
                    {
                        List targetTableInfos = getSchemaInfo(pu);

                        addJoinColumnToInfo(relation.getJoinColumnName(), targetTableInfo, targetTableInfos,
                                entityMetadata);

                        // add for newly discovered persistence unit.
                        puToSchemaMetadata.put(pu, targetTableInfos);
                    }
                    else
                    {
                        addJoinColumnToInfo(relation.getJoinColumnName(), targetTableInfo, tableInfos, entityMetadata);
                    }
                }
            }
            // if relation type is one to one or many to one.
            else if (relation.isUnary() && relation.getJoinColumnName() != null)
            {
                tableInfo.addColumnInfo(getJoinColumn(tableInfo, relation.getJoinColumnName(), targetEntityMetadata
                        .getIdAttribute().getJavaType()));
            }
            // if relation type is many to many and relation via join table.
            else if ((relationType.equals(ForeignKey.MANY_TO_MANY)) && (entityMetadata.isRelationViaJoinTable()))
            {
                JoinTableMetadata joinTableMetadata = relation.getJoinTableMetadata();
                String joinTableName = joinTableMetadata != null ? joinTableMetadata.getJoinTableName() : null;
                String joinColumnName = joinTableMetadata != null ? (String) joinTableMetadata.getJoinColumns()
                        .toArray()[0] : null;
                String inverseJoinColumnName = joinTableMetadata != null ? (String) joinTableMetadata
                        .getInverseJoinColumns().toArray()[0] : null;
                if (joinTableName != null)
                {
                    TableInfo joinTableInfo = new TableInfo(joinTableName, Type.COLUMN_FAMILY.name(), String.class,
                            joinColumnName.concat(inverseJoinColumnName));
                    if (!tableInfos.isEmpty() && !tableInfos.contains(joinTableInfo) || tableInfos.isEmpty())
                    {
                        joinTableInfo.addColumnInfo(getJoinColumn(joinTableInfo, joinColumnName, entityMetadata
                                .getIdAttribute().getJavaType()));
                        joinTableInfo.addColumnInfo(getJoinColumn(joinTableInfo, inverseJoinColumnName, entityMetadata
                                .getIdAttribute().getJavaType()));

                        // // Do not delete above lines. Currently join table
                        // columns are of type string only.
                        // // It needs to be fixed later.
                        // joinTableInfo.addColumnInfo(getJoinColumn(joinTableInfo,
                        // joinColumnName, String.class));
                        // joinTableInfo.addColumnInfo(getJoinColumn(joinTableInfo,
                        // inverseJoinColumnName, String.class));

                        tableInfos.add(joinTableInfo);
                    }
                }
            }
        }
    }

    /**
     * adds join column name to the table Info of entity.
     * 
     * @param joinColumn
     * @param targetTableInfo
     * @param targetTableInfos
     */
    private void addJoinColumnToInfo(String joinColumn, TableInfo targetTableInfo, List targetTableInfos,
            EntityMetadata m)
    {
        ColumnInfo columnInfoOfJoinColumn = getJoinColumn(targetTableInfo, joinColumn, m.getIdAttribute()
                .getBindableJavaType());
        if (!targetTableInfos.isEmpty() && targetTableInfos.contains(targetTableInfo))
        {
            int idx = targetTableInfos.indexOf(targetTableInfo);
            targetTableInfo = targetTableInfos.get(idx);
            if (!targetTableInfo.getColumnMetadatas().contains(columnInfoOfJoinColumn))
            {
                targetTableInfo.addColumnInfo(columnInfoOfJoinColumn);
            }
        }
        else
        {
            if (!targetTableInfo.getColumnMetadatas().contains(columnInfoOfJoinColumn))
            {
                targetTableInfo.addColumnInfo(columnInfoOfJoinColumn);
            }
            targetTableInfos.add(targetTableInfo);
        }
    }

    /**
     * Adds column to table info of entity.
     * 
     * @param entityMetadata
     * @param type
     * @param tableInfo
     */
    private void addColumnToTableInfo(EntityMetadata entityMetadata, Type type, TableInfo tableInfo)
    {
        // Add columns to table info.
        Metamodel metaModel = KunderaMetadata.INSTANCE.getApplicationMetadata().getMetamodel(
                entityMetadata.getPersistenceUnit());
        EntityType entityType = metaModel.entity(entityMetadata.getEntityClazz());
        Map columns = entityMetadata.getIndexProperties();

        Set attributes = entityType.getAttributes();

        Iterator iter = attributes.iterator();
        while (iter.hasNext())
        {
            Attribute attr = iter.next();
            if (!attr.isAssociation())
            {
                if (((MetamodelImpl) metaModel).isEmbeddable(attr.getJavaType()))
                {
                    EmbeddableType embeddable = metaModel.embeddable(attr.getJavaType());

                    EmbeddedColumnInfo embeddedColumnInfo = getEmbeddedColumn(tableInfo, embeddable, attr.getName(),
                            attr.getJavaType());

                    if (!tableInfo.getEmbeddedColumnMetadatas().contains(embeddedColumnInfo))
                    {
                        tableInfo.addEmbeddedColumnInfo(embeddedColumnInfo);
                    }
                }
                else if (!attr.isCollection() && !((SingularAttribute) attr).isId())
                {
                    ColumnInfo columnInfo = getColumn(tableInfo, attr,
                            columns != null ? columns.get(((AbstractAttribute) attr).getJPAColumnName()) : null);
                    if (!tableInfo.getColumnMetadatas().contains(columnInfo))
                    {
                        tableInfo.addColumnInfo(columnInfo);
                    }
                }
                else if (attr.isCollection()
                        && MetadataUtils.isBasicElementCollectionField((Field) attr.getJavaMember()))
                {
                    CollectionColumnInfo cci = new CollectionColumnInfo();
                    cci.setCollectionColumnName(((AbstractAttribute) attr).getJPAColumnName());
                    cci.setType(attr.getJavaType());
                    cci.setGenericClasses(PropertyAccessorHelper.getGenericClasses((Field) attr.getJavaMember()));

                    tableInfo.addCollectionColumnMetadata(cci);
                }
            }
        }

        onInheritedProperty(tableInfo, entityType);
    }

    /**
     * Add {@link DiscriminatorColumn} for schema generation.
     * 
     * @param tableInfo
     *            table info.
     * @param entityType
     *            entity type.
     */
    private void onInheritedProperty(TableInfo tableInfo, EntityType entityType)
    {
        String discrColumn = ((AbstractManagedType) entityType).getDiscriminatorColumn();

        if (discrColumn != null)
        {
            ColumnInfo columnInfo = new ColumnInfo();
            columnInfo.setColumnName(discrColumn);
            columnInfo.setType(String.class);
            columnInfo.setIndexable(true);

            IndexInfo idxInfo = new IndexInfo(discrColumn);
            tableInfo.addColumnInfo(columnInfo);
            tableInfo.addToIndexedColumnList(idxInfo);
        }
    }

    /**
     * Returns list of configured table/column families.
     * 
     * @param persistenceUnit
     *            persistence unit, for which schema needs to be fetched.
     * 
     * @return list of {@link TableInfo}
     */
    private List getSchemaInfo(String persistenceUnit)
    {
        List tableInfos = puToSchemaMetadata.get(persistenceUnit);
        // if no TableInfos for given persistence unit.
        if (tableInfos == null)
        {
            tableInfos = new ArrayList();
        }
        return tableInfos;
    }

    /**
     * Returns map of entity metdata {@link EntityMetadata}.
     * 
     * @param appMetadata
     *            application metadata
     * @param persistenceUnit
     *            persistence unit
     * @return map of entity metadata.
     */
    private Map getEntityMetadataCol(ApplicationMetadata appMetadata, String persistenceUnit)
    {
        Metamodel metaModel = appMetadata.getMetamodel(persistenceUnit);
        Map entityMetadataMap = ((MetamodelImpl) metaModel).getEntityMetadataMap();
        return entityMetadataMap;
    }

    /**
     * Get Embedded column info.
     * 
     * @param embeddableType
     * @param embeddableColName
     * @param embeddedEntityClass
     * @return
     */
    private EmbeddedColumnInfo getEmbeddedColumn(TableInfo tableInfo, EmbeddableType embeddableType,
            String embeddableColName, Class embeddedEntityClass)
    {
        EmbeddedColumnInfo embeddedColumnInfo = new EmbeddedColumnInfo(embeddableType);
        embeddedColumnInfo.setEmbeddedColumnName(embeddableColName);
        Map indexedColumns = IndexProcessor.getIndexesOnEmbeddable(embeddedEntityClass);
        List columns = new ArrayList();

        Set attributes = embeddableType.getAttributes();
        Iterator iter = attributes.iterator();

        while (iter.hasNext())
        {
            Attribute attr = iter.next();
            columns.add(getColumn(tableInfo, attr, indexedColumns.get(attr.getName())));
        }
        embeddedColumnInfo.setColumns(columns);
        return embeddedColumnInfo;
    }

    /**
     * getColumn method return ColumnInfo for the given column
     * 
     * @param Object
     *            of Column.
     * @return Object of ColumnInfo.
     */
    private ColumnInfo getColumn(TableInfo tableInfo, Attribute column, PropertyIndex indexedColumn)
    {
        ColumnInfo columnInfo = new ColumnInfo();

        if (column.getJavaType().isEnum())
        {
            columnInfo.setType(String.class);
        }
        else
        {
            columnInfo.setType(column.getJavaType());
        }
        columnInfo.setColumnName(((AbstractAttribute) column).getJPAColumnName());
        if (indexedColumn != null && indexedColumn.getName() != null)
        {
            columnInfo.setIndexable(true);
            IndexInfo indexInfo = new IndexInfo(((AbstractAttribute) column).getJPAColumnName(),
                    indexedColumn.getMax(), indexedColumn.getMin(), indexedColumn.getIndexType());
            tableInfo.addToIndexedColumnList(indexInfo);
            // Add more if required
        }
        return columnInfo;
    }

    /**
     * getJoinColumn method return ColumnInfo for the join column
     * 
     * @param columnType
     * 
     * @param String
     *            joinColumnName.
     * @return ColumnInfo object columnInfo.
     */
    private ColumnInfo getJoinColumn(TableInfo tableInfo, String joinColumnName, Class columnType)
    {
        ColumnInfo columnInfo = new ColumnInfo();
        columnInfo.setColumnName(joinColumnName);
        columnInfo.setIndexable(true);

        IndexInfo indexInfo = new IndexInfo(joinColumnName);
        tableInfo.addToIndexedColumnList(indexInfo);

        columnInfo.setType(columnType);
        return columnInfo;
    }

    /**
     * getKunderaProperty method return auto schema generation property for give
     * persistence unit.
     * 
     * @param externalProperties
     * 
     * @param String
     *            persistenceUnit.
     * @return value of kundera auto ddl in form of String.
     */
    private String getSchemaProperty(String persistenceUnit, Map externalProperties)
    {
        PersistenceUnitMetadata persistenceUnitMetadata = KunderaMetadata.INSTANCE.getApplicationMetadata()
                .getPersistenceUnitMetadata(persistenceUnit);
        String autoDdlOption = externalProperties != null ? (String) externalProperties
                .get(PersistenceProperties.KUNDERA_DDL_AUTO_PREPARE) : null;
        if (autoDdlOption == null)
        {
            autoDdlOption = persistenceUnitMetadata != null ? persistenceUnitMetadata
                    .getProperty(PersistenceProperties.KUNDERA_DDL_AUTO_PREPARE) : null;
        }
        return autoDdlOption;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy