Package org.jboss.as.cmp.jdbc.metadata

Source Code of org.jboss.as.cmp.jdbc.metadata.JDBCRelationshipRoleMetaData

/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* 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 2.1 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 org.jboss.as.cmp.jdbc.metadata;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jboss.as.cmp.jdbc.metadata.parser.ParsedCmpField;
import org.jboss.as.cmp.jdbc.metadata.parser.ParsedRelationshipRole;
import org.jboss.metadata.ejb.spec.RelationRoleMetaData;

/**
* Imutable class which represents one ejb-relationship-role element found in
* the ejb-jar.xml file's ejb-relation elements.
*
* @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
* @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
* @version $Revision: 81030 $
*/
public final class JDBCRelationshipRoleMetaData {
    /**
     * Relation to which this role belongs.
     */
    private final JDBCRelationMetaData relationMetaData;

    /**
     * Role name
     */
    private final String relationshipRoleName;

    /**
     * Should this role have a foreign key constraint?
     */
    private final boolean foreignKeyConstraint;

    /**
     * Should the cascade-delete be batched.
     */
    private final boolean batchCascadeDelete;

    private boolean genIndex;

    /**
     * Type of the cmr field (i.e., collection or set)
     */
    private JDBCReadAheadMetaData readAhead;

    /**
     * Is the multiplicity one? If not, multiplicity is many.
     */
    private final boolean multiplicityOne;

    /**
     * Should this entity be deleted when related entity is deleted.
     */
    private final boolean cascadeDelete;

    /**
     * The entity that has this role.
     */
    private final JDBCEntityMetaData entity;

    /**
     * Name of the entity's cmr field for this role.
     */
    private final String cmrFieldName;

    /**
     * true if this side is navigable
     */
    private final boolean navigable;

    /**
     * Type of the cmr field (i.e., collection or set)
     */
    private final String cmrFieldType;

    /**
     * The other role in this relationship.
     */
    private JDBCRelationshipRoleMetaData relatedRole;

    /**
     * The key fields used by this role by field name.
     */
    private Map<String, JDBCCMPFieldMetaData> keyFields = new HashMap<String, JDBCCMPFieldMetaData>();

    public JDBCRelationshipRoleMetaData(final JDBCRelationMetaData relationMetaData, final JDBCApplicationMetaData application, final RelationRoleMetaData role) {
        this.relationMetaData = relationMetaData;

        relationshipRoleName = role.getEjbRelationshipRoleName();
        multiplicityOne = role.isMultiplicityOne();
        cascadeDelete = role.isCascadedDelete();
        batchCascadeDelete = false;
        foreignKeyConstraint = false;
        readAhead = null;

        String fieldName = role.getCmrField() != null ? role.getCmrField().getCmrFieldName() : null;
        if (fieldName == null) {
            cmrFieldName = generateNonNavigableCMRName(role);
            navigable = false;
        } else {
            cmrFieldName = fieldName;
            navigable = true;
        }
        cmrFieldType = role.getCmrField() != null ? role.getCmrField().getCmrFieldType() : null;
        // get the entity for this role
        entity = application.getBeanByEjbName(role.getRoleSource().getEjbName());
        if (entity == null) {
            throw new IllegalArgumentException("Entity: " + role.getRoleSource().getEjbName() +
                    " not found for relation: " + role.getRelation().getEjbRelationName());
        }
    }

    public JDBCRelationshipRoleMetaData(JDBCRelationMetaData relationMetaData, JDBCApplicationMetaData application, JDBCRelationshipRoleMetaData defaultValues) {
        this.relationMetaData = relationMetaData;
        this.entity = application.getBeanByEjbName(defaultValues.getEntity().getName());

        relationshipRoleName = defaultValues.getRelationshipRoleName();
        multiplicityOne = defaultValues.isMultiplicityOne();
        cascadeDelete = defaultValues.isCascadeDelete();

        cmrFieldName = defaultValues.getCMRFieldName();
        navigable = defaultValues.isNavigable();
        cmrFieldType = defaultValues.getCMRFieldType();

        foreignKeyConstraint = defaultValues.hasForeignKeyConstraint();
        readAhead = entity.getReadAhead();

        batchCascadeDelete = defaultValues.isBatchCascadeDelete();
        if (batchCascadeDelete) {
            if (!cascadeDelete)
                throw new RuntimeException(relationMetaData.getRelationName() + '/' + relationshipRoleName + " has batch-cascade-delete in jbosscmp-jdbc.xml but has no cascade-delete in ejb-jar.xml");

            if (relationMetaData.isTableMappingStyle()) {
                throw new RuntimeException("Relationship " + relationMetaData.getRelationName() + " with relation-table-mapping style was setup for batch cascade-delete." + " Batch cascade-delete supported only for foreign key mapping style.");
            }
        }
    }

