{
initializeFKMapUniqueConstraints(ownerFmd);
}
boolean duplicate = false;
JavaTypeMapping fkDiscrimMapping = null;
JavaTypeMapping orderMapping = null;
if (ownerFmd.hasExtension("relation-discriminator-column"))
{
// Collection has a relation discriminator so we need to share the FK. Check for the required discriminator
String colName = ownerFmd.getValueForExtension("relation-discriminator-column");
if (colName == null)
{
// No column defined so use a fallback name
colName = "RELATION_DISCRIM";
}
Set fkDiscrimEntries = getExternalFkDiscriminatorMappings().entrySet();
Iterator discrimMappingIter = fkDiscrimEntries.iterator();
while (discrimMappingIter.hasNext())
{
Map.Entry entry = (Map.Entry)discrimMappingIter.next();
JavaTypeMapping discrimMapping = (JavaTypeMapping)entry.getValue();
String discrimColName = (discrimMapping.getDatastoreMapping(0).getDatastoreField().getColumnMetaData()).getName();
if (discrimColName.equalsIgnoreCase(colName))
{
duplicate = true;
fkDiscrimMapping = discrimMapping;
orderMapping = getExternalOrderMappings().get(entry.getKey());
break;
}
}
if (!duplicate)
{
// Create the relation discriminator column since we dont have this discriminator
ColumnMetaData colmd = new ColumnMetaData();
colmd.setName(colName);
colmd.setAllowsNull(Boolean.TRUE); // Allow for elements not in any discriminated collection
fkDiscrimMapping = storeMgr.getMappingManager().getMapping(String.class); // Only support String discriminators currently
fkDiscrimMapping.setDatastoreContainer(this);
ColumnCreator.createIndexColumn(fkDiscrimMapping, storeMgr, clr, this, colmd, false);
}
if (fkDiscrimMapping != null)
{
getExternalFkDiscriminatorMappings().put(ownerFmd, fkDiscrimMapping);
}
}
// Add the order mapping as necessary
addOrderMapping(ownerFmd, orderMapping, clr);
}
else
{
// Unidirectional (element knows nothing about the owner)
String ownerClassName = ownerFmd.getAbstractClassMetaData().getFullClassName();
JavaTypeMapping fkMapping = new PersistableMapping();
fkMapping.setDatastoreContainer(this);
fkMapping.initialize(storeMgr, ownerClassName);
JavaTypeMapping fkDiscrimMapping = null;
JavaTypeMapping orderMapping = null;
boolean duplicate = false;
try
{
// Get the owner id mapping of the "1" end
DatastoreClass ownerTbl = storeMgr.getDatastoreClass(ownerClassName, clr);
if (ownerTbl == null)
{
// Class doesn't have its own table (subclass-table) so find where it persists
AbstractClassMetaData[] ownerParentCmds =
storeMgr.getClassesManagingTableForClass(ownerFmd.getAbstractClassMetaData(), clr);
if (ownerParentCmds.length > 1)
{
throw new NucleusUserException("Relation (" + ownerFmd.getFullFieldName() +
") with multiple related tables (using subclass-table). Not supported");
}
ownerClassName = ownerParentCmds[0].getFullClassName();
ownerTbl = storeMgr.getDatastoreClass(ownerClassName, clr);
}
JavaTypeMapping ownerIdMapping = ownerTbl.getIdMapping();
ColumnMetaDataContainer colmdContainer = null;
if (ownerFmd.hasCollection() || ownerFmd.hasArray())
{
// 1-N Collection/array
colmdContainer = ownerFmd.getElementMetaData();
}
else if (ownerFmd.hasMap() && ownerFmd.getKeyMetaData() != null && ownerFmd.getKeyMetaData().getMappedBy() != null)
{
// 1-N Map with key stored in the value
colmdContainer = ownerFmd.getValueMetaData();
}
else if (ownerFmd.hasMap() && ownerFmd.getValueMetaData() != null && ownerFmd.getValueMetaData().getMappedBy() != null)
{
// 1-N Map with value stored in the key
colmdContainer = ownerFmd.getKeyMetaData();
}
CorrespondentColumnsMapper correspondentColumnsMapping =
new CorrespondentColumnsMapper(colmdContainer, ownerIdMapping, true);
int countIdFields = ownerIdMapping.getNumberOfDatastoreMappings();
for (int i=0; i<countIdFields; i++)
{
DatastoreMapping refDatastoreMapping = ownerIdMapping.getDatastoreMapping(i);
JavaTypeMapping mapping = storeMgr.getMappingManager().getMapping(refDatastoreMapping.getJavaTypeMapping().getJavaType());
ColumnMetaData colmd = correspondentColumnsMapping.getColumnMetaDataByIdentifier(((Column)refDatastoreMapping.getDatastoreField()).getIdentifier());
if (colmd == null)
{
throw new NucleusUserException(LOCALISER.msg("057035",
((Column)refDatastoreMapping.getDatastoreField()).getIdentifier(), toString())).setFatal();
}
DatastoreIdentifier identifier = null;
IdentifierFactory idFactory = storeMgr.getIdentifierFactory();
if (colmd.getName() == null || colmd.getName().length() < 1)
{
// No user provided name so generate one
identifier = idFactory.newForeignKeyFieldIdentifier(ownerFmd,
null, refDatastoreMapping.getDatastoreField().getIdentifier(),
storeMgr.getNucleusContext().getTypeManager().isDefaultEmbeddedType(mapping.getJavaType()),
FieldRole.ROLE_OWNER);
}
else
{
// User-defined name
identifier = idFactory.newDatastoreFieldIdentifier(colmd.getName());
}
DatastoreField refColumn = addDatastoreField(mapping.getJavaType().getName(), identifier, mapping, colmd);
((Column)refDatastoreMapping.getDatastoreField()).copyConfigurationTo(refColumn);
if (colmd == null || (colmd != null && colmd.getAllowsNull() == null) ||
(colmd != null && colmd.getAllowsNull() != null && colmd.isAllowsNull()))
{
// User either wants it nullable, or haven't specified anything, so make it nullable
refColumn.setNullable();
}
fkMapping.addDatastoreMapping(getStoreManager().getMappingManager().createDatastoreMapping(mapping, refColumn, refDatastoreMapping.getJavaTypeMapping().getJavaType().getName()));
((PersistableMapping)fkMapping).addJavaTypeMapping(mapping);
}
}
catch (DuplicateDatastoreFieldException dce)
{
// If the user hasnt specified "relation-discriminator-column" here we dont allow the sharing of columns
if (!ownerFmd.hasExtension("relation-discriminator-column"))
{
throw dce;
}
// Find the FK using this column and use it instead of creating a new one since we're sharing
Iterator fkIter = getExternalFkMappings().entrySet().iterator();
fkMapping = null;
while (fkIter.hasNext())
{
Map.Entry entry = (Map.Entry)fkIter.next();
JavaTypeMapping existingFkMapping = (JavaTypeMapping)entry.getValue();
for (int j=0;j<existingFkMapping.getNumberOfDatastoreMappings();j++)
{
if (existingFkMapping.getDatastoreMapping(j).getDatastoreField().getIdentifier().toString().equals(dce.getConflictingColumn().getIdentifier().toString()))
{
// The FK is shared (and so if it is a List we also share the index)
fkMapping = existingFkMapping;
fkDiscrimMapping = externalFkDiscriminatorMappings.get(entry.getKey());
orderMapping = getExternalOrderMappings().get(entry.getKey());