Search in sources :

Example 1 with ElementContainerHandler

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);
    }
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) RelationType(org.datanucleus.metadata.RelationType) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) TypeManager(org.datanucleus.store.types.TypeManager) Collection(java.util.Collection) SCOCollection(org.datanucleus.store.types.SCOCollection) SCOCollection(org.datanucleus.store.types.SCOCollection) ObjectProvider(org.datanucleus.state.ObjectProvider) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) ElementContainerHandler(org.datanucleus.store.types.ElementContainerHandler) PersistableRelationStore(org.datanucleus.store.types.scostore.PersistableRelationStore)

Example 2 with ElementContainerHandler

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);
                    }
                }
            }
        }
    }
}
Also used : AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) ElementContainerHandler(org.datanucleus.store.types.ElementContainerHandler)

Example 3 with ElementContainerHandler

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);
    }
}
Also used : SCOContainer(org.datanucleus.store.types.SCOContainer) MapHandler(org.datanucleus.store.types.containers.MapHandler) TypeManager(org.datanucleus.store.types.TypeManager) ElementContainerHandler(org.datanucleus.store.types.ElementContainerHandler)

Example 4 with 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());
                    }
                }
            }
        }
    }
}
Also used : ElementContainerAdapter(org.datanucleus.store.types.ElementContainerAdapter) ContainerHandler(org.datanucleus.store.types.ContainerHandler) ElementContainerHandler(org.datanucleus.store.types.ElementContainerHandler) ObjectProvider(org.datanucleus.state.ObjectProvider) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) ElementContainerHandler(org.datanucleus.store.types.ElementContainerHandler)

Aggregations

ElementContainerHandler (org.datanucleus.store.types.ElementContainerHandler)4 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)3 ObjectProvider (org.datanucleus.state.ObjectProvider)2 TypeManager (org.datanucleus.store.types.TypeManager)2 Collection (java.util.Collection)1 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)1 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)1 RelationType (org.datanucleus.metadata.RelationType)1 ContainerHandler (org.datanucleus.store.types.ContainerHandler)1 ElementContainerAdapter (org.datanucleus.store.types.ElementContainerAdapter)1 SCOCollection (org.datanucleus.store.types.SCOCollection)1 SCOContainer (org.datanucleus.store.types.SCOContainer)1 MapHandler (org.datanucleus.store.types.containers.MapHandler)1 PersistableRelationStore (org.datanucleus.store.types.scostore.PersistableRelationStore)1