    public JDBCRelationshipRoleMetaData(JDBCRelationMetaData relationMetaData, JDBCApplicationMetaData application, ParsedRelationshipRole parsedRelationshipRole, JDBCRelationshipRoleMetaData defaultValues) {
        this.relationMetaData = relationMetaData;
        this.entity = application.getBeanByEjbName(defaultValues.getEntity().getName());

        relationshipRoleName = defaultValues.getRelationshipRoleName();
        multiplicityOne = defaultValues.isMultiplicityOne();
        cascadeDelete = defaultValues.isCascadeDelete();

        cmrFieldName = defaultValues.getCMRFieldName();
        navigable = defaultValues.isNavigable();
        cmrFieldType = defaultValues.getCMRFieldType();

        // foreign key constraint?  If not provided, keep default.
        if (parsedRelationshipRole.getForeignKeyConstraint() != null) {
            foreignKeyConstraint = parsedRelationshipRole.getForeignKeyConstraint();
        } else {
            foreignKeyConstraint = defaultValues.hasForeignKeyConstraint();
        }

        // read-ahead
        if (parsedRelationshipRole.getReadAhead() != null) {
            readAhead = new JDBCReadAheadMetaData(parsedRelationshipRole.getReadAhead(), entity.getReadAhead());
        } else {
            readAhead = entity.getReadAhead();
        }
        batchCascadeDelete = parsedRelationshipRole.getBatchCascadeDelete() != null && parsedRelationshipRole.getBatchCascadeDelete();
        if (batchCascadeDelete) {
            if (!cascadeDelete)
                throw new RuntimeException(
                        relationMetaData.getRelationName() + '/' + relationshipRoleName
                                + " has batch-cascade-delete in jbosscmp-jdbc.xml but has no cascade-delete in ejb-jar.xml"
                );

            if (relationMetaData.isTableMappingStyle()) {
                throw new RuntimeException(
                        "Relationship " + relationMetaData.getRelationName()
                                + " with relation-table-mapping style was setup for batch cascade-delete."
                                + " Batch cascade-delete supported only for foreign key mapping style."
                );
            }
        }
    }

    public void init(final JDBCRelationshipRoleMetaData relatedRole) {
        this.relatedRole = relatedRole;
        keyFields.putAll(loadKeyFields());
    }

    public void init(final JDBCRelationshipRoleMetaData relatedRole, final ParsedRelationshipRole parsedRole) {
        this.relatedRole = relatedRole;
        keyFields.putAll(loadKeyFields(parsedRole));
    }


    /**
     * Gets the relation to which this role belongs.
     */
    public JDBCRelationMetaData getRelationMetaData() {
        return relationMetaData;
    }

    /**
     * Gets the name of this role.
     */
    public String getRelationshipRoleName() {
        return relationshipRoleName;
    }

    /**
     * Should this role use a foreign key constraint.
     *
     * @return true if the store mananager will execute an ALTER TABLE ADD
     *         CONSTRAINT statement to add a foreign key constraint.
     */
    public boolean hasForeignKeyConstraint() {
        return foreignKeyConstraint;
    }

    public boolean isBatchCascadeDelete() {
        return batchCascadeDelete;
    }

    /**
     * Gets the read ahead meta data
     */
    public JDBCReadAheadMetaData getReadAhead() {
        return readAhead;
    }

    public JDBCEntityMetaData getEntity() {
        return entity;
    }

    /**
     * Gets the key fields of this role.
     *
     * @return an unmodifiable collection of JDBCCMPFieldMetaData objects
     */
    public Collection<JDBCCMPFieldMetaData> getKeyFields() {
        return Collections.unmodifiableCollection(keyFields.values());
    }

    public boolean isIndexed() {
        return genIndex;
    }

    private static String generateNonNavigableCMRName(final RelationRoleMetaData role) {
        RelationRoleMetaData relatedRole = role.getRelatedRole();
        return relatedRole.getRoleSource().getEjbName() + "_" + relatedRole.getCmrField().getCmrFieldName();
    }

    /**
     * Checks if the multiplicity is one.
     */
    public boolean isMultiplicityOne() {
        return multiplicityOne;
    }

    /**
     * Checks if the multiplicity is many.
     */
    public boolean isMultiplicityMany() {
        return !multiplicityOne;
    }

    /**
     * Should this entity be deleted when related entity is deleted.
     */
    public boolean isCascadeDelete() {
        return cascadeDelete;
    }

    /**
     * Gets the name of the entity's cmr field for this role.
     */
    public String getCMRFieldName() {
        return cmrFieldName;
    }

    public boolean isNavigable() {
        return navigable;
    }

    /**
     * Gets the type of the cmr field (i.e., collection or set)
     */
    public String getCMRFieldType() {
        return cmrFieldType;
    }

    /**
     * Gets the related role's jdbc meta data.
     */
    public JDBCRelationshipRoleMetaData getRelatedRole() {
        return relationMetaData.getOtherRelationshipRole(this);
    }

