Fields Summary |
---|
public static final int | ACT_CASCADEWhen the parent object is deleted from db,
delete the relationship object described by this object also. |
public static final int | ACT_NONEWhen the parent object is deleted,
no action is required for the relationship object described by this object. |
public static final int | ACT_NULLIFYCurrently runtime code does not interprete this action. |
public static final int | ACT_RESTRICTCurrently runtime code does not interprete this action. |
public static final int | ACT_AGGREGATECurrently runtime code does not interprete this action. |
public ClassDesc | foreignConfigClass descriptor for the class of this relationship field. |
public int | cardinalityLWB |
public int | cardinalityUPB |
public int | deleteAction |
public ArrayList | foreignFieldsArray of LocalFieldDesc. |
public ArrayList | foreignColumnsArray of ColumnElement. |
public ArrayList | localFieldsArray of LocalFieldDesc. |
public ArrayList | localColumnsArray of ColumnElement. |
public ArrayList | assocForeignFieldsArray of LocalFieldDesc. |
public ArrayList | assocForeignColumnsArray of ColumnElement. |
public ArrayList | assocLocalFieldsArray of LocalFieldDesc. |
public ArrayList | assocLocalColumnsArray of ColumnElement. |
private ForeignFieldDesc | inverseRelationshipFieldIf inverseRelationshipField is not null, it means this field is
under managed relationship. Otherwise, this is a one-way relationship. |
private boolean | isMappedToPkTrue, if the relationship is mapped to primary key fields
on the other relationship side. |
Methods Summary |
---|
private void | addForeignKeyFieldsToDFG()Silently adding hidden (local foreign key) fields to the DFG.
for (int i = 0; i < localFields.size(); i++) {
LocalFieldDesc lf = (LocalFieldDesc) localFields.get(i);
if (lf.absoluteID < 0 && !useJoinTable()) {
classDesc.getFetchGroup(GROUP_DEFAULT).add(lf);
}
}
|
private boolean | checkDependentSide(com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc inverseFieldDesc)Marks the dependent side as identified by jdo meta-data for update.
If no side is marked dependent, the following rules apply:
- Foreign key relationships can be handled from both sides,
because it must be an 1:1 relationship mapped to primary key
fields.
- Jointable relationships need to be updated from exactly one
side to implement unified dependency management. It's important to
check the dependency on both relationship sides before the responsible
side is chosen.
boolean refIntegrityUpdate;
// Check if meta data identifies the dependent relationship side.
if (this.isDependentOn(inverseFieldDesc)) {
// This side is marked dependent and will be updated.
refIntegrityUpdate = true;
} else if (inverseFieldDesc.isDependentOn(this)) {
// This side is marked as primary, the other side will be updated.
refIntegrityUpdate = false;
} else {
if (!useJoinTable()) {
// No information about the dependent side can be obtained and the
// relationship is mapped to the primary key fields on both sides.
// Relationship updates can be done from either side, but only during
// instance creation/deletion.
refIntegrityUpdate = true;
} else {
// No information about the dependent side can be obtained. If
// the Employee-Insurance relationship is mapped to a jointable,
// the dependent side can't be determinated. Identifying the
// updated side is essential to provide unified dependency
// management for the database updates, see
// SQLStateManager#manageDependencyForObjectField
refIntegrityUpdate = chooseUpdatedSide(inverseFieldDesc);
}
}
return refIntegrityUpdate;
|
private static boolean | checkForeignKey(java.util.ArrayList fieldList)Checks if at least one of the fields in fieldList
is updatable. In this case fieldList makes up a
foreign key. This is based on the assumption, that key fields
referred in relationships must not be updated. Not updatable fields
have property REF_INTEGRITY_UPDATES unset.
for (int i = 0; i < fieldList.size(); i++) {
FieldDesc lf = (FieldDesc) fieldList.get(i);
if ((lf.sqlProperties & FieldDesc.PROP_REF_INTEGRITY_UPDATES) > 0) {
// Based on the assumption, that referred key fields
// have property REF_INTEGRITY_UPDATES unset, at least
// one of the fields is not part of the key.
return true;
}
}
return false;
|
private boolean | checkForeignKeysAndDependentSide(com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc inverseFieldDesc)Checks, if one relationship side isn't mapped to primary key fields
(i.e. foreign key side). Based on the assumption, that jointable
relationships are always mapped to the primary key columns,
this method is called for foreign relationships only.
boolean refIntegrityUpdate;
// Check the foreign keys.
if (checkForeignKey(getLocalFields())) {
// The foreign key is on the local side.
refIntegrityUpdate = true;
} else if (checkForeignKey(getForeignFields())) {
// The foreign key is on the other side.
refIntegrityUpdate = false;
} else {
// The relationship is mapped to primary key columns on either side.
refIntegrityUpdate = checkDependentSide(inverseFieldDesc);
}
return refIntegrityUpdate;
|
private boolean | checkReferentialIntegrityUpdatesForCollectionField()Checks, if datastore updates will be scheduled locally or on
the opposite relationship side.
boolean refIntegrityUpdate;
ForeignFieldDesc inverseFieldDesc = getInverseRelationshipField();
if (inverseFieldDesc == null) {
refIntegrityUpdate = defineUpdatedSideXToM();
} else {
if (inverseFieldDesc.cardinalityUPB <= 1) {
// For 1:N relationships, we always update the relationship side
// which includes jointables. We indicate this by unsetting the
// REF_INTEGRITY_UPDATES property which means that integrity updates
// cannot be done locally.
refIntegrityUpdate = false;
} else {
// For N:M relationships, we choose the updated relationship side
// depending on the alphabethical order of the related class names.
// N:M relationships must be mapped to a jointable. As jointable
// entries can be created from each side, we just define the side.
refIntegrityUpdate = defineUpdatedSideNToM(inverseFieldDesc);
}
}
return refIntegrityUpdate;
|
private boolean | checkReferentialIntegrityUpdatesForObjectField()Checks, if datastore updates will be scheduled locally or on
the opposite relationship side.
boolean refIntegrityUpdate;
ForeignFieldDesc inverseFieldDesc = getInverseRelationshipField();
if (inverseFieldDesc == null) {
// Update the local side for one-way relationships.
refIntegrityUpdate = true;
} else {
if (inverseFieldDesc.cardinalityUPB > 1) {
// For 1:N relationships, we always update the local side
// which includes jointables. We indicate this by setting the
// REF_INTEGRITY_UPDATES property which means that integrity updates
// are done locally.
refIntegrityUpdate = true;
} else {
// For 1:1 relationships, we choose the updated relationship side
// depending on the side having the foreign key. If the relationship
// is mapped to primary key fields only, we consider if one side
// is marked for cascade delete. Otherwise, we choose the updatable
// side depending on the alphabethical order of the related class names.
refIntegrityUpdate = defineUpdatedSide1To1(inverseFieldDesc);
}
}
return refIntegrityUpdate;
|
private boolean | chooseUpdatedSide(com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc inverseFieldDesc)Choose the updated relationship side based on the alphabethical
order of the related class names. For self relationships, the
field names itself are compared, too.
int comparison = classDesc.getName().compareTo(foreignConfig.getName());
if (comparison == 0) {
comparison = getName().compareTo(inverseFieldDesc.getName());
}
return comparison < 0;
|
void | computeTrackedRelationshipFields()
// If the field is a ForeignFieldDesc, we only need
// to compare against other ForeignFieldDesc. The reason
// is that ForeignFieldDesc implicitly tracks a LocalFieldDesc
// (foreign key field) via relationship updates.
ForeignFieldDesc inverseField = getInverseRelationshipField();
for (int k = 0; k < classDesc.foreignFields.size(); k++) {
ForeignFieldDesc tf = (ForeignFieldDesc) classDesc.foreignFields.get(k);
if ((this != tf) && (getType() == tf.getType()) && (compareColumns(this, tf) == true)) {
if ((inverseField != null) &&
(tf.getInverseRelationshipField() == null)) {
tf.setInverseRelationshipField(inverseField);
}
// Mark the relationship field tracking the foreign key as primary.
if ((sqlProperties & FieldDesc.PROP_SECONDARY_TRACKED_FIELD) == 0) {
sqlProperties |= FieldDesc.PROP_PRIMARY_TRACKED_FIELD;
}
if ((tf.sqlProperties & FieldDesc.PROP_PRIMARY_TRACKED_FIELD) == 0) {
tf.sqlProperties |= FieldDesc.PROP_SECONDARY_TRACKED_FIELD;
}
addTrackedField(tf);
}
}
|
public java.lang.Object | createObjectId(com.sun.jdo.spi.persistence.support.sqlstore.SQLStateManager sm, LocalFieldDesc fieldDesc, java.lang.Object value)Constructs the oid of a related instance. If called by {@link
SQLStateManager#updateTrackedFields}, the new value for the
local field fieldDesc is not yet set and passed as
parameter value . If called for navigation by
{@link SQLStateManager#populateForeignField}, values of updated
local fields must be retrieved from the before image. In both
cases, the actual call to this method is in {@link
SQLStateManager#getObjectById}.
For tracked field usage, see
{@link SQLStateManager#setForeignKey} and
{@link SQLStateManager#updateTrackedFields}.
For navigation usage, see
{@link SQLStateManager#realizeForeignField}.
assert isMappedToPk();
Class oidClass = foreignConfig.getOidClass();
Object oid = null;
try {
oid = oidClass.newInstance();
} catch (Exception e) {
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
"core.statemanager.cantnewoid", oidClass.getName()), e); // NOI18N
}
Field keyFields[] = foreignConfig.getKeyFields();
String keyFieldNames[] = foreignConfig.getKeyFieldNames();
for (int i = 0; i < keyFields.length && oid != null; i++) {
Field keyField = keyFields[i];
for (int j = 0; j < foreignFields.size() && oid != null; j++) {
LocalFieldDesc fa = (LocalFieldDesc) foreignFields.get(j);
if (fa.getName().compareTo(keyFieldNames[i]) == 0) {
LocalFieldDesc la = (LocalFieldDesc) localFields.get(j);
Object keyFieldValue = null;
if (la == fieldDesc) {
keyFieldValue = value;
} else if (sm.getSetMaskBit(la.absoluteID) && !sm.getSetMaskBit(absoluteID)) {
keyFieldValue = la.getValue(sm.getBeforeImage());
} else {
keyFieldValue = la.getValue(sm);
}
if (keyFieldValue != null) {
try {
// We need to convert the keyFieldValue to the proper type before
// setting it.
keyField.set(oid, fa.convertValue(keyFieldValue, sm));
} catch (IllegalAccessException e) {
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
"core.statemanager.cantsetkeyfield", keyField.getName()), e); // NOI18N
}
} else {
oid = null;
}
}
}
}
return oid;
|
private boolean | defineUpdatedSide1To1(com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc inverseFieldDesc)Defines the updated side for one-to-one relationships. The updated side
is either defined by:
- The relationship side mapped to non-key columns.
- The relationship side is identified as dependent side, or
- Mark both sides updatable for foreign key relationships.
- Choose a side for jointable relationships.
boolean refIntegrityUpdate;
final boolean updateOtherSide = (inverseFieldDesc.sqlProperties & FieldDesc.PROP_REF_INTEGRITY_UPDATES) > 0;
if (!updateOtherSide) {
// The opposite side has already been identified not to be updated.
refIntegrityUpdate = true;
} else if (!useJoinTable()) {
// Check foreign key constraints and the dependent side.
refIntegrityUpdate = checkForeignKeysAndDependentSide(inverseFieldDesc);
} else {
// Just check the dependent side.
refIntegrityUpdate = checkDependentSide(inverseFieldDesc);
}
if (!refIntegrityUpdate && cardinalityLWB == 1) {
// Lower bound should not be 1 in this case.
// We silently set it to 0 for now.
// RESOLVE: Shall we throw an exception here?
cardinalityLWB = 0;
}
return refIntegrityUpdate;
|
private boolean | defineUpdatedSideNToM(com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc inverseFieldDesc)Defines the updated side for many-to-many relationships. As jointable
entries can be created from either side, we just define the side. The updated
side is chosen based on the alphabethical order of the related class names.
boolean refIntegrityUpdate;
final boolean updateOtherSide = (inverseFieldDesc.sqlProperties & FieldDesc.PROP_REF_INTEGRITY_UPDATES) > 0;
if (!updateOtherSide) {
// The opposite side has already been identified not to be updated.
refIntegrityUpdate = true;
} else {
refIntegrityUpdate = chooseUpdatedSide(inverseFieldDesc);
}
return refIntegrityUpdate;
|
private boolean | defineUpdatedSideXToM()Defines the updated side for a collection relationship
mapped one-way.
boolean refIntegrityUpdate;
if (!useJoinTable()) {
// As this is a foreign key relationship, the other side must
// be the one side. Foreign key relationships can be updated
// from either side, even if the inverse side is unknown.
refIntegrityUpdate = false;
} else {
// Update the local side for one-way relationships mapped to jointables.
refIntegrityUpdate = true;
}
return refIntegrityUpdate;
|
void | fixupFieldProperties()Determines the relationship side to be updated. Foreign key relationships
must always be updated on the side having the foreign key. Jointable
relationships can be handled from either side. To have unified
dependency management for foreign key _and_ jointable relationships,
it's essential that we apply the same rules defining the updated side
for foreign key and jointable relationships. We also need to always
update the same relationship side.
boolean refIntegrityUpdate = true;
if (cardinalityUPB > 1) {
// Collection side
if (!(refIntegrityUpdate = checkReferentialIntegrityUpdatesForCollectionField())) {
unsetReferentialIntegrityUpdateProperty();
// We also unset the IN_CONCURRENCY_CHECK property because we can't
// detect concurrency violation for changes made to a Collection
sqlProperties &= ~(FieldDesc.PROP_IN_CONCURRENCY_CHECK);
}
} else {
// Object side
if (!(refIntegrityUpdate = checkReferentialIntegrityUpdatesForObjectField())) {
unsetReferentialIntegrityUpdateProperty();
sqlProperties &= ~(FieldDesc.PROP_IN_CONCURRENCY_CHECK);
} else if (!useJoinTable()) {
// This side will write relationship updates to the database.
// Mark the local fields as part of the foreign key.
for (int i = 0; i < localFields.size(); i++) {
((LocalFieldDesc)localFields.get(i)).sqlProperties |= FieldDesc.PROP_FOREIGN_KEY_FIELD;
}
}
}
if (!refIntegrityUpdate) {
unsetConcurrencyCheckProperty();
}
|
void | fixupForeignReference(ClassDesc foreignConfig, com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc inverseField)Initializes relationship field information.
registerForeignConfig(foreignConfig, inverseField);
initializeFieldLists();
initializeIsMappedToPk();
addForeignKeyFieldsToDFG();
|
public java.util.ArrayList | getAssocForeignFields()
// Only create assocForeignFields if there is a corresponding
// assocForeignColumns to save space.
if (assocForeignFields == null && assocForeignColumns != null) {
assocForeignFields = new ArrayList();
}
return assocForeignFields;
|
public java.util.ArrayList | getAssocLocalFields()
// Only create assocLocalFields if there is a corresponding
// assocLocalColumns to save space.
if (assocLocalFields == null && assocLocalColumns != null) {
assocLocalFields = new ArrayList();
}
return assocLocalFields;
|
public java.util.ArrayList | getForeignFields()
if (foreignFields == null) {
foreignFields = new ArrayList();
}
return foreignFields;
|
public com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc | getInverseRelationshipField()
return inverseRelationshipField;
|
public java.util.ArrayList | getLocalFields()
if (localFields == null) {
localFields = new ArrayList();
}
return localFields;
|
public boolean | hasForeignKey()Checks the conditions that guarantee, that we have the foreign
key on this side.
boolean result = false;
// RESOLVE: Can't check PROP_REF_INTEGRITY_UPDATES for 1 way mappings.
// See #checkReferentialIntegrityUpdatesForObjectField.
if (inverseRelationshipField != null) {
result = cardinalityUPB == 1 && !useJoinTable() &&
(sqlProperties & FieldDesc.PROP_REF_INTEGRITY_UPDATES) > 0;
}
return result;
|
private void | initializeFieldLists()Initialize the field lists based on column list information.
ClassDesc theConfig = classDesc;
for (int i = 0; i < 4; i++) {
ArrayList fields = null;
ArrayList columns = null;
switch (i) {
case 0:
columns = localColumns;
fields = getLocalFields();
break;
case 1:
columns = assocLocalColumns;
fields = getAssocLocalFields();
break;
case 2:
columns = assocForeignColumns;
fields = getAssocForeignFields();
break;
case 3:
columns = foreignColumns;
fields = getForeignFields();
theConfig = foreignConfig;
break;
}
if (columns == null) continue;
for (int j = 0; j < columns.size(); j++) {
ColumnElement ce = (ColumnElement) columns.get(j);
TableElement te = ce.getDeclaringTable();
if (te == null) {
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
"core.configuration.columnnotable")); // NOI18N
}
fields.add(theConfig.getLocalFieldDesc(ce));
}
}
|
private void | initializeIsMappedToPk()Checks, if the relationship is mapped to primary key fields
on the other relationship side and sets the property
isMappedToPk .
int count = foreignFields.size();
isMappedToPk = !useJoinTable() &&
foreignConfig.getKeyFields().length == count;
for (int i = 0; i < count && isMappedToPk; i++) {
isMappedToPk = ((LocalFieldDesc) foreignFields.get(i)).isKeyField();
}
|
private boolean | isDependentOn(com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc inverseFieldDesc)Checks, if this relationship side is dependent
on the inverse side inverseFieldDesc . The
dependent side can be identified by the following criteria:
- This side has cardinalityLWB == 1.
- The inverse side is marked for cascade delete.
return (this.cardinalityLWB == 1 ||
inverseFieldDesc.deleteAction == ForeignFieldDesc.ACT_CASCADE);
|
public boolean | isMappedToPk()Returns true, if the relationship is mapped to primary key fields
on the other relationship side.
return isMappedToPk;
|
public boolean | isRelationshipField()Returns true.
return true;
|
private void | registerForeignConfig(ClassDesc foreignConfig, com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc inverseField)Registers the relationship information about the foreign class.
boolean debug = logger.isLoggable(Logger.FINEST);
if (debug) {
Object[] items = new Object[] {classDesc, this, foreignConfig};
logger.finest("sqlstore.model.classdesc.general", items); // NOI18N
}
// Remember the class descriptor for the foreign class.
this.foreignConfig = foreignConfig;
if (debug && inverseField != null) {
logger.finest("sqlstore.model.classdesc.assocrelatedfield", inverseField); //NOI18N
}
setInverseRelationshipField(inverseField);
|
private void | setInverseRelationshipField(com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc f)
inverseRelationshipField = f;
|
private void | unsetConcurrencyCheckProperty()Unsets the IN_CONCURRENCY_CHECK property for all the
(hidden) local fields involved in this relationship.
// Copy the field list temporarily.
ArrayList fieldList = (ArrayList) getLocalFields().clone();
if (useJoinTable()) {
fieldList.addAll(getAssocLocalFields());
}
for (int j = 0; j < fieldList.size(); j++) {
FieldDesc lf = (FieldDesc) fieldList.get(j);
if (lf.absoluteID < 0) {
if (logger.isLoggable(Logger.FINEST)) {
logger.finest("sqlstore.model.classdesc.unsetconcurrencychk", lf.getName()); // NOI18N
}
lf.sqlProperties &= ~(FieldDesc.PROP_IN_CONCURRENCY_CHECK);
}
}
|
private void | unsetReferentialIntegrityUpdateProperty()Unsets the REF_INTEGRITY_UPDATES property for this relationship field.
Datastore updates will be scheduled on the opposite relationship side.
if (logger.isLoggable(Logger.FINEST)) {
logger.finest("sqlstore.model.classdesc.unsetrefintegrityupdate", getName()); // NOI18N
}
sqlProperties &= ~(FieldDesc.PROP_REF_INTEGRITY_UPDATES);
|
public boolean | useJoinTable()Returns true, if the relationship is mapped to a join table.
return (assocLocalColumns != null && assocLocalColumns.size() > 0);
|