use of org.datanucleus.state.ObjectProvider in project datanucleus-rdbms by datanucleus.
the class FKSetStore method add.
/**
* Method to add an object to the relationship at the collection end.
* @param ownerOP ObjectProvider for the owner.
* @param element Element to be added
* @return Success indicator
*/
public boolean add(final ObjectProvider ownerOP, E element, int size) {
if (element == null) {
// Sets allow no duplicates
throw new NucleusUserException(Localiser.msg("056039"));
}
// Make sure that the element is persisted in the datastore (reachability)
final Object newOwner = ownerOP.getObject();
final ExecutionContext ec = ownerOP.getExecutionContext();
// Find the (element) table storing the FK back to the owner
boolean isPersistentInterface = storeMgr.getNucleusContext().getMetaDataManager().isPersistentInterface(elementType);
DatastoreClass elementTable = null;
if (isPersistentInterface) {
elementTable = storeMgr.getDatastoreClass(storeMgr.getNucleusContext().getMetaDataManager().getImplementationNameForPersistentInterface(elementType), clr);
} else {
Class elementTypeCls = clr.classForName(elementType);
if (elementTypeCls.isInterface()) {
// Set<interface> so use type of element passed in and get its table
elementTable = storeMgr.getDatastoreClass(element.getClass().getName(), clr);
} else {
// Use table for element type
elementTable = storeMgr.getDatastoreClass(elementType, clr);
}
}
if (elementTable == null) {
// "subclass-table", persisted into table of other class
AbstractClassMetaData[] managingCmds = storeMgr.getClassesManagingTableForClass(elementCmd, clr);
if (managingCmds != null && managingCmds.length > 0) {
// Find which of these subclasses is appropriate for this element
for (int i = 0; i < managingCmds.length; i++) {
Class tblCls = clr.classForName(managingCmds[i].getFullClassName());
if (tblCls.isAssignableFrom(element.getClass())) {
elementTable = storeMgr.getDatastoreClass(managingCmds[i].getFullClassName(), clr);
break;
}
}
}
}
final DatastoreClass elementTbl = elementTable;
boolean inserted = validateElementForWriting(ec, element, new FieldValues() {
public void fetchFields(ObjectProvider elementOP) {
if (elementTbl != null) {
JavaTypeMapping externalFKMapping = elementTbl.getExternalMapping(ownerMemberMetaData, MappingType.EXTERNAL_FK);
if (externalFKMapping != null) {
// The element has an external FK mapping so set the value it needs to use in the INSERT
elementOP.setAssociatedValue(externalFKMapping, ownerOP.getObject());
}
if (relationDiscriminatorMapping != null) {
// Element type has a shared FK so set the discriminator value for this relation
elementOP.setAssociatedValue(relationDiscriminatorMapping, relationDiscriminatorValue);
}
}
int fieldNumInElement = getFieldNumberInElementForBidirectional(elementOP);
if (fieldNumInElement >= 0) {
// TODO Move this into RelationshipManager
// Managed Relations : 1-N bidir, so make sure owner is correct at persist
Object currentOwner = elementOP.provideField(fieldNumInElement);
if (currentOwner == null) {
// No owner, so correct it
NucleusLogger.PERSISTENCE.info(Localiser.msg("056037", ownerOP.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(elementOP.getObject())));
elementOP.replaceFieldMakeDirty(fieldNumInElement, newOwner);
} else if (currentOwner != newOwner) {
// Check for owner change
Object ownerId1 = ec.getApiAdapter().getIdForObject(currentOwner);
Object ownerId2 = ec.getApiAdapter().getIdForObject(newOwner);
if (ownerId1 != null && ownerId2 != null && ownerId1.equals(ownerId2)) {
// Must be attaching
if (!ec.getApiAdapter().isDetached(newOwner)) {
// Attaching, so make sure we set to the attached owner
elementOP.replaceField(fieldNumInElement, newOwner);
}
} else if (ownerOP.getReferencedPC() == null) {
// Not being attached so must be inconsistent owner, so throw exception
throw new NucleusUserException(Localiser.msg("056038", ownerOP.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(elementOP.getObject()), StringUtils.toJVMIDString(currentOwner)));
}
}
}
}
public void fetchNonLoadedFields(ObjectProvider op) {
}
public FetchPlan getFetchPlanForLoading() {
return null;
}
});
if (inserted) {
// Element has just been persisted so the FK will be set
return true;
}
// Element was already persistent so make sure the FK is in place
// TODO This is really "ManagedRelationships" so needs to go in RelationshipManager
ObjectProvider elementOP = ec.findObjectProvider(element);
if (elementOP == null) {
// Element is likely being attached and this is the detached element; lookup the attached element via the id
Object elementId = ec.getApiAdapter().getIdForObject(element);
if (elementId != null) {
element = (E) ec.findObject(elementId, false, false, element.getClass().getName());
if (element != null) {
elementOP = ec.findObjectProvider(element);
}
}
}
int fieldNumInElement = getFieldNumberInElementForBidirectional(elementOP);
if (fieldNumInElement >= 0 && elementOP != null) {
// Managed Relations : 1-N bidir, so update the owner of the element
// Ensure is loaded
elementOP.isLoaded(fieldNumInElement);
Object oldOwner = elementOP.provideField(fieldNumInElement);
if (oldOwner != newOwner) {
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("055009", ownerOP.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(element)));
}
elementOP.replaceFieldMakeDirty(fieldNumInElement, newOwner);
if (ec.getManageRelations()) {
// Managed Relationships - add the change we've made here to be analysed at flush
RelationshipManager relationshipManager = ec.getRelationshipManager(elementOP);
relationshipManager.relationChange(fieldNumInElement, oldOwner, newOwner);
if (ec.isFlushing()) {
// When already flushing process the changes right away to make them effective during the current flush
relationshipManager.process();
}
}
if (ec.isFlushing()) {
elementOP.flush();
}
}
return oldOwner != newOwner;
}
// 1-N unidir so update the FK if not set to be contained in the set
boolean contained = contains(ownerOP, element);
return (contained ? false : updateElementFk(ownerOP, element, newOwner));
}
use of org.datanucleus.state.ObjectProvider in project datanucleus-rdbms by datanucleus.
the class FKSetStore method iterator.
/**
* Accessor for an iterator for the set.
* @param ownerOP ObjectProvider for the owner.
* @return Iterator for the set.
*/
public Iterator<E> iterator(ObjectProvider ownerOP) {
ExecutionContext ec = ownerOP.getExecutionContext();
if (elementInfo == null || elementInfo.length == 0) {
return null;
}
// Generate the statement, and statement mapping/parameter information
IteratorStatement iterStmt = getIteratorStatement(ec, ec.getFetchPlan(), true);
SelectStatement sqlStmt = iterStmt.getSelectStatement();
StatementClassMapping iteratorMappingClass = iterStmt.getStatementClassMapping();
// Input parameter(s) - the owner
int inputParamNum = 1;
StatementMappingIndex ownerStmtMapIdx = new StatementMappingIndex(ownerMapping);
if (sqlStmt.getNumberOfUnions() > 0) {
// Add parameter occurrence for each union of statement
for (int j = 0; j < sqlStmt.getNumberOfUnions() + 1; j++) {
int[] paramPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < ownerMapping.getNumberOfDatastoreMappings(); k++) {
paramPositions[k] = inputParamNum++;
}
ownerStmtMapIdx.addParameterOccurrence(paramPositions);
}
} else {
int[] paramPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < ownerMapping.getNumberOfDatastoreMappings(); k++) {
paramPositions[k] = inputParamNum++;
}
ownerStmtMapIdx.addParameterOccurrence(paramPositions);
}
if (ec.getTransaction().getSerializeRead() != null && ec.getTransaction().getSerializeRead()) {
sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
}
String stmt = sqlStmt.getSQLText().toSQL();
try {
ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
SQLController sqlControl = storeMgr.getSQLController();
try {
// Create the statement
PreparedStatement ps = sqlControl.getStatementForQuery(mconn, stmt);
// Set the owner
ObjectProvider stmtOwnerOP = BackingStoreHelper.getOwnerObjectProviderForBackingStore(ownerOP);
int numParams = ownerStmtMapIdx.getNumberOfParameterOccurrences();
for (int paramInstance = 0; paramInstance < numParams; paramInstance++) {
ownerStmtMapIdx.getMapping().setObject(ec, ps, ownerStmtMapIdx.getParameterPositionsForOccurrence(paramInstance), stmtOwnerOP.getObject());
}
try {
ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, stmt, ps);
try {
ResultObjectFactory rof = null;
if (elementsAreEmbedded || elementsAreSerialised) {
throw new NucleusException("Cannot have FK set with non-persistent objects");
}
rof = new PersistentClassROF(ec, rs, false, iteratorMappingClass, elementCmd, clr.classForName(elementType));
return new CollectionStoreIterator(ownerOP, rs, rof, this);
} finally {
rs.close();
}
} finally {
sqlControl.closeStatement(mconn, ps);
}
} finally {
mconn.release();
}
} catch (SQLException | MappedDatastoreException e) {
throw new NucleusDataStoreException(Localiser.msg("056006", stmt), e);
}
}
use of org.datanucleus.state.ObjectProvider in project datanucleus-rdbms by datanucleus.
the class FKSetStore method remove.
/**
* Method to remove the link to the collection object specified.
* Depending on the column characteristics in the collection table, the id of the owner field may
* be NULLed, or the record may be deleted completely (as per cascade-delete in EJB).
* @param ownerOP ObjectProvider for the owner.
* @param element The element of the collection to be deleted.
* @param allowDependentField Whether to allow any cascade deletes caused by this removal
* @return A success indicator.
*/
public boolean remove(ObjectProvider ownerOP, Object element, int size, boolean allowDependentField) {
if (element == null) {
return false;
}
if (!validateElementForReading(ownerOP, element)) {
return false;
}
// Find the ObjectProvider for the element
Object elementToRemove = element;
ExecutionContext ec = ownerOP.getExecutionContext();
if (// User passed in detached object to collection.remove()!
ec.getApiAdapter().isDetached(element)) {
// Find an attached equivalent of this detached object (DON'T attach the object itself)
elementToRemove = ec.findObject(ec.getApiAdapter().getIdForObject(element), true, false, element.getClass().getName());
}
ObjectProvider elementOP = ec.findObjectProvider(elementToRemove);
Object oldOwner = null;
if (ownerMemberMetaData.getMappedBy() != null) {
if (!ec.getApiAdapter().isDeleted(elementToRemove)) {
// Find the existing owner if the record hasn't already been deleted
ObjectProvider ownerHolderOP = elementOP;
int ownerFieldNumberInHolder = -1;
if (ownerMemberMetaData.getMappedBy().indexOf('.') > 0) {
AbstractMemberMetaData otherMmd = null;
AbstractClassMetaData otherCmd = elementOP.getClassMetaData();
String remainingMappedBy = ownerMemberMetaData.getMappedBy();
while (remainingMappedBy.indexOf('.') > 0) {
int dotPosition = remainingMappedBy.indexOf('.');
String thisMappedBy = remainingMappedBy.substring(0, dotPosition);
otherMmd = otherCmd.getMetaDataForMember(thisMappedBy);
Object holderValueAtField = ownerHolderOP.provideField(otherMmd.getAbsoluteFieldNumber());
ownerHolderOP = ec.findObjectProviderForEmbedded(holderValueAtField, ownerHolderOP, otherMmd);
remainingMappedBy = remainingMappedBy.substring(dotPosition + 1);
otherCmd = storeMgr.getMetaDataManager().getMetaDataForClass(otherMmd.getTypeName(), clr);
if (remainingMappedBy.indexOf('.') < 0) {
otherMmd = otherCmd.getMetaDataForMember(remainingMappedBy);
ownerFieldNumberInHolder = otherMmd.getAbsoluteFieldNumber();
}
}
} else {
ownerFieldNumberInHolder = elementOP.getClassMetaData().getAbsolutePositionOfMember(ownerMemberMetaData.getMappedBy());
}
ownerHolderOP.isLoaded(ownerFieldNumberInHolder);
oldOwner = ownerHolderOP.provideField(ownerFieldNumberInHolder);
}
} else {
// TODO Check if the element is managed by a different owner now
}
// Owner of the element has been changed
if (ownerMemberMetaData.getMappedBy() != null && oldOwner != ownerOP.getObject() && oldOwner != null) {
return false;
}
boolean deleteElement = checkRemovalOfElementShouldDelete(ownerOP);
if (deleteElement) {
if (ec.getApiAdapter().isPersistable(elementToRemove) && ec.getApiAdapter().isDeleted(elementToRemove)) {
// Element is waiting to be deleted so flush it (it has the FK)
elementOP.flush();
} else {
// Element not yet marked for deletion so go through the normal process
ec.deleteObjectInternal(elementToRemove);
}
} else {
// Perform any necessary "managed relationships" updates on the element (when bidirectional)
manageRemovalOfElement(ownerOP, elementToRemove);
// Update the datastore FK
updateElementFk(ownerOP, elementToRemove, null);
}
return true;
}
use of org.datanucleus.state.ObjectProvider in project datanucleus-rdbms by datanucleus.
the class FKSetStore method manageRemovalOfElement.
/**
* Convenience method to manage the removal of an element from the collection, performing
* any necessary "managed relationship" updates when the field is bidirectional.
* @param ownerOP ObjectProvider for the owner.
* @param element The element
*/
protected void manageRemovalOfElement(ObjectProvider ownerOP, Object element) {
ExecutionContext ec = ownerOP.getExecutionContext();
if (relationType == RelationType.ONE_TO_MANY_BI) {
// Managed Relations : 1-N bidirectional so null the owner on the elements
if (!ec.getApiAdapter().isDeleted(element)) {
ObjectProvider elementOP = ec.findObjectProvider(element);
if (elementOP != null) {
// Null the owner of the element
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("055010", ownerOP.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(element)));
}
ObjectProvider ownerHolderOP = elementOP;
int ownerFieldNumberInHolder = -1;
if (ownerMemberMetaData.getMappedBy() != null && ownerMemberMetaData.getMappedBy().indexOf('.') > 0) {
AbstractMemberMetaData otherMmd = null;
AbstractClassMetaData otherCmd = elementCmd;
String remainingMappedBy = ownerMemberMetaData.getMappedBy();
while (remainingMappedBy.indexOf('.') > 0) {
int dotPosition = remainingMappedBy.indexOf('.');
String thisMappedBy = remainingMappedBy.substring(0, dotPosition);
otherMmd = otherCmd.getMetaDataForMember(thisMappedBy);
Object holderValueAtField = ownerHolderOP.provideField(otherMmd.getAbsoluteFieldNumber());
ownerHolderOP = ec.findObjectProviderForEmbedded(holderValueAtField, ownerHolderOP, otherMmd);
remainingMappedBy = remainingMappedBy.substring(dotPosition + 1);
otherCmd = storeMgr.getMetaDataManager().getMetaDataForClass(otherMmd.getTypeName(), clr);
if (remainingMappedBy.indexOf('.') < 0) {
otherMmd = otherCmd.getMetaDataForMember(remainingMappedBy);
ownerFieldNumberInHolder = otherMmd.getAbsoluteFieldNumber();
}
}
} else {
ownerFieldNumberInHolder = getFieldNumberInElementForBidirectional(elementOP);
}
Object currentValue = ownerHolderOP.provideField(ownerFieldNumberInHolder);
if (currentValue != null) {
ownerHolderOP.replaceFieldMakeDirty(ownerFieldNumberInHolder, null);
if (ec.isFlushing()) {
// Make sure this change gets flushed
ownerHolderOP.flush();
}
}
}
}
}
}
use of org.datanucleus.state.ObjectProvider in project datanucleus-rdbms by datanucleus.
the class JoinArrayStore method iterator.
/**
* Method to return an iterator to the array.
* @param ownerOP ObjectProvider for the owner of the array
*/
public Iterator<E> iterator(ObjectProvider ownerOP) {
ExecutionContext ec = ownerOP.getExecutionContext();
// Generate the statement, and statement mapping/parameter information
IteratorStatement iterStmt = getIteratorStatement(ec, ec.getFetchPlan(), true);
SelectStatement sqlStmt = iterStmt.sqlStmt;
StatementClassMapping iteratorMappingClass = iterStmt.stmtClassMapping;
// Input parameter(s) - the owner
int inputParamNum = 1;
StatementMappingIndex ownerIdx = new StatementMappingIndex(ownerMapping);
if (sqlStmt.getNumberOfUnions() > 0) {
// Add parameter occurrence for each union of statement
for (int j = 0; j < sqlStmt.getNumberOfUnions() + 1; j++) {
int[] paramPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < paramPositions.length; k++) {
paramPositions[k] = inputParamNum++;
}
ownerIdx.addParameterOccurrence(paramPositions);
}
} else {
int[] paramPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < paramPositions.length; k++) {
paramPositions[k] = inputParamNum++;
}
ownerIdx.addParameterOccurrence(paramPositions);
}
StatementParameterMapping iteratorMappingParams = new StatementParameterMapping();
iteratorMappingParams.addMappingForParameter("owner", ownerIdx);
if (ec.getTransaction().getSerializeRead() != null && ec.getTransaction().getSerializeRead()) {
sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
}
String stmt = sqlStmt.getSQLText().toSQL();
try {
ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
SQLController sqlControl = storeMgr.getSQLController();
try {
// Create the statement
PreparedStatement ps = sqlControl.getStatementForQuery(mconn, stmt);
// Set the owner
ObjectProvider stmtOwnerOP = BackingStoreHelper.getOwnerObjectProviderForBackingStore(ownerOP);
int numParams = ownerIdx.getNumberOfParameterOccurrences();
for (int paramInstance = 0; paramInstance < numParams; paramInstance++) {
ownerIdx.getMapping().setObject(ec, ps, ownerIdx.getParameterPositionsForOccurrence(paramInstance), stmtOwnerOP.getObject());
}
try {
ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, stmt, ps);
try {
if (elementsAreEmbedded || elementsAreSerialised) {
// No ResultObjectFactory needed - handled by SetStoreIterator
return new ArrayStoreIterator(ownerOP, rs, null, this);
} else if (elementMapping instanceof ReferenceMapping) {
// No ResultObjectFactory needed - handled by SetStoreIterator
return new ArrayStoreIterator(ownerOP, rs, null, this);
} else {
ResultObjectFactory rof = new PersistentClassROF(ec, rs, false, iteratorMappingClass, elementCmd, clr.classForName(elementType));
return new ArrayStoreIterator(ownerOP, rs, rof, this);
}
} finally {
rs.close();
}
} finally {
sqlControl.closeStatement(mconn, ps);
}
} finally {
mconn.release();
}
} catch (SQLException | MappedDatastoreException e) {
throw new NucleusDataStoreException(Localiser.msg("056006", stmt), e);
}
}
Aggregations