use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.
the class FKListStore method validateElementForWriting.
/**
* Method to validate that an element is valid for writing to the datastore.
* TODO Minimise differences to super.validateElementForWriting()
* @param ownerSM StateManager for the List owner
* @param element The element to validate
* @param index The position that the element is being stored at in the list
* @return Whether the element was inserted
*/
protected boolean validateElementForWriting(final DNStateManager ownerSM, final Object element, final int index) {
final Object newOwner = ownerSM.getObject();
ComponentInfo info = getComponentInfoForElement(element);
final DatastoreClass elementTable = storeMgr.getNucleusContext().getMetaDataManager().isPersistentInterface(elementType) ? storeMgr.getDatastoreClass(storeMgr.getNucleusContext().getMetaDataManager().getImplementationNameForPersistentInterface(elementType), clr) : storeMgr.getDatastoreClass(element.getClass().getName(), clr);
final JavaTypeMapping orderMapping = (info != null) ? info.getDatastoreClass().getExternalMapping(ownerMemberMetaData, MappingType.EXTERNAL_INDEX) : this.orderMapping;
// Check if element is ok for use in the datastore, specifying any external mappings that may be required
boolean inserted = super.validateElementForWriting(ownerSM.getExecutionContext(), element, new FieldValues() {
public void fetchFields(DNStateManager elemOP) {
// Find the (element) table storing the FK back to the owner
if (elementTable != null) {
JavaTypeMapping externalFKMapping = elementTable.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
elemOP.setAssociatedValue(externalFKMapping, ownerSM.getObject());
}
if (relationDiscriminatorMapping != null) {
elemOP.setAssociatedValue(relationDiscriminatorMapping, relationDiscriminatorValue);
}
if (orderMapping != null && index >= 0) {
if (ownerMemberMetaData.getOrderMetaData() != null && ownerMemberMetaData.getOrderMetaData().getMappedBy() != null) {
// Order is stored in a field in the element so update it
// We support mapped-by fields of types int/long/Integer/Long currently
Object indexValue = null;
if (orderMapping.getMemberMetaData().getTypeName().equals(ClassNameConstants.JAVA_LANG_LONG) || orderMapping.getMemberMetaData().getTypeName().equals(ClassNameConstants.LONG)) {
indexValue = Long.valueOf(index);
} else {
indexValue = Integer.valueOf(index);
}
elemOP.replaceFieldMakeDirty(orderMapping.getMemberMetaData().getAbsoluteFieldNumber(), indexValue);
} else {
// Order is stored in a surrogate column so save its vaue for the element to use later
elemOP.setAssociatedValue(orderMapping, Integer.valueOf(index));
}
}
}
if (ownerMemberMetaData.getMappedBy() != null) {
// TODO This is ManagedRelations - move into RelationshipManager
// Managed Relations : 1-N bidir, so make sure owner is correct at persist
// TODO Support DOT notation in mappedBy
DNStateManager ownerHolderSM = elemOP;
int ownerFieldNumberInHolder = -1;
if (ownerMemberMetaData.getMappedBy().indexOf('.') > 0) {
AbstractMemberMetaData otherMmd = null;
AbstractClassMetaData otherCmd = info.getAbstractClassMetaData();
String remainingMappedBy = ownerMemberMetaData.getMappedBy();
while (remainingMappedBy.indexOf('.') > 0) {
// JPA mappedBy dot notation
int dotPosition = remainingMappedBy.indexOf('.');
String thisMappedBy = remainingMappedBy.substring(0, dotPosition);
otherMmd = otherCmd.getMetaDataForMember(thisMappedBy);
Object holderValueAtField = ownerHolderSM.provideField(otherMmd.getAbsoluteFieldNumber());
ownerHolderSM = ownerSM.getExecutionContext().findStateManagerForEmbedded(holderValueAtField, ownerHolderSM, otherMmd, PersistableObjectType.EMBEDDED_COLLECTION_ELEMENT_PC);
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 = info.getAbstractClassMetaData().getAbsolutePositionOfMember(ownerMemberMetaData.getMappedBy());
}
Object currentOwner = ownerHolderSM.provideField(ownerFieldNumberInHolder);
if (currentOwner == null) {
// No owner, so correct it
NucleusLogger.PERSISTENCE.info(Localiser.msg("056037", ownerSM.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(ownerHolderSM.getObject())));
ownerHolderSM.replaceFieldMakeDirty(ownerFieldNumberInHolder, newOwner);
} else if (currentOwner != newOwner && ownerSM.getReferencedPC() == null) {
// Inconsistent owner, so throw exception
throw new NucleusUserException(Localiser.msg("056038", ownerSM.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(ownerHolderSM.getObject()), StringUtils.toJVMIDString(currentOwner)));
}
}
}
public void fetchNonLoadedFields(DNStateManager sm) {
}
public FetchPlan getFetchPlanForLoading() {
return null;
}
});
return inserted;
}
use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.
the class FKSetStore method add.
@Override
public boolean add(final DNStateManager ownerSM, 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 = ownerSM.getObject();
final ExecutionContext ec = ownerSM.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(DNStateManager 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, ownerSM.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", ownerSM.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 (ownerSM.getReferencedPC() == null) {
// Not being attached so must be inconsistent owner, so throw exception
throw new NucleusUserException(Localiser.msg("056038", ownerSM.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(elementOP.getObject()), StringUtils.toJVMIDString(currentOwner)));
}
}
}
}
public void fetchNonLoadedFields(DNStateManager sm) {
}
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
DNStateManager elementSM = ec.findStateManager(element);
if (elementSM == 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) {
elementSM = ec.findStateManager(element);
}
}
}
int fieldNumInElement = getFieldNumberInElementForBidirectional(elementSM);
if (fieldNumInElement >= 0 && elementSM != null) {
// Managed Relations : 1-N bidir, so update the owner of the element
// Ensure is loaded
elementSM.isLoaded(fieldNumInElement);
Object oldOwner = elementSM.provideField(fieldNumInElement);
if (oldOwner != newOwner) {
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("055009", ownerSM.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(element)));
}
elementSM.replaceFieldMakeDirty(fieldNumInElement, newOwner);
if (ec.getManageRelations()) {
// Managed Relationships - add the change we've made here to be analysed at flush
RelationshipManager relationshipManager = ec.getRelationshipManager(elementSM);
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()) {
elementSM.flush();
}
}
return oldOwner != newOwner;
}
// 1-N unidir so update the FK if not set to be contained in the set
boolean contained = contains(ownerSM, element);
return (contained ? false : updateElementFk(ownerSM, element, newOwner));
}
use of org.datanucleus.state.DNStateManager 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 ownerSM StateManager for the owner.
* @param element The element
*/
protected void manageRemovalOfElement(DNStateManager ownerSM, Object element) {
ExecutionContext ec = ownerSM.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)) {
DNStateManager elementSM = ec.findStateManager(element);
if (elementSM != null) {
// Null the owner of the element
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("055010", ownerSM.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(element)));
}
DNStateManager ownerHolderSM = elementSM;
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) {
// JPA mappedBy dot notation
int dotPosition = remainingMappedBy.indexOf('.');
String thisMappedBy = remainingMappedBy.substring(0, dotPosition);
otherMmd = otherCmd.getMetaDataForMember(thisMappedBy);
Object holderValueAtField = ownerHolderSM.provideField(otherMmd.getAbsoluteFieldNumber());
ownerHolderSM = ec.findStateManagerForEmbedded(holderValueAtField, ownerHolderSM, otherMmd, PersistableObjectType.EMBEDDED_COLLECTION_ELEMENT_PC);
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(elementSM);
}
Object currentValue = ownerHolderSM.provideField(ownerFieldNumberInHolder);
if (currentValue != null) {
ownerHolderSM.replaceFieldMakeDirty(ownerFieldNumberInHolder, null);
if (ec.isFlushing()) {
// Make sure this change gets flushed
ownerHolderSM.flush();
}
}
}
}
}
}
use of org.datanucleus.state.DNStateManager 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 ownerSM StateManager 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
* @param size Not used
* @return A success indicator.
*/
@Override
public boolean remove(DNStateManager ownerSM, Object element, int size, boolean allowDependentField) {
if (element == null) {
return false;
}
if (!validateElementForReading(ownerSM, element)) {
return false;
}
// Find StateManager for the element
Object elementToRemove = element;
ExecutionContext ec = ownerSM.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());
}
DNStateManager elementSM = ec.findStateManager(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
DNStateManager ownerHolderSM = elementSM;
int ownerFieldNumberInHolder = -1;
if (ownerMemberMetaData.getMappedBy().indexOf('.') > 0) {
AbstractMemberMetaData otherMmd = null;
AbstractClassMetaData otherCmd = elementSM.getClassMetaData();
String remainingMappedBy = ownerMemberMetaData.getMappedBy();
while (remainingMappedBy.indexOf('.') > 0) {
// JPA mappedBy dot notation
int dotPosition = remainingMappedBy.indexOf('.');
String thisMappedBy = remainingMappedBy.substring(0, dotPosition);
otherMmd = otherCmd.getMetaDataForMember(thisMappedBy);
Object holderValueAtField = ownerHolderSM.provideField(otherMmd.getAbsoluteFieldNumber());
ownerHolderSM = ec.findStateManagerForEmbedded(holderValueAtField, ownerHolderSM, otherMmd, PersistableObjectType.EMBEDDED_COLLECTION_ELEMENT_PC);
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 = elementSM.getClassMetaData().getAbsolutePositionOfMember(ownerMemberMetaData.getMappedBy());
}
ownerHolderSM.isLoaded(ownerFieldNumberInHolder);
oldOwner = ownerHolderSM.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 != ownerSM.getObject() && oldOwner != null) {
return false;
}
boolean deleteElement = checkRemovalOfElementShouldDelete(ownerSM);
if (deleteElement) {
if (ec.getApiAdapter().isPersistable(elementToRemove) && ec.getApiAdapter().isDeleted(elementToRemove)) {
// Element is waiting to be deleted so flush it (it has the FK)
elementSM.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(ownerSM, elementToRemove);
// Update the datastore FK
updateElementFk(ownerSM, elementToRemove, null);
}
return true;
}
use of org.datanucleus.state.DNStateManager in project datanucleus-rdbms by datanucleus.
the class BackingStoreHelper method populateEmbeddedKeyFieldsInStatement.
/**
* Convenience method to populate the passed PreparedStatement with the field values from
* the embedded map key starting at the specified jdbc position.
* @param sm StateManager of the owning container
* @param key The embedded key
* @param ps The PreparedStatement
* @param jdbcPosition JDBC position in the statement to start at
* @param joinTable The Join table where the values are embedded
* @param mapStore the map store
* @return The next JDBC position
*/
public static int populateEmbeddedKeyFieldsInStatement(DNStateManager sm, Object key, PreparedStatement ps, int jdbcPosition, JoinTable joinTable, AbstractMapStore mapStore) {
AbstractClassMetaData kmd = mapStore.getKeyClassMetaData();
EmbeddedKeyPCMapping embeddedMapping = (EmbeddedKeyPCMapping) mapStore.getKeyMapping();
StatementClassMapping mappingDefinition = new StatementClassMapping();
int[] elementFieldNumbers = new int[embeddedMapping.getNumberOfJavaTypeMappings()];
for (int i = 0; i < embeddedMapping.getNumberOfJavaTypeMappings(); i++) {
JavaTypeMapping fieldMapping = embeddedMapping.getJavaTypeMapping(i);
int absFieldNum = kmd.getAbsolutePositionOfMember(fieldMapping.getMemberMetaData().getName());
elementFieldNumbers[i] = absFieldNum;
StatementMappingIndex stmtMapping = new StatementMappingIndex(fieldMapping);
int[] jdbcParamPositions = new int[fieldMapping.getNumberOfColumnMappings()];
for (int j = 0; j < fieldMapping.getNumberOfColumnMappings(); j++) {
jdbcParamPositions[j] = jdbcPosition++;
}
stmtMapping.addParameterOccurrence(jdbcParamPositions);
mappingDefinition.addMappingForMember(absFieldNum, stmtMapping);
}
DNStateManager elementSM = mapStore.getStateManagerForEmbeddedPCObject(sm, key, joinTable.getOwnerMemberMetaData(), PersistableObjectType.EMBEDDED_MAP_KEY_PC);
elementSM.provideFields(elementFieldNumbers, new ParameterSetter(elementSM, ps, mappingDefinition));
return jdbcPosition;
}
Aggregations