{
// Go through the fields for this class and add columns for them
for (int fieldNumber=0; fieldNumber<mmds.length; fieldNumber++)
{
// Primary key fields are added by the initialisePK method
AbstractMemberMetaData mmd = mmds[fieldNumber];
if (!mmd.isPrimaryKey())
{
if (managesMember(mmd.getFullFieldName()))
{
if (!mmd.getClassName(true).equals(theCmd.getFullClassName()))
{
// Field already managed by this table so maybe we are overriding a superclass
JavaTypeMapping fieldMapping = getMappingForMemberName(mmd.getFullFieldName());
ColumnMetaData[] colmds = mmd.getColumnMetaData();
if (colmds != null && colmds.length > 0)
{
// Apply this set of ColumnMetaData to the existing mapping
int colnum = 0;
IdentifierFactory idFactory = getStoreManager().getIdentifierFactory();
for (int i=0;i<fieldMapping.getNumberOfDatastoreMappings();i++)
{
Column col = (Column)fieldMapping.getDatastoreMapping(i).getDatastoreField();
col.setIdentifier(idFactory.newDatastoreFieldIdentifier(colmds[colnum].getName()));
col.setColumnMetaData(colmds[colnum]);
colnum++;
if (colnum == colmds.length)
{
// Reached end of specified metadata
break;
}
}
if (NucleusLogger.DATASTORE.isDebugEnabled())
{
// TODO Change this to reflect that we have updated the previous mapping
// Provide field->column mapping debug message
StringBuffer columnsStr = new StringBuffer();
for (int i=0;i<fieldMapping.getNumberOfDatastoreMappings();i++)
{
if (i > 0)
{
columnsStr.append(",");
}
columnsStr.append(fieldMapping.getDatastoreMapping(i).getDatastoreField());
}
if (fieldMapping.getNumberOfDatastoreMappings() == 0)
{
columnsStr.append("[none]");
}
StringBuffer datastoreMappingTypes = new StringBuffer();
for (int i=0;i<fieldMapping.getNumberOfDatastoreMappings();i++)
{
if (i > 0)
{
datastoreMappingTypes.append(',');
}
datastoreMappingTypes.append(fieldMapping.getDatastoreMapping(i).getClass().getName());
}
NucleusLogger.DATASTORE.debug(LOCALISER.msg("057010",
mmd.getFullFieldName(), columnsStr.toString(), fieldMapping.getClass().getName(), datastoreMappingTypes.toString()));
}
}
}
}
else
{
// Manage the field if not already managed (may already exist if overriding a superclass field)
if (mmd.getPersistenceModifier() == FieldPersistenceModifier.PERSISTENT)
{
boolean isPrimary = true;
if (mmd.getTable() != null && mmd.getJoinMetaData() == null)
{
// Field has a table specified and is not a 1-N with join table
// so is mapped to a secondary table
isPrimary = false;
}
if (isPrimary)
{
// Add the field to this table
JavaTypeMapping fieldMapping = storeMgr.getMappingManager().getMapping(this, mmd, clr, FieldRole.ROLE_FIELD);
if (theCmd != cmd &&
theCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUPERCLASS_TABLE &&
fieldMapping.getNumberOfDatastoreMappings() > 0)
{
// Field is for a subclass and so column(s) has to either allow nulls, or have default
int numCols = fieldMapping.getNumberOfDatastoreMappings();
for (int colNum = 0;colNum < numCols; colNum++)
{
Column col = (Column) fieldMapping.getDatastoreMapping(colNum).getDatastoreField();
if (col.getDefaultValue() == null && !col.isNullable())
{
// Column needs to be nullable
NucleusLogger.DATASTORE_SCHEMA.debug("Member " + mmd.getFullFieldName() +
" uses superclass-table yet the field is not marked as nullable " +
" nor does it have a default value, so setting the column as nullable");
col.setNullable();
}
}
}
addMemberMapping(fieldMapping);
}
else
{
// Add the field to the appropriate secondary table
if (secondaryTables == null)
{
secondaryTables = new HashMap();
}
SecondaryTable secTable = secondaryTables.get(mmd.getTable());
if (secTable == null)
{
// Secondary table doesnt exist yet so create it to users specifications.
JoinMetaData[] joinmds = theCmd.getJoinMetaData();
JoinMetaData joinmd = null;
if (joinmds != null)
{
for (int j=0;j<joinmds.length;j++)
{
if (joinmds[j].getTable().equalsIgnoreCase(mmd.getTable()) &&
(joinmds[j].getCatalog() == null || (joinmds[j].getCatalog() != null && joinmds[j].getCatalog().equalsIgnoreCase(mmd.getCatalog()))) &&
(joinmds[j].getSchema() == null || (joinmds[j].getSchema() != null && joinmds[j].getSchema().equalsIgnoreCase(mmd.getSchema()))))
{
joinmd = joinmds[j];
break;
}
}
}
DatastoreIdentifier secTableIdentifier =
storeMgr.getIdentifierFactory().newDatastoreContainerIdentifier(mmd.getTable());
// Use specified catalog, else take catalog of the owning table
String catalogName = mmd.getCatalog();
if (catalogName == null)
{
catalogName = getCatalogName();
}
// Use specified schema, else take schema of the owning table
String schemaName = mmd.getSchema();
if (schemaName == null)
{
schemaName = getSchemaName();
}
secTableIdentifier.setCatalogName(catalogName);
secTableIdentifier.setSchemaName(schemaName);
secTable = new SecondaryTable(secTableIdentifier, storeMgr, this, joinmd, clr);
secTable.preInitialize(clr);
secTable.initialize(clr);
secTable.postInitialize(clr);
secondaryTables.put(mmd.getTable(), secTable);
}
secTable.addMemberMapping(storeMgr.getMappingManager().getMapping(secTable, mmd,
clr, FieldRole.ROLE_FIELD));
}
}
else if (mmd.getPersistenceModifier() != FieldPersistenceModifier.TRANSACTIONAL)
{
throw new NucleusException(LOCALISER.msg("057006",mmd.getName())).setFatal();
}
// Calculate if we need a FK adding due to a 1-N (FK) relationship
boolean needsFKToContainerOwner = false;
int relationType = mmd.getRelationType(clr);
if (relationType == Relation.ONE_TO_MANY_BI)
{
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
if (mmd.getJoinMetaData() == null && relatedMmds[0].getJoinMetaData() == null)
{
needsFKToContainerOwner = true;
}
}
else if (relationType == Relation.ONE_TO_MANY_UNI)
{
if (mmd.getJoinMetaData() == null)
{
needsFKToContainerOwner = true;
}
}
if (needsFKToContainerOwner)
{
// 1-N uni/bidirectional using FK, so update the element side with a FK
if ((mmd.getCollection() != null && !SCOUtils.collectionHasSerialisedElements(mmd)) ||
(mmd.getArray() != null && !SCOUtils.arrayIsStoredInSingleColumn(mmd, storeMgr.getMetaDataManager())))
{
// 1-N ForeignKey collection/array, so add FK to element table
AbstractClassMetaData elementCmd = null;
if (mmd.hasCollection())
{
// Collection
elementCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(mmd.getCollection().getElementType(), clr);
}
else
{
// Array
elementCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(mmd.getType().getComponentType(), clr);
}
if (elementCmd == null)
{
// Elements that are reference types or non-PC will come through here
if (mmd.hasCollection())
{
NucleusLogger.METADATA.warn(LOCALISER.msg("057016",
theCmd.getFullClassName(), mmd.getCollection().getElementType()));
}
else
{
NucleusLogger.METADATA.warn(LOCALISER.msg("057014",
theCmd.getFullClassName(), mmd.getType().getComponentType().getName()));
}
}
else
{
AbstractClassMetaData[] elementCmds = null;
// TODO : Cater for interface elements, and get the metadata for the implementation classes here
if (elementCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUBCLASS_TABLE)
{
elementCmds = storeMgr.getClassesManagingTableForClass(elementCmd, clr);
}
else
{
elementCmds = new ClassMetaData[1];
elementCmds[0] = elementCmd;
}
// Run callbacks for each of the element classes.
for (int i=0;i<elementCmds.length;i++)
{
storeMgr.addSchemaCallback(elementCmds[i].getFullClassName(), mmd);
DatastoreClass dc = storeMgr.getDatastoreClass(elementCmds[i].getFullClassName(), clr);
if (dc == null)
{
throw new NucleusException("Unable to add foreign-key to " +
elementCmds[i].getFullClassName() + " to " + this + " since element has no table!");
}
ClassTable ct = (ClassTable) dc;
if (ct.isInitialized())
{
// if the target table is already initialized, run the callbacks
ct.runCallBacks(clr);
}
}
}
}
else if (mmd.getMap() != null && !SCOUtils.mapHasSerialisedKeysAndValues(mmd))
{
// 1-N ForeignKey map, so add FK to value table
if (mmd.getKeyMetaData() != null && mmd.getKeyMetaData().getMappedBy() != null)
{
// Key is stored in the value table so add the FK to the value table
AbstractClassMetaData valueCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(mmd.getMap().getValueType(), clr);
if (valueCmd == null)
{
// Interface elements will come through here and java.lang.String and others as well
NucleusLogger.METADATA.warn(LOCALISER.msg("057018",
theCmd.getFullClassName(), mmd.getMap().getValueType()));
}
else
{
AbstractClassMetaData[] valueCmds = null;
// TODO : Cater for interface values, and get the metadata for the implementation classes here
if (valueCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUBCLASS_TABLE)
{
valueCmds = storeMgr.getClassesManagingTableForClass(valueCmd, clr);
}
else
{
valueCmds = new ClassMetaData[1];
valueCmds[0] = valueCmd;
}
// Run callbacks for each of the value classes.
for (int i=0;i<valueCmds.length;i++)
{
storeMgr.addSchemaCallback(valueCmds[i].getFullClassName(), mmd);
DatastoreClass dc = storeMgr.getDatastoreClass(valueCmds[i].getFullClassName(), clr);
ClassTable ct = (ClassTable) dc;
if (ct.isInitialized())
{
// if the target table is already initialized, run the callbacks
ct.runCallBacks(clr);
}
}
}
}
else if (mmd.getValueMetaData() != null && mmd.getValueMetaData().getMappedBy() != null)
{
// Value is stored in the key table so add the FK to the key table
AbstractClassMetaData keyCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(mmd.getMap().getKeyType(), clr);
if (keyCmd == null)
{
// Interface elements will come through here and java.lang.String and others as well
NucleusLogger.METADATA.warn(LOCALISER.msg("057019",
theCmd.getFullClassName(), mmd.getMap().getKeyType()));
}
else
{
AbstractClassMetaData[] keyCmds = null;
// TODO : Cater for interface keys, and get the metadata for the implementation classes here