    /**
     * Loads the key fields for this role based on the primary keys of the
     * this entity.
     */
    private Map<String, JDBCCMPFieldMetaData> loadKeyFields() {
        // with foreign key mapping, foreign key fields are no added if
        // - it is the many side of one-to-many relationship
        // - it is the one side of one-to-one relationship and related side is not navigable
        if (relationMetaData.isForeignKeyMappingStyle()) {
            if (isMultiplicityMany())
                return Collections.emptyMap();
            else if (getRelatedRole().isMultiplicityOne() && !getRelatedRole().isNavigable())
                return Collections.emptyMap();
        }

        // get all of the pk fields
        List<JDBCCMPFieldMetaData> pkFields = new ArrayList<JDBCCMPFieldMetaData>();
        for (JDBCCMPFieldMetaData cmpField : entity.getCMPFields()) {
            if (cmpField.isPrimaryKeyMember()) {
                pkFields.add(cmpField);
            }
        }

        // generate a new key field for each pk field
        Map<String, JDBCCMPFieldMetaData> fields = new HashMap<String, JDBCCMPFieldMetaData>(pkFields.size());
        for (JDBCCMPFieldMetaData cmpField : pkFields) {
            String columnName;
            if (relationMetaData.isTableMappingStyle()) {
                if (entity.equals(relatedRole.getEntity()))
                    columnName = getCMRFieldName();
                else
                    columnName = entity.getName();
            } else {
                columnName = relatedRole.getCMRFieldName();
            }

            if (pkFields.size() > 1) {
                columnName += "_" + cmpField.getFieldName();
            }

            genIndex = (genIndex) || cmpField.isIndexed();

            cmpField = new JDBCCMPFieldMetaData(
                    entity,
                    cmpField,
                    columnName,
                    false,
                    relationMetaData.isTableMappingStyle(),
                    relationMetaData.isReadOnly(),
                    relationMetaData.getReadTimeOut(),
                    relationMetaData.isTableMappingStyle());
            fields.put(cmpField.getFieldName(), cmpField);
        }
        return Collections.unmodifiableMap(fields);
    }

    private Map<String, JDBCCMPFieldMetaData> loadKeyFields(final ParsedRelationshipRole parsedRole) {

        // no field overrides, we're done
        final List<ParsedCmpField> keyFields = parsedRole.getKeyFields();
        if (keyFields == null) {
            return loadKeyFields();
        }

        if(keyFields.isEmpty()) {
            return Collections.EMPTY_MAP;
        }

        if (relationMetaData.isForeignKeyMappingStyle() && isMultiplicityMany()) {
            throw new RuntimeException("Role: " + relationshipRoleName + " with multiplicity many using " +
                    "foreign-key mapping is not allowed to have key-fields");
        }

        // load the default field values
        Map<String, JDBCCMPFieldMetaData> defaultFields = getPrimaryKeyFields();

        // load overrides
        Map<String, JDBCCMPFieldMetaData> fields = new HashMap<String, JDBCCMPFieldMetaData>(defaultFields.size());
        for (ParsedCmpField keyField : keyFields) {
            String fieldName = keyField.getFieldName();

            JDBCCMPFieldMetaData cmpField = defaultFields.remove(fieldName);
            if (cmpField == null) {
                throw new RuntimeException("Role '" + relationshipRoleName + "' on Entity Bean '" + entity.getName() + "' : CMP field for key not found: field " + "name='" + fieldName + "'");
            }
            genIndex = keyField.getGenIndex() != null && keyField.getGenIndex();


            cmpField = new JDBCCMPFieldMetaData(
                    entity,
                    keyField,
                    cmpField,
                    false,
                    relationMetaData.isTableMappingStyle(),
                    relationMetaData.isReadOnly(),
                    relationMetaData.getReadTimeOut(),
                    relationMetaData.isTableMappingStyle());
            fields.put(cmpField.getFieldName(), cmpField);
        }

        // all fields must be overriden
        if (!defaultFields.isEmpty()) {
            throw new RuntimeException("Mappings were not provided for all " +
                    "fields: unmaped fields=" + defaultFields.keySet() +
                    " in role=" + relationshipRoleName);
        }
        return Collections.unmodifiableMap(fields);
    }

    /**
     * Returns the primary key fields of the entity mapped by field name.
     */
    private Map<String, JDBCCMPFieldMetaData> getPrimaryKeyFields() {
        Map<String, JDBCCMPFieldMetaData> pkFields = new HashMap<String, JDBCCMPFieldMetaData>();
        for (JDBCCMPFieldMetaData cmpField : entity.getCMPFields()) {
            if (cmpField.isPrimaryKeyMember())
                pkFields.put(cmpField.getFieldName(), cmpField);
        }
        return pkFields;
    }
}
TOP

Related Classes of org.jboss.as.cmp.jdbc.metadata.JDBCRelationshipRoleMetaData

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.