use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.
the class PersistableMapping method postUpdate.
/**
* Method executed just afer any update of the owning object, allowing any necessary action to this field and the object stored in it.
* @param sm StateManager for the owner
*/
public void postUpdate(DNStateManager sm) {
Object pc = sm.provideField(mmd.getAbsoluteFieldNumber());
pc = mmd.isSingleCollection() ? SCOUtils.singleCollectionValue(getStoreManager().getNucleusContext().getTypeManager(), pc) : pc;
ClassLoaderResolver clr = sm.getExecutionContext().getClassLoaderResolver();
RelationType relationType = mmd.getRelationType(clr);
if (pc == null) {
if (relationType == RelationType.MANY_TO_ONE_UNI) {
// Update join table entry
PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
store.remove(sm);
}
return;
}
DNStateManager otherSM = sm.getExecutionContext().findStateManager(pc);
if (otherSM == null) {
if (relationType == RelationType.ONE_TO_ONE_BI || relationType == RelationType.MANY_TO_ONE_BI || relationType == RelationType.MANY_TO_ONE_UNI) {
// Related object is not yet persisted (e.g 1-1 with FK at other side) so persist it
Object other = sm.getExecutionContext().persistObjectInternal(pc, null, -1, PersistableObjectType.PC);
otherSM = sm.getExecutionContext().findStateManager(other);
}
}
if (relationType == RelationType.MANY_TO_ONE_UNI) {
// Update join table entry
PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
store.update(sm, otherSM);
}
}
use of org.datanucleus.state.DNStateManager 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 sm StateManager for the owner
*/
public void postInsert(DNStateManager sm) {
Object pc = sm.provideField(mmd.getAbsoluteFieldNumber());
TypeManager typeManager = sm.getExecutionContext().getTypeManager();
pc = mmd.isSingleCollection() ? singleCollectionValue(typeManager, pc) : pc;
if (pc == null) {
// Has been set to null so nothing to do
return;
}
ClassLoaderResolver clr = sm.getExecutionContext().getClassLoaderResolver();
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
RelationType relationType = mmd.getRelationType(clr);
if (relationType == RelationType.ONE_TO_ONE_BI) {
DNStateManager otherSM = sm.getExecutionContext().findStateManager(pc);
if (otherSM == null) {
return;
}
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, sm.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 = otherSM.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", sm.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), relatedMmd.getFullFieldName()));
}
Object replaceValue = sm.getObject();
if (relatedMmd.isSingleCollection()) {
ElementContainerHandler containerHandler = typeManager.getContainerHandler(relatedMmd.getType());
replaceValue = containerHandler.newContainer(relatedMmd, sm.getObject());
}
otherSM.replaceField(relatedMmd.getAbsoluteFieldNumber(), replaceValue);
} else if (relatedValue != sm.getObject()) {
// Managed Relations : Other side is inconsistent so throw exception
throw new NucleusUserException(Localiser.msg("041020", sm.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
DNStateManager otherSM = sm.getExecutionContext().findStateManager(pc);
if (otherSM != null) {
// Managed Relations : add to the collection on the other side
Collection relatedColl = (Collection) otherSM.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (relatedColl != null && !(relatedColl instanceof SCOCollection)) {
// TODO Make sure the collection is a wrapper
boolean contained = relatedColl.contains(sm.getObject());
if (!contained) {
NucleusLogger.PERSISTENCE.info(Localiser.msg("041022", sm.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) {
DNStateManager otherSM = sm.getExecutionContext().findStateManager(pc);
if (otherSM == null) {
// Related object is not yet persisted so persist it
Object other = sm.getExecutionContext().persistObjectInternal(pc, null, -1, PersistableObjectType.PC);
otherSM = sm.getExecutionContext().findStateManager(other);
}
// Add join table entry
PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
store.add(sm, otherSM);
}
}
use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.
the class PersistableMapping method getObject.
/**
* Returns an instance of a persistable class.
* Processes the FK field and generates the id of the object from the result values, and hence the object itself.
* TODO Pass in the discriminator/version columns also where available
* @param ec execution context
* @param rs The ResultSet
* @param resultIndexes indexes in the ResultSet to retrieve
* @return The persistable object
*/
public Object getObject(ExecutionContext ec, final ResultSet rs, int[] resultIndexes) {
// Check for null FK
if (storeMgr.getResultValueAtPosition(rs, this, resultIndexes[0]) == null) {
// Assumption : if the first param is null, then the field is null
return null;
}
// Return the object represented by this mapping
Object pc = null;
if (cmd.getIdentityType() == IdentityType.DATASTORE) {
pc = MappingHelper.getObjectForDatastoreIdentity(ec, this, rs, resultIndexes, cmd);
} else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
pc = MappingHelper.getObjectForApplicationIdentity(ec, this, rs, resultIndexes, cmd);
} else {
return null;
}
// Sanity check that we have loaded the version also
DNStateManager pcSM = ec.findStateManager(pc);
if (pcSM != null) {
VersionMetaData vermd = cmd.getVersionMetaDataForTable();
if (vermd != null && vermd.getStrategy() != VersionStrategy.NONE && ec.getTransaction().getOptimistic() && !pcSM.isVersionLoaded()) {
// For some reason the version was not loaded on this object, and wanting to delete it, so load the version (+DFG) now.
// This can happen when we have 1-1 between A and B and we loaded the B field of A via FetchRequest but didn't pull in the version since the inheritance wasn't knowable
pcSM.loadUnloadedFieldsInFetchPlan();
}
}
return pc;
}
use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.
the class PersistableMapping method preDelete.
/**
* Method executed just before the owning object is deleted, allowing tidying up of any relation information.
* @param sm StateManager for the owner
*/
public void preDelete(DNStateManager sm) {
int fieldNumber = mmd.getAbsoluteFieldNumber();
ExecutionContext ec = sm.getExecutionContext();
ClassLoaderResolver clr = ec.getClassLoaderResolver();
RelationType relationType = mmd.getRelationType(clr);
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
// Check if we should delete the related object when this object is deleted
boolean dependent = mmd.isDependent();
if (mmd.isCascadeRemoveOrphans()) {
// JPA allows "orphan removal" to define deletion of the other side
dependent = true;
}
if (!dependent) {
if (relationType == RelationType.ONE_TO_ONE_UNI) {
// Special case of FK this side and unidirectional, just return
return;
}
// TODO If we have the FK and not dependent then should avoid the load on the related object
}
if (!sm.isFieldLoaded(fieldNumber)) {
// Load the field if we need its value
try {
// First try from stored FK value, otherwise load from database
if (!sm.loadStoredField(fieldNumber)) {
sm.loadField(fieldNumber);
}
} catch (NucleusObjectNotFoundException onfe) {
// Already deleted so just return
return;
}
}
Object pc = sm.provideField(fieldNumber);
pc = mmd.isSingleCollection() ? SCOUtils.singleCollectionValue(getStoreManager().getNucleusContext().getTypeManager(), pc) : pc;
if (pc == null) {
// Null value so nothing to do
return;
}
// N-1 Uni, so delete join table entry
if (relationType == RelationType.MANY_TO_ONE_UNI) {
// Update join table entry
PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
store.remove(sm);
}
// Check if the field has a FK defined TODO Cater for more than 1 related field
boolean hasFK = false;
if (!dependent) {
// Not dependent, so check if the datastore has a FK and will take care of it for us
if (mmd.getForeignKeyMetaData() != null) {
hasFK = true;
}
if (RelationType.isBidirectional(relationType) && relatedMmds[0].getForeignKeyMetaData() != null) {
hasFK = true;
}
if (ec.getStringProperty(PropertyNames.PROPERTY_DELETION_POLICY).equals("JDO2")) {
// JDO doesn't currently take note of foreign-key
hasFK = false;
}
}
// There may be some corner cases that this code doesn't yet cater for
if (relationType == RelationType.ONE_TO_ONE_UNI || (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() == null)) {
// 1-1 with FK at this side (owner of the relation)
if (dependent) {
boolean relatedObjectDeleted = ec.getApiAdapter().isDeleted(pc);
if (isNullable() && !relatedObjectDeleted) {
// Other object not yet deleted, but the field is nullable so just null out the FK
// TODO Not doing this would cause errors in 1-1 uni relations (e.g AttachDetachTest)
// TODO Log this since it affects the resultant objects
sm.replaceFieldMakeDirty(fieldNumber, null);
storeMgr.getPersistenceHandler().updateObject(sm, new int[] { fieldNumber });
if (!relatedObjectDeleted) {
// Mark the other object for deletion since not yet tagged
ec.deleteObjectInternal(pc);
}
} else {
// Can't just delete the other object since that would cause a FK constraint violation. Do nothing - handled by DeleteRequest on other object
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.DATASTORE_PERSIST.debug(Localiser.msg("041017", StringUtils.toJVMIDString(sm.getObject()), mmd.getFullFieldName()));
}
}
} else {
// We're deleting the FK at this side so shouldn't be an issue
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, sm.getObject(), pc);
if (relatedMmd != null) {
DNStateManager otherSM = ec.findStateManager(pc);
if (otherSM != null) {
// Managed Relations : 1-1 bidir, so null out the object at the other
Object currentValue = otherSM.provideField(relatedMmd.getAbsoluteFieldNumber());
if (currentValue != null) {
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("041019", StringUtils.toJVMIDString(pc), relatedMmd.getFullFieldName(), sm.getObjectAsPrintable()));
}
otherSM.replaceFieldMakeDirty(relatedMmd.getAbsoluteFieldNumber(), null);
if (ec.getManageRelations()) {
otherSM.getExecutionContext().getRelationshipManager(otherSM).relationChange(relatedMmd.getAbsoluteFieldNumber(), sm.getObject(), null);
}
}
}
}
}
} else if (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() != null) {
// 1-1 with FK at other side
DatastoreClass relatedTable = storeMgr.getDatastoreClass(relatedMmds[0].getClassName(), clr);
JavaTypeMapping relatedMapping = relatedTable.getMemberMapping(relatedMmds[0]);
boolean isNullable = relatedMapping.isNullable();
DNStateManager otherSM = ec.findStateManager(pc);
if (dependent) {
if (isNullable) {
// Null out the FK in the datastore using a direct update (since we are deleting)
otherSM.replaceFieldMakeDirty(relatedMmds[0].getAbsoluteFieldNumber(), null);
storeMgr.getPersistenceHandler().updateObject(otherSM, new int[] { relatedMmds[0].getAbsoluteFieldNumber() });
}
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
} else if (!hasFK) {
if (isNullable()) {
Object currentRelatedValue = otherSM.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (currentRelatedValue != null) {
// Null out the FK in the datastore using a direct update (since we are deleting)
otherSM.replaceFieldMakeDirty(relatedMmds[0].getAbsoluteFieldNumber(), null);
storeMgr.getPersistenceHandler().updateObject(otherSM, new int[] { relatedMmds[0].getAbsoluteFieldNumber() });
// Managed Relations : 1-1 bidir, so null out the object at the other
if (ec.getManageRelations()) {
otherSM.getExecutionContext().getRelationshipManager(otherSM).relationChange(relatedMmds[0].getAbsoluteFieldNumber(), sm.getObject(), null);
}
}
} else {
// TODO Remove it
}
} else {
// User has a FK defined (in MetaData) so let the datastore take care of it
}
} else if (relationType == RelationType.MANY_TO_ONE_BI) {
DNStateManager otherSM = ec.findStateManager(pc);
if (relatedMmds[0].getJoinMetaData() == null) {
// N-1 with FK at this side
if (otherSM.isDeleting()) {
// Other object is being deleted too but this side has the FK so just delete this object
} else {
// Other object is not being deleted so delete it if necessary
if (dependent) {
if (isNullable()) {
// TODO Datastore nullability info can be unreliable so try to avoid this call
// Null out the FK in the datastore using a direct update (since we are deleting)
sm.replaceFieldMakeDirty(fieldNumber, null);
storeMgr.getPersistenceHandler().updateObject(sm, new int[] { fieldNumber });
}
if (ec.getApiAdapter().isDeleted(pc)) {
// Object is already tagged for deletion but we're deleting the FK so leave til flush()
} else {
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
}
} else {
// Managed Relations : remove element from collection/map
if (relatedMmds[0].hasCollection()) {
// Only update the other side if not already being deleted
if (!ec.getApiAdapter().isDeleted(otherSM.getObject()) && !otherSM.isDeleting()) {
// Make sure the other object is updated in any caches
ec.markDirty(otherSM, false);
// Make sure collection field is loaded
otherSM.isLoaded(relatedMmds[0].getAbsoluteFieldNumber());
Collection otherColl = (Collection) otherSM.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (otherColl != null) {
if (ec.getManageRelations()) {
otherSM.getExecutionContext().getRelationshipManager(otherSM).relationRemove(relatedMmds[0].getAbsoluteFieldNumber(), sm.getObject());
}
if (otherColl.contains(sm.getObject())) {
// TODO Localise this message
NucleusLogger.PERSISTENCE.debug("ManagedRelationships : delete of object causes removal from collection at " + relatedMmds[0].getFullFieldName());
otherColl.remove(sm.getObject());
}
}
}
} else if (relatedMmds[0].hasMap()) {
// TODO Cater for maps, but what is the key/value pair ?
}
}
}
} else {
// N-1 with join table so no FK here so need to remove from Collection/Map first? (managed relations)
if (dependent) {
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
} else {
// Managed Relations : remove element from collection/map
if (relatedMmds[0].hasCollection()) {
// Only update the other side if not already being deleted
if (!ec.getApiAdapter().isDeleted(otherSM.getObject()) && !otherSM.isDeleting()) {
// Make sure the other object is updated in any caches
ec.markDirty(otherSM, false);
// Make sure the other object has the collection loaded so does this change
otherSM.isLoaded(relatedMmds[0].getAbsoluteFieldNumber());
Collection otherColl = (Collection) otherSM.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (otherColl != null && otherColl.contains(sm.getObject())) {
// TODO Localise this
NucleusLogger.PERSISTENCE.debug("ManagedRelationships : delete of object causes removal from collection at " + relatedMmds[0].getFullFieldName());
otherColl.remove(sm.getObject());
}
}
} else if (relatedMmds[0].hasMap()) {
// TODO Cater for maps, but what is the key/value pair ?
}
}
}
} else if (relationType == RelationType.MANY_TO_ONE_UNI) {
// N-1 uni with join table
if (dependent) {
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
}
} else {
// No relation so what is this field ?
}
}
use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.
the class EmbeddedMapping method setObject.
/**
* Mutator for the embedded object in the datastore.
* @param ec ExecutionContext
* @param ps The Prepared Statement
* @param value The embedded object to use
* @param ownerSM StateManager of the owning object containing this embedded object
* @param ownerFieldNumber Field number in the owning object where this is stored
* @param param Param numbers in the PreparedStatement for the fields of this object
*/
@Override
public void setObject(ExecutionContext ec, PreparedStatement ps, int[] param, Object value, DNStateManager ownerSM, int ownerFieldNumber) {
if (value == null) {
String nullColumn = (emd != null) ? emd.getNullIndicatorColumn() : null;
String nullValue = (emd != null) ? emd.getNullIndicatorValue() : null;
int n = 0;
if (discrimMapping != null) {
discrimMapping.setObject(ec, ps, new int[] { param[n] }, null);
n++;
}
int numJavaMappings = javaTypeMappings.size();
for (int i = 0; i < numJavaMappings; i++) {
JavaTypeMapping mapping = javaTypeMappings.get(i);
int[] posMapping = new int[mapping.getNumberOfColumnMappings()];
for (int j = 0; j < posMapping.length; j++) {
posMapping[j] = param[n++];
}
// in which case apply the required value
if (nullColumn != null && nullValue != null && mapping.getMemberMetaData().getColumnMetaData().length > 0 && mapping.getMemberMetaData().getColumnMetaData()[0].getName().equals(nullColumn)) {
// Try to cater for user having an integer based column and value
if (mapping instanceof IntegerMapping || mapping instanceof BigIntegerMapping || mapping instanceof LongMapping || mapping instanceof ShortMapping) {
Object convertedValue = null;
try {
if (mapping instanceof IntegerMapping || mapping instanceof ShortMapping) {
convertedValue = Integer.valueOf(nullValue);
} else if (mapping instanceof LongMapping || mapping instanceof BigIntegerMapping) {
convertedValue = Long.valueOf(nullValue);
}
} catch (Exception e) {
}
mapping.setObject(ec, ps, posMapping, convertedValue);
} else {
mapping.setObject(ec, ps, posMapping, nullValue);
}
} else {
if (mapping.getNumberOfColumnMappings() > 0) {
mapping.setObject(ec, ps, posMapping, null);
}
}
}
} else {
ApiAdapter api = ec.getApiAdapter();
if (!api.isPersistable(value)) {
throw new NucleusException(Localiser.msg("041016", value.getClass(), value)).setFatal();
}
AbstractClassMetaData embCmd = ec.getMetaDataManager().getMetaDataForClass(value.getClass(), ec.getClassLoaderResolver());
DNStateManager embSM = ec.findStateManager(value);
if (embSM == null || api.getExecutionContext(value) == null) {
// Assign a StateManager to manage our embedded object
embSM = ec.getNucleusContext().getStateManagerFactory().newForEmbedded(ec, value, false, ownerSM, ownerFieldNumber, objectType);
}
int n = 0;
if (discrimMapping != null) {
if (discrimMetaData.getStrategy() != DiscriminatorStrategy.NONE) {
discrimMapping.setObject(ec, ps, new int[] { param[n] }, embCmd.getDiscriminatorValue());
}
n++;
}
int numJavaMappings = javaTypeMappings.size();
for (int i = 0; i < numJavaMappings; i++) {
JavaTypeMapping mapping = javaTypeMappings.get(i);
int[] posMapping = new int[mapping.getNumberOfColumnMappings()];
for (int j = 0; j < posMapping.length; j++) {
posMapping[j] = param[n++];
}
// Retrieve value of member from Embedded StateManager
int embAbsFieldNum = embCmd.getAbsolutePositionOfMember(mapping.getMemberMetaData().getName());
if (embAbsFieldNum >= 0) {
// Member is present in this embedded type
Object fieldValue = embSM.provideField(embAbsFieldNum);
if (mapping instanceof EmbeddedPCMapping) {
mapping.setObject(ec, ps, posMapping, fieldValue, embSM, embAbsFieldNum);
} else {
if (mapping.getNumberOfColumnMappings() > 0) {
mapping.setObject(ec, ps, posMapping, fieldValue);
}
}
} else {
mapping.setObject(ec, ps, posMapping, null);
}
}
}
}
Aggregations