package org.jboss.ejb.plugins.cmp.jdbc.metadata;
import java.util.Collection;
import java.util.Collections;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.jboss.deployment.DeploymentException;
import org.jboss.metadata.MetaData;
import org.jboss.metadata.RelationshipRoleMetaData;
import org.w3c.dom.Element;
public final class JDBCRelationshipRoleMetaData
{
private final JDBCRelationMetaData relationMetaData;
private final String relationshipRoleName;
private final boolean multiplicityOne;
private final boolean foreignKeyConstraint;
private final boolean cascadeDelete;
private final boolean batchCascadeDelete;
private final JDBCEntityMetaData entity;
private final String cmrFieldName;
private final boolean navigable;
private final String cmrFieldType;
private boolean genIndex;
private final JDBCReadAheadMetaData readAhead;
private JDBCRelationshipRoleMetaData relatedRole;
private Map keyFields;
public JDBCRelationshipRoleMetaData(JDBCRelationMetaData relationMetaData,
JDBCApplicationMetaData application,
RelationshipRoleMetaData role)
throws DeploymentException
{
this.relationMetaData = relationMetaData;
relationshipRoleName = role.getRelationshipRoleName();
multiplicityOne = role.isMultiplicityOne();
cascadeDelete = role.isCascadeDelete();
batchCascadeDelete = false;
foreignKeyConstraint = false;
readAhead = null;
String fieldName = loadCMRFieldName(role);
if(fieldName == null)
{
cmrFieldName = generateNonNavigableCMRName(role);
navigable = false;
}
else
{
cmrFieldName = fieldName;
navigable = true;
}
cmrFieldType = role.getCMRFieldType();
entity = application.getBeanByEjbName(role.getEntityName());
if(entity == null)
{
throw new DeploymentException("Entity: " + role.getEntityName() +
" not found for relation: " + role.getRelationMetaData().getRelationName());
}
}
public JDBCRelationshipRoleMetaData(JDBCRelationMetaData relationMetaData,
JDBCApplicationMetaData application,
Element element,
JDBCRelationshipRoleMetaData defaultValues)
throws DeploymentException
{
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();
String fkString = MetaData.getOptionalChildContent(element, "fk-constraint");
if(fkString != null)
{
foreignKeyConstraint = Boolean.valueOf(fkString).booleanValue();
}
else
{
foreignKeyConstraint = defaultValues.hasForeignKeyConstraint();
}
Element readAheadElement = MetaData.getOptionalChild(element, "read-ahead");
if(readAheadElement != null)
{
readAhead = new JDBCReadAheadMetaData(readAheadElement, entity.getReadAhead());
}
else
{
readAhead = entity.getReadAhead();
}
batchCascadeDelete = MetaData.getOptionalChild(element, "batch-cascade-delete") != null;
if(batchCascadeDelete)
{
if(!cascadeDelete)
throw new DeploymentException(
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 DeploymentException(
"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(JDBCRelationshipRoleMetaData relatedRole)
throws DeploymentException
{
init(relatedRole, null);
}
public void init(JDBCRelationshipRoleMetaData relatedRole, Element element)
throws DeploymentException
{
this.relatedRole = relatedRole;
if(element == null || "defaults".equals(element.getTagName()))
{
keyFields = loadKeyFields();
}
else
{
keyFields = loadKeyFields(element);
}
}
private static String loadCMRFieldName(RelationshipRoleMetaData role)
{
return role.getCMRFieldName();
}
private static String generateNonNavigableCMRName(RelationshipRoleMetaData role)
{
RelationshipRoleMetaData relatedRole = role.getRelatedRoleMetaData();
return relatedRole.getEntityName() + "_" + relatedRole.getCMRFieldName();
}
public JDBCRelationMetaData getRelationMetaData()
{
return relationMetaData;
}
public String getRelationshipRoleName()
{
return relationshipRoleName;
}
public boolean hasForeignKeyConstraint()
{
return foreignKeyConstraint;
}
public boolean isMultiplicityOne()
{
return multiplicityOne;
}
public boolean isMultiplicityMany()
{
return !multiplicityOne;
}
public boolean isCascadeDelete()
{
return cascadeDelete;
}
public boolean isBatchCascadeDelete()
{
return batchCascadeDelete;
}
public JDBCEntityMetaData getEntity()
{
return entity;
}
public String getCMRFieldName()
{
return cmrFieldName;
}
private boolean isNavigable()
{
return navigable;
}
private String getCMRFieldType()
{
return cmrFieldType;
}
public JDBCRelationshipRoleMetaData getRelatedRole()
{
return relationMetaData.getOtherRelationshipRole(this);
}
public JDBCReadAheadMetaData getReadAhead()
{
return readAhead;
}
public Collection getKeyFields()
{
return Collections.unmodifiableCollection(keyFields.values());
}
public boolean isIndexed()
{
return genIndex;
}
private Map loadKeyFields()
{
if(relationMetaData.isForeignKeyMappingStyle())
{
if(isMultiplicityMany())
return Collections.EMPTY_MAP;
else
if(getRelatedRole().isMultiplicityOne() && !getRelatedRole().isNavigable())
return Collections.EMPTY_MAP;
}
ArrayList pkFields = new ArrayList();
for(Iterator i = entity.getCMPFields().iterator(); i.hasNext();)
{
JDBCCMPFieldMetaData cmpField = (JDBCCMPFieldMetaData) i.next();
if(cmpField.isPrimaryKeyMember())
{
pkFields.add(cmpField);
}
}
Map fields = new HashMap(pkFields.size());
for(Iterator i = pkFields.iterator(); i.hasNext();)
{
JDBCCMPFieldMetaData cmpField = (JDBCCMPFieldMetaData) i.next();
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();
}
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 loadKeyFields(Element element)
throws DeploymentException
{
Element keysElement = MetaData.getOptionalChild(element, "key-fields");
if(keysElement == null)
{
return loadKeyFields();
}
Iterator iter = MetaData.getChildrenByTagName(keysElement, "key-field");
if(!iter.hasNext())
{
return Collections.EMPTY_MAP;
}
else
if(relationMetaData.isForeignKeyMappingStyle() && isMultiplicityMany())
{
throw new DeploymentException("Role: " + relationshipRoleName + " with multiplicity many using " +
"foreign-key mapping is not allowed to have key-fields");
}
Map defaultFields = getPrimaryKeyFields();
Map fields = new HashMap(defaultFields.size());
while(iter.hasNext())
{
Element keyElement = (Element) iter.next();
String fieldName = MetaData.getUniqueChildContent(keyElement, "field-name");
JDBCCMPFieldMetaData cmpField = (JDBCCMPFieldMetaData) defaultFields.remove(fieldName);
if(cmpField == null)
{
throw new DeploymentException(
"Role '" + relationshipRoleName + "' on Entity Bean '" +
entity.getName() + "' : CMP field for key not found: field " +
"name='" + fieldName + "'");
}
String isIndexedtmp = MetaData.getOptionalChildContent(keyElement, "dbindex");
boolean isIndexed;
if(isIndexedtmp != null)
isIndexed = true;
else
isIndexed = false;
genIndex = isIndexed;
cmpField = new JDBCCMPFieldMetaData(
entity,
keyElement,
cmpField,
false,
relationMetaData.isTableMappingStyle(),
relationMetaData.isReadOnly(),
relationMetaData.getReadTimeOut(),
relationMetaData.isTableMappingStyle());
fields.put(cmpField.getFieldName(), cmpField);
}
if(!defaultFields.isEmpty())
{
throw new DeploymentException("Mappings were not provided for all " +
"fields: unmaped fields=" + defaultFields.keySet() +
" in role=" + relationshipRoleName);
}
return Collections.unmodifiableMap(fields);
}
private Map getPrimaryKeyFields()
{
Map pkFields = new HashMap();
for(Iterator cmpFieldsIter = entity.getCMPFields().iterator(); cmpFieldsIter.hasNext();)
{
JDBCCMPFieldMetaData cmpField = (JDBCCMPFieldMetaData) cmpFieldsIter.next();
if(cmpField.isPrimaryKeyMember())
pkFields.put(cmpField.getFieldName(), cmpField);
}
return pkFields;
}
}