use of org.datanucleus.store.types.ElementContainerHandler in project datanucleus-rdbms by datanucleus.
the class PersistableMapping method postInsert.
/**
* Method executed just after the insert of the owning object, allowing any necessary action
* to this field and the object stored in it.
* @param op ObjectProvider for the owner
*/
public void postInsert(ObjectProvider op) {
Object pc = op.provideField(mmd.getAbsoluteFieldNumber());
TypeManager typeManager = op.getExecutionContext().getTypeManager();
pc = mmd.isSingleCollection() ? singleCollectionValue(typeManager, pc) : pc;
if (pc == null) {
// Has been set to null so nothing to do
return;
}
ClassLoaderResolver clr = op.getExecutionContext().getClassLoaderResolver();
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
RelationType relationType = mmd.getRelationType(clr);
if (relationType == RelationType.ONE_TO_ONE_BI) {
ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
if (otherOP == null) {
return;
}
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, op.getObject(), pc);
if (relatedMmd == null) {
// Fsck knows why
throw new NucleusUserException("You have a field " + mmd.getFullFieldName() + " that is 1-1 bidir yet cannot find the equivalent field at the other side. Why is that?");
}
Object relatedValue = otherOP.provideField(relatedMmd.getAbsoluteFieldNumber());
relatedValue = relatedMmd.isSingleCollection() ? singleCollectionValue(typeManager, relatedValue) : relatedValue;
if (relatedValue == null) {
// Managed Relations : Other side not set so update it in memory
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("041018", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), relatedMmd.getFullFieldName()));
}
Object replaceValue = op.getObject();
if (relatedMmd.isSingleCollection()) {
ElementContainerHandler containerHandler = typeManager.getContainerHandler(relatedMmd.getType());
replaceValue = containerHandler.newContainer(relatedMmd, op.getObject());
}
otherOP.replaceField(relatedMmd.getAbsoluteFieldNumber(), replaceValue);
} else if (relatedValue != op.getObject()) {
// Managed Relations : Other side is inconsistent so throw exception
throw new NucleusUserException(Localiser.msg("041020", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), StringUtils.toJVMIDString(relatedValue)));
}
} else if (relationType == RelationType.MANY_TO_ONE_BI && relatedMmds[0].hasCollection()) {
// TODO Make sure we have this PC in the collection at the other side
ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
if (otherOP != null) {
// Managed Relations : add to the collection on the other side
Collection relatedColl = (Collection) otherOP.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (relatedColl != null && !(relatedColl instanceof SCOCollection)) {
// TODO Make sure the collection is a wrapper
boolean contained = relatedColl.contains(op.getObject());
if (!contained) {
NucleusLogger.PERSISTENCE.info(Localiser.msg("041022", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), relatedMmds[0].getFullFieldName()));
// TODO Enable this. Currently causes issues with PMImplTest, InheritanceStrategyTest, TCK "inheritance1.conf"
/*relatedColl.add(op.getObject());*/
}
}
}
} else if (relationType == RelationType.MANY_TO_ONE_UNI) {
ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
if (otherOP == null) {
// Related object is not yet persisted so persist it
Object other = op.getExecutionContext().persistObjectInternal(pc, null, -1, ObjectProvider.PC);
otherOP = op.getExecutionContext().findObjectProvider(other);
}
// Add join table entry
PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
store.add(op, otherOP);
}
}
use of org.datanucleus.store.types.ElementContainerHandler in project datanucleus-core by datanucleus.
the class RelationshipManagerImpl method processOneToOneBidirectionalRelation.
/**
* Method to process all 1-1 bidir fields.
* Processes the case where we had a 1-1 field set at this side previously to some value and now to
* some other value. We need to make sure that all of the affected objects are now related consistently.
* Taking an example <pre>a.b = b1; a.b = b2;</pre> so A's b field is changed from b1 to b2.
* The following changes are likely to be necessary
* <ul>
* <li>b1.a = null - so we null out the old related objects link back to this object</li>
* <li>b2.oldA = null - if b2 was previously related to a different A, null out that objects link to b2</li>
* <li>b2.a = a - set the link from b2 back to a so it is bidirectional</li>
* </ul>
* @param mmd MetaData for the field
* @param clr ClassLoader resolver
* @param ec ExecutionContext
* @param changes List of changes to the field
*/
protected void processOneToOneBidirectionalRelation(AbstractMemberMetaData mmd, ClassLoaderResolver clr, ExecutionContext ec, List<RelationChange> changes) {
for (RelationChange change : changes) {
if (change.type == ChangeType.CHANGE_OBJECT) {
Object oldValue = change.oldValue;
// TODO Use change.value (JDO TCK test pm.conf can fail due to being hollow instead of transient)
Object newValue = ownerOP.provideField(mmd.getAbsoluteFieldNumber());
oldValue = mmd.isSingleCollection() ? singleCollectionValue(ec.getTypeManager(), oldValue) : oldValue;
if (oldValue != null) {
// Previously had "a.b = b1"; "a.b" has been changed
// Need to remove from the other side if still set
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, pc, oldValue);
ObjectProvider oldOP = ec.findObjectProvider(oldValue);
if (oldOP != null) {
boolean oldIsDeleted = ec.getApiAdapter().isDeleted(oldOP.getObject());
if (!oldIsDeleted) {
// Old still exists, so make sure its relation is correct
if (!oldOP.isFieldLoaded(relatedMmd.getAbsoluteFieldNumber())) {
// Load the field in case we need to set the old value
oldOP.loadField(relatedMmd.getAbsoluteFieldNumber());
}
Object oldValueFieldValue = oldOP.provideField(relatedMmd.getAbsoluteFieldNumber());
oldValueFieldValue = mmd.isSingleCollection() ? singleCollectionValue(ec.getTypeManager(), oldValueFieldValue) : oldValueFieldValue;
if (oldValueFieldValue == null) {
// Set to null so nothing to do
} else if (oldValueFieldValue == pc) {
// Still set to this object, so null out the other objects relation
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("013004", StringUtils.toJVMIDString(oldValue), relatedMmd.getFullFieldName(), StringUtils.toJVMIDString(pc), StringUtils.toJVMIDString(newValue)));
}
Object replaceValue = null;
if (relatedMmd.isSingleCollection()) {
replaceValue = ec.getTypeManager().getContainerHandler(relatedMmd.getType()).newContainer(mmd);
}
oldOP.replaceFieldValue(relatedMmd.getAbsoluteFieldNumber(), replaceValue);
}
} else {
// Old value is already deleted so don't need to set its relation field
}
}
}
newValue = mmd.isSingleCollection() ? singleCollectionValue(ec.getTypeManager(), newValue) : newValue;
if (newValue != null) {
// Previously had "a.b = b1"; Now have "a.b = b2"
// Need to set the other side if not yet set, and unset any related old value on the other side
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, pc, newValue);
// Force persistence because it might not be persisted yet when using delayed operations
ObjectProvider newOP = ec.findObjectProvider(newValue, true);
if (newOP != null && relatedMmd != null) {
if (!newOP.isFieldLoaded(relatedMmd.getAbsoluteFieldNumber())) {
// Load the field in case we need to set the link from the old value
newOP.loadField(relatedMmd.getAbsoluteFieldNumber());
}
Object newValueFieldValue = newOP.provideField(relatedMmd.getAbsoluteFieldNumber());
if (relatedMmd.isSingleCollection()) {
newValueFieldValue = singleCollectionValue(ec.getTypeManager(), newValueFieldValue);
}
if (newValueFieldValue == null) {
// Was set to null so set to our object
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("013005", StringUtils.toJVMIDString(newValue), relatedMmd.getFullFieldName(), StringUtils.toJVMIDString(pc)));
}
Object replaceValue = pc;
if (relatedMmd.isSingleCollection()) {
ElementContainerHandler containerHandler = ec.getTypeManager().getContainerHandler(relatedMmd.getType());
replaceValue = containerHandler.newContainer(null, pc);
}
newOP.replaceFieldValue(relatedMmd.getAbsoluteFieldNumber(), replaceValue);
} else if (newValueFieldValue != pc) {
// Was set to different object, so null out the other objects relation
ObjectProvider newValueFieldOP = ec.findObjectProvider(newValueFieldValue);
if (newValueFieldOP != null) {
// Null out the field of the related object of the new value
if (!newValueFieldOP.isFieldLoaded(mmd.getAbsoluteFieldNumber())) {
// Load the field in case we need to set the link from the old value
newValueFieldOP.loadField(mmd.getAbsoluteFieldNumber());
}
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("013004", StringUtils.toJVMIDString(newValueFieldValue), mmd.getFullFieldName(), StringUtils.toJVMIDString(newValue), StringUtils.toJVMIDString(pc)));
}
newValueFieldOP.replaceFieldValue(mmd.getAbsoluteFieldNumber(), null);
}
// Update the field of the new value to our object
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("013005", StringUtils.toJVMIDString(newValue), relatedMmd.getFullFieldName(), StringUtils.toJVMIDString(pc)));
}
Object replaceValue = pc;
if (relatedMmd.isSingleCollection()) {
ElementContainerHandler containerHandler = ec.getTypeManager().getContainerHandler(relatedMmd.getType());
replaceValue = containerHandler.newContainer(null, pc);
}
newOP.replaceFieldValue(relatedMmd.getAbsoluteFieldNumber(), replaceValue);
}
}
}
}
}
}
use of org.datanucleus.store.types.ElementContainerHandler in project datanucleus-core by datanucleus.
the class L2CachePopulateFieldManager method processContainer.
private void processContainer(int fieldNumber, Object container, AbstractMemberMetaData mmd) {
Object unwrappedContainer = container;
if (container instanceof SCOContainer) {
if (!((SCOContainer) container).isLoaded()) {
// Contents not loaded so just mark as unloaded
cachedPC.setLoadedField(fieldNumber, false);
return;
}
unwrappedContainer = ((SCO) container).getValue();
}
TypeManager typeManager = op.getExecutionContext().getTypeManager();
if (mmd.hasMap()) {
MapHandler mapHandler = typeManager.getContainerHandler(mmd.getType());
processMapContainer(fieldNumber, unwrappedContainer, mmd, mapHandler);
} else {
ElementContainerHandler elementContainerHandler = typeManager.getContainerHandler(mmd.getType());
processElementContainer(fieldNumber, unwrappedContainer, mmd, elementContainerHandler);
}
}
use of org.datanucleus.store.types.ElementContainerHandler in project datanucleus-core by datanucleus.
the class DeleteFieldManager method processSingleValue.
private void processSingleValue(Object value, AbstractMemberMetaData mmd, ExecutionContext ec, RelationType relationType) {
// Process PC fields
if (mmd.isDependent()) {
processPersistable(value);
} else if (manageRelationships && RelationType.isBidirectional(relationType) && !mmd.isEmbedded()) {
ObjectProvider valueOP = ec.findObjectProvider(value);
if (valueOP != null && !valueOP.getLifecycleState().isDeleted() && !valueOP.isDeleting()) {
AbstractMemberMetaData relMmd = mmd.getRelatedMemberMetaData(ec.getClassLoaderResolver())[0];
if (relationType == RelationType.ONE_TO_ONE_BI) {
valueOP.replaceFieldMakeDirty(relMmd.getAbsoluteFieldNumber(), null);
valueOP.flush();
} else if (relationType == RelationType.MANY_TO_ONE_BI) {
// Make sure field at other side is loaded, and remove from any Collection
valueOP.loadField(relMmd.getAbsoluteFieldNumber());
Object relValue = valueOP.provideField(relMmd.getAbsoluteFieldNumber());
if (relValue != null) {
ContainerHandler containerHandler = ec.getTypeManager().getContainerHandler(relMmd.getType());
if (containerHandler instanceof ElementContainerHandler) {
ElementContainerAdapter adapter = (ElementContainerAdapter) containerHandler.getAdapter(relValue);
adapter.remove(op.getObject());
}
}
}
}
}
}
Aggregations