/** * Convenience logging method to output the mapping information for an element, key, value field * * @param mapping The mapping */ protected void debugMapping(JavaTypeMapping mapping) { if (NucleusLogger.DATASTORE.isDebugEnabled()) { // Provide field->column mapping debug message StringBuffer columnsStr = new StringBuffer(); for (int i = 0; i < mapping.getNumberOfDatastoreMappings(); i++) { if (i > 0) { columnsStr.append(","); } columnsStr.append(mapping.getDatastoreMapping(i).getDatastoreField()); } if (mapping.getNumberOfDatastoreMappings() == 0) { columnsStr.append("[none]"); } StringBuffer datastoreMappingTypes = new StringBuffer(); for (int i = 0; i < mapping.getNumberOfDatastoreMappings(); i++) { if (i > 0) { datastoreMappingTypes.append(','); } datastoreMappingTypes.append(mapping.getDatastoreMapping(i).getClass().getName()); } NucleusLogger.DATASTORE.debug( LOCALISER.msg( "057010", mmd.getFullFieldName(), columnsStr.toString(), mapping.getClass().getName(), datastoreMappingTypes.toString())); } }
/** * Accessor for the candidate keys for this table. * * @return The indices */ protected List getExpectedCandidateKeys() { // The indices required by foreign keys (BaseTable) List candidateKeys = super.getExpectedCandidateKeys(); if (keyMapping instanceof EmbeddedKeyPCMapping) { // Add all candidate keys required by fields of the embedded key EmbeddedKeyPCMapping embMapping = (EmbeddedKeyPCMapping) keyMapping; for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) { JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i); UniqueMetaData umd = embFieldMapping.getMemberMetaData().getUniqueMetaData(); if (umd != null) { CandidateKey ck = TableUtils.getCandidateKeyForField(this, umd, embFieldMapping); if (ck != null) { candidateKeys.add(ck); } } } } if (valueMapping instanceof EmbeddedValuePCMapping) { // Add all candidate keys required by fields of the embedded value EmbeddedValuePCMapping embMapping = (EmbeddedValuePCMapping) valueMapping; for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) { JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i); UniqueMetaData umd = embFieldMapping.getMemberMetaData().getUniqueMetaData(); if (umd != null) { CandidateKey ck = TableUtils.getCandidateKeyForField(this, umd, embFieldMapping); if (ck != null) { candidateKeys.add(ck); } } } } return candidateKeys; }
/** * Accessor for the indices for this table. This includes both the user-defined indices (via * MetaData), and the ones required by foreign keys (required by relationships). * * @param clr The ClassLoaderResolver * @return The indices */ protected Set getExpectedIndices(ClassLoaderResolver clr) { // The indices required by foreign keys (BaseTable) Set indices = super.getExpectedIndices(clr); if (keyMapping instanceof EmbeddedKeyPCMapping) { // Add all indices required by fields of the embedded key EmbeddedKeyPCMapping embMapping = (EmbeddedKeyPCMapping) keyMapping; for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) { JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i); IndexMetaData imd = embFieldMapping.getMemberMetaData().getIndexMetaData(); if (imd != null) { Index index = TableUtils.getIndexForField(this, imd, embFieldMapping); if (index != null) { indices.add(index); } } } } if (valueMapping instanceof EmbeddedValuePCMapping) { // Add all indices required by fields of the embedded value EmbeddedValuePCMapping embMapping = (EmbeddedValuePCMapping) valueMapping; for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) { JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i); IndexMetaData imd = embFieldMapping.getMemberMetaData().getIndexMetaData(); if (imd != null) { Index index = TableUtils.getIndexForField(this, imd, embFieldMapping); if (index != null) { indices.add(index); } } } } return indices; }
/** * Convenience method to apply the user specification of <primary-key> columns * * @param pkmd MetaData for the primary key */ protected void applyUserPrimaryKeySpecification(PrimaryKeyMetaData pkmd) { ColumnMetaData[] pkCols = pkmd.getColumnMetaData(); for (int i = 0; i < pkCols.length; i++) { String colName = pkCols[i].getName(); boolean found = false; for (int j = 0; j < ownerMapping.getNumberOfDatastoreMappings(); j++) { if (ownerMapping .getDatastoreMapping(j) .getDatastoreField() .getIdentifier() .getIdentifierName() .equals(colName)) { ownerMapping.getDatastoreMapping(j).getDatastoreField().setAsPrimaryKey(); found = true; } } if (!found) { for (int j = 0; j < keyMapping.getNumberOfDatastoreMappings(); j++) { if (keyMapping .getDatastoreMapping(j) .getDatastoreField() .getIdentifier() .getIdentifierName() .equals(colName)) { keyMapping.getDatastoreMapping(j).getDatastoreField().setAsPrimaryKey(); found = true; } } } if (!found) { for (int j = 0; j < valueMapping.getNumberOfDatastoreMappings(); j++) { if (valueMapping .getDatastoreMapping(j) .getDatastoreField() .getIdentifier() .getIdentifierName() .equals(colName)) { valueMapping.getDatastoreMapping(j).getDatastoreField().setAsPrimaryKey(); found = true; } } } if (!found) { throw new NucleusUserException(LOCALISER.msg("057040", toString(), colName)); } } }
/** * Accessor for the expected foreign keys for this table. * * @param clr The ClassLoaderResolver * @return The expected foreign keys. */ public List getExpectedForeignKeys(ClassLoaderResolver clr) { assertIsInitialized(); boolean autoMode = false; if (storeMgr .getStringProperty("datanucleus.rdbms.constraintCreateMode") .equals("DataNucleus")) { autoMode = true; } ArrayList foreignKeys = new ArrayList(); try { // FK from join table to owner table DatastoreClass referencedTable = storeMgr.getDatastoreClass(ownerType, clr); if (referencedTable != null) { // Take <foreign-key> from <join> ForeignKeyMetaData fkmd = null; if (mmd.getJoinMetaData() != null) { fkmd = mmd.getJoinMetaData().getForeignKeyMetaData(); } if (fkmd != null || autoMode) { ForeignKey fk = new ForeignKey(ownerMapping, dba, referencedTable, true); fk.setForMetaData(fkmd); foreignKeys.add(fk); } } if (!isSerialisedValuePC()) { if (isEmbeddedValuePC()) { // Add any FKs for the fields of the (embedded) value EmbeddedValuePCMapping embMapping = (EmbeddedValuePCMapping) valueMapping; for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) { JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i); AbstractMemberMetaData embFmd = embFieldMapping.getMemberMetaData(); if (ClassUtils.isReferenceType(embFmd.getType()) && embFieldMapping instanceof ReferenceMapping) { // Field is a reference type, so add a FK to the table of the PC for each PC // implementation Collection fks = TableUtils.getForeignKeysForReferenceField( embFieldMapping, embFmd, autoMode, storeMgr, clr); foreignKeys.addAll(fks); } else if (storeMgr .getNucleusContext() .getMetaDataManager() .getMetaDataForClass(embFmd.getType(), clr) != null && embFieldMapping.getNumberOfDatastoreMappings() > 0 && embFieldMapping instanceof PersistableMapping) { // Field is for a PC class with the FK at this side, so add a FK to the table of this // PC ForeignKey fk = TableUtils.getForeignKeyForPCField( embFieldMapping, embFmd, autoMode, storeMgr, clr); if (fk != null) { foreignKeys.add(fk); } } } } else if (mmd.getMap().valueIsPersistent()) { // FK from join table to value table referencedTable = storeMgr.getDatastoreClass(mmd.getMap().getValueType(), clr); if (referencedTable != null) { // Take <foreign-key> from <value> ForeignKeyMetaData fkmd = null; if (mmd.getValueMetaData() != null) { fkmd = mmd.getValueMetaData().getForeignKeyMetaData(); } if (fkmd != null || autoMode) { ForeignKey fk = new ForeignKey(valueMapping, dba, referencedTable, true); fk.setForMetaData(fkmd); foreignKeys.add(fk); } } } } if (!isSerialisedKeyPC()) { if (isEmbeddedKeyPC()) { // Add any FKs for the fields of the (embedded) key EmbeddedKeyPCMapping embMapping = (EmbeddedKeyPCMapping) keyMapping; for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) { JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i); AbstractMemberMetaData embFmd = embFieldMapping.getMemberMetaData(); if (ClassUtils.isReferenceType(embFmd.getType()) && embFieldMapping instanceof ReferenceMapping) { // Field is a reference type, so add a FK to the table of the PC for each PC // implementation Collection fks = TableUtils.getForeignKeysForReferenceField( embFieldMapping, embFmd, autoMode, storeMgr, clr); foreignKeys.addAll(fks); } else if (storeMgr .getNucleusContext() .getMetaDataManager() .getMetaDataForClass(embFmd.getType(), clr) != null && embFieldMapping.getNumberOfDatastoreMappings() > 0 && embFieldMapping instanceof PersistableMapping) { // Field is for a PC class with the FK at this side, so add a FK to the table of this // PC ForeignKey fk = TableUtils.getForeignKeyForPCField( embFieldMapping, embFmd, autoMode, storeMgr, clr); if (fk != null) { foreignKeys.add(fk); } } } } else if (mmd.getMap().keyIsPersistent()) { // FK from join table to key table referencedTable = storeMgr.getDatastoreClass(mmd.getMap().getKeyType(), clr); if (referencedTable != null) { // Take <foreign-key> from <key> ForeignKeyMetaData fkmd = null; if (mmd.getKeyMetaData() != null) { fkmd = mmd.getKeyMetaData().getForeignKeyMetaData(); } if (fkmd != null || autoMode) { ForeignKey fk = new ForeignKey(keyMapping, dba, referencedTable, true); fk.setForMetaData(fkmd); foreignKeys.add(fk); } } } } } catch (NoTableManagedException e) { // expected when no table exists } return foreignKeys; }
/** * Method to initialise the table definition. * * @param clr The ClassLoaderResolver */ public void initialize(ClassLoaderResolver clr) { assertIsUninitialized(); MapMetaData mapmd = mmd.getMap(); if (mapmd == null) { throw new NucleusUserException(LOCALISER.msg("057017", mmd)); } PrimaryKeyMetaData pkmd = (mmd.getJoinMetaData() != null ? mmd.getJoinMetaData().getPrimaryKeyMetaData() : null); boolean pkColsSpecified = (pkmd != null && pkmd.getColumnMetaData() != null); boolean pkRequired = requiresPrimaryKey(); // Add owner mapping ColumnMetaData[] ownerColmd = null; if (mmd.getJoinMetaData() != null && mmd.getJoinMetaData().getColumnMetaData() != null && mmd.getJoinMetaData().getColumnMetaData().length > 0) { // Column mappings defined at this side (1-N, M-N) // When specified at this side they use the <join> tag ownerColmd = mmd.getJoinMetaData().getColumnMetaData(); } ownerMapping = ColumnCreator.createColumnsForJoinTables( clr.classForName(ownerType), mmd, ownerColmd, storeMgr, this, pkRequired, false, FieldRole.ROLE_OWNER, clr); if (NucleusLogger.DATASTORE.isDebugEnabled()) { debugMapping(ownerMapping); } String keyValueFieldName = (mmd.getKeyMetaData() != null ? mmd.getKeyMetaData().getMappedBy() : null); String valueKeyFieldName = (mmd.getValueMetaData() != null ? mmd.getValueMetaData().getMappedBy() : null); // Add key mapping boolean keyPC = (mmd.hasMap() && mmd.getMap().keyIsPersistent()); Class keyCls = clr.classForName(mapmd.getKeyType()); if (keyValueFieldName != null && isEmbeddedValuePC()) { // Added in value code } else if (isSerialisedKey() || isEmbeddedKeyPC() || (isEmbeddedKey() && !keyPC) || ClassUtils.isReferenceType(keyCls)) { // Key = PC(embedded), PC(serialised), Non-PC(serialised), Non-PC(embedded), Reference keyMapping = storeMgr.getMappingManager().getMapping(this, mmd, clr, FieldRole.ROLE_MAP_KEY); if (Boolean.TRUE.equals(mmd.getContainer().allowNulls())) { // Make all key col(s) nullable so we can store null elements for (int i = 0; i < keyMapping.getNumberOfDatastoreMappings(); i++) { Column elementCol = (Column) keyMapping.getDatastoreMapping(i).getDatastoreField(); elementCol.setNullable(); } } if (NucleusLogger.DATASTORE.isDebugEnabled()) { debugMapping(keyMapping); } if (valueKeyFieldName != null && isEmbeddedKeyPC()) { // Key (PC) is embedded and value is a field of the key EmbeddedKeyPCMapping embMapping = (EmbeddedKeyPCMapping) keyMapping; valueMapping = embMapping.getJavaTypeMapping(valueKeyFieldName); } } else { // Key = PC ColumnMetaData[] keyColmd = null; KeyMetaData keymd = mmd.getKeyMetaData(); if (keymd != null && keymd.getColumnMetaData() != null && keymd.getColumnMetaData().length > 0) { // Column mappings defined at this side (1-N, M-N) keyColmd = keymd.getColumnMetaData(); } keyMapping = ColumnCreator.createColumnsForJoinTables( keyCls, mmd, keyColmd, storeMgr, this, false, false, FieldRole.ROLE_MAP_KEY, clr); if (mmd.getContainer().allowNulls() == Boolean.TRUE) { // Make all key col(s) nullable so we can store null elements for (int i = 0; i < keyMapping.getNumberOfDatastoreMappings(); i++) { Column elementCol = (Column) keyMapping.getDatastoreMapping(i).getDatastoreField(); elementCol.setNullable(); } } if (NucleusLogger.DATASTORE.isDebugEnabled()) { debugMapping(keyMapping); } } // Add value mapping boolean valuePC = (mmd.hasMap() && mmd.getMap().valueIsPersistent()); Class valueCls = clr.classForName(mapmd.getValueType()); if (valueKeyFieldName != null && isEmbeddedKeyPC()) { // Added in key code } else if (isSerialisedValue() || isEmbeddedValuePC() || (isEmbeddedValue() && !valuePC) || ClassUtils.isReferenceType(valueCls)) { // Value = PC(embedded), PC(serialised), Non-PC(serialised), Non-PC(embedded), Reference valueMapping = storeMgr.getMappingManager().getMapping(this, mmd, clr, FieldRole.ROLE_MAP_VALUE); if (mmd.getContainer().allowNulls() == Boolean.TRUE) { // Make all value col(s) nullable so we can store null elements for (int i = 0; i < valueMapping.getNumberOfDatastoreMappings(); i++) { Column elementCol = (Column) valueMapping.getDatastoreMapping(i).getDatastoreField(); elementCol.setNullable(); } } if (NucleusLogger.DATASTORE.isDebugEnabled()) { debugMapping(valueMapping); } if (keyValueFieldName != null && isEmbeddedValuePC()) { // Value (PC) is embedded and key is a field of the value EmbeddedValuePCMapping embMapping = (EmbeddedValuePCMapping) valueMapping; keyMapping = embMapping.getJavaTypeMapping(keyValueFieldName); } } else { // Value = PC ColumnMetaData[] valueColmd = null; ValueMetaData valuemd = mmd.getValueMetaData(); if (valuemd != null && valuemd.getColumnMetaData() != null && valuemd.getColumnMetaData().length > 0) { // Column mappings defined at this side (1-N, M-N) valueColmd = valuemd.getColumnMetaData(); } valueMapping = ColumnCreator.createColumnsForJoinTables( clr.classForName(mapmd.getValueType()), mmd, valueColmd, storeMgr, this, false, true, FieldRole.ROLE_MAP_VALUE, clr); if (mmd.getContainer().allowNulls() == Boolean.TRUE) { // Make all value col(s) nullable so we can store null elements for (int i = 0; i < valueMapping.getNumberOfDatastoreMappings(); i++) { Column elementCol = (Column) valueMapping.getDatastoreMapping(i).getDatastoreField(); elementCol.setNullable(); } } if (NucleusLogger.DATASTORE.isDebugEnabled()) { debugMapping(valueMapping); } } // Add order mapping if required boolean orderRequired = false; if (mmd.getOrderMetaData() != null) { // User requested order column so add one orderRequired = true; } else if (requiresPrimaryKey() && !pkColsSpecified) { // PK is required so maybe need to add an index to form the PK if (isEmbeddedKeyPC()) { if (mmd.getMap().getKeyClassMetaData(clr, storeMgr.getMetaDataManager()).getIdentityType() != IdentityType.APPLICATION) { // Embedded key PC with datastore id so we need an index to form the PK orderRequired = true; } } else if (isSerialisedKey()) { // Serialised key, so need an index to form the PK orderRequired = true; } else if (keyMapping instanceof ReferenceMapping) { // ReferenceMapping, so have order if more than 1 implementation ReferenceMapping refMapping = (ReferenceMapping) keyMapping; if (refMapping.getJavaTypeMapping().length > 1) { orderRequired = true; } } else if (!(keyMapping instanceof PersistableMapping)) { // Non-PC, so depends if the key column can be used as part of a PK // TODO This assumes the keyMapping has a single column but what if it is Color with 4 cols? Column elementCol = (Column) keyMapping.getDatastoreMapping(0).getDatastoreField(); if (!((RDBMSAdapter) storeMgr.getDatastoreAdapter()) .isValidPrimaryKeyType(elementCol.getJdbcType())) { // Not possible to use this Non-PC type as part of the PK orderRequired = true; } } } if (orderRequired) { // Order/Adapter (index) column is required (integer based) ColumnMetaData orderColmd = null; if (mmd.getOrderMetaData() != null && mmd.getOrderMetaData().getColumnMetaData() != null && mmd.getOrderMetaData().getColumnMetaData().length > 0) { // Specified "order" column info orderColmd = mmd.getOrderMetaData().getColumnMetaData()[0]; if (orderColmd.getName() == null) { orderColmd = new ColumnMetaData(orderColmd); if (mmd.hasExtension("adapter-column-name")) { // Specified "extension" column name // TODO Is this needed? The user can just specify <order column="..."> orderColmd.setName(mmd.getValueForExtension("adapter-column-name")); } else { // No column name so use default DatastoreIdentifier id = storeMgr.getIdentifierFactory().newIndexFieldIdentifier(mmd); orderColmd.setName(id.getIdentifierName()); } } } else { if (mmd.hasExtension("adapter-column-name")) { // Specified "extension" column name // TODO Is this needed? The user can just specify <order column="..."> orderColmd = new ColumnMetaData(); orderColmd.setName(mmd.getValueForExtension("adapter-column-name")); } else { // No column name so use default DatastoreIdentifier id = storeMgr.getIdentifierFactory().newIndexFieldIdentifier(mmd); orderColmd = new ColumnMetaData(); orderColmd.setName(id.getIdentifierName()); } } orderMapping = storeMgr .getMappingManager() .getMapping(int.class); // JDO2 spec [18.5] order column is assumed to be "int" ColumnCreator.createIndexColumn( orderMapping, storeMgr, clr, this, orderColmd, pkRequired && !pkColsSpecified); if (NucleusLogger.DATASTORE.isDebugEnabled()) { debugMapping(orderMapping); } } // Define primary key of the join table (if any) if (pkRequired) { if (pkColsSpecified) { // Apply the users PK specification applyUserPrimaryKeySpecification(pkmd); } else { // Define PK using JPOX rules if (orderRequired) { // Order column specified so owner+order are the PK orderMapping.getDatastoreMapping(0).getDatastoreField().setAsPrimaryKey(); } else { // No order column specified so owner+key are the PK for (int i = 0; i < keyMapping.getNumberOfDatastoreMappings(); i++) { keyMapping.getDatastoreMapping(i).getDatastoreField().setAsPrimaryKey(); } } } } state = TABLE_STATE_INITIALIZED; }