use of org.datanucleus.metadata.AbstractMemberMetaData in project datanucleus-core by datanucleus.
the class CopyKeyFieldsFromObjectId method execute.
/**
* Method to add the contents of the class method.
*/
public void execute() {
visitor.visitCode();
ClassMetaData cmd = enhancer.getClassMetaData();
if (cmd.getIdentityType() == IdentityType.APPLICATION) {
// application identity
if (!cmd.isInstantiable()) {
// Application identity but mapped-superclass with no PK defined, so just "return"
Label startLabel = new Label();
visitor.visitLabel(startLabel);
visitor.visitInsn(Opcodes.RETURN);
Label endLabel = new Label();
visitor.visitLabel(endLabel);
visitor.visitLocalVariable("this", getClassEnhancer().getClassDescriptor(), null, startLabel, endLabel, 0);
visitor.visitLocalVariable(argNames[0], getNamer().getObjectIdFieldConsumerDescriptor(), null, startLabel, endLabel, 1);
visitor.visitLocalVariable(argNames[1], EnhanceUtils.CD_Object, null, startLabel, endLabel, 2);
visitor.visitMaxs(0, 3);
} else {
int[] pkFieldNums = cmd.getPKMemberPositions();
String objectIdClass = cmd.getObjectidClass();
String ACN_objectIdClass = objectIdClass.replace('.', '/');
if (IdentityUtils.isSingleFieldIdentityClass(objectIdClass)) {
// SingleFieldIdentity
Label startLabel = new Label();
visitor.visitLabel(startLabel);
// if (fc == null) throw new IllegalArgumentException("...");
visitor.visitVarInsn(Opcodes.ALOAD, 1);
Label l1 = new Label();
visitor.visitJumpInsn(Opcodes.IFNONNULL, l1);
visitor.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalArgumentException");
visitor.visitInsn(Opcodes.DUP);
visitor.visitLdcInsn("ObjectIdFieldConsumer is null");
visitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V");
visitor.visitInsn(Opcodes.ATHROW);
// if (!(oid instanceof LongIdentity)) throw new ClassCastException("...");
visitor.visitLabel(l1);
visitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
visitor.visitVarInsn(Opcodes.ALOAD, 2);
visitor.visitTypeInsn(Opcodes.INSTANCEOF, ACN_objectIdClass);
Label l5 = new Label();
visitor.visitJumpInsn(Opcodes.IFNE, l5);
visitor.visitTypeInsn(Opcodes.NEW, "java/lang/ClassCastException");
visitor.visitInsn(Opcodes.DUP);
visitor.visitLdcInsn("oid is not instanceof " + objectIdClass);
visitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/ClassCastException", "<init>", "(Ljava/lang/String;)V");
visitor.visitInsn(Opcodes.ATHROW);
// XXXIdentity o = (XXXIdentity) oid;
visitor.visitLabel(l5);
visitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
visitor.visitVarInsn(Opcodes.ALOAD, 2);
visitor.visitTypeInsn(Opcodes.CHECKCAST, ACN_objectIdClass);
visitor.visitVarInsn(Opcodes.ASTORE, 3);
// fc.storeXXXField(1, o.getKey());
Label l9 = new Label();
visitor.visitLabel(l9);
visitor.visitVarInsn(Opcodes.ALOAD, 1);
EnhanceUtils.addBIPUSHToMethod(visitor, pkFieldNums[0]);
AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(pkFieldNums[0]);
Class primitiveType = ClassUtils.getPrimitiveTypeForType(fmd.getType());
if (primitiveType != null) {
// The PK field is a primitive wrapper so create wrapper from getKey()
String ACN_fieldType = fmd.getTypeName().replace('.', '/');
String getKeyReturnDesc = Type.getDescriptor(primitiveType);
visitor.visitVarInsn(Opcodes.ALOAD, 3);
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ACN_objectIdClass, "getKey", "()" + getKeyReturnDesc);
visitor.visitMethodInsn(Opcodes.INVOKESTATIC, ACN_fieldType, "valueOf", "(" + getKeyReturnDesc + ")L" + ACN_fieldType + ";");
visitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, getNamer().getObjectIdFieldConsumerAsmClassName(), "storeObjectField", "(I" + EnhanceUtils.CD_Object + ")V");
} else {
// PK field isn't a primitive wrapper
visitor.visitVarInsn(Opcodes.ALOAD, 3);
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ACN_objectIdClass, "getKey", "()" + getNamer().getTypeDescriptorForSingleFieldIdentityGetKey(objectIdClass));
visitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, getNamer().getObjectIdFieldConsumerAsmClassName(), "store" + getNamer().getTypeNameForUseWithSingleFieldIdentity(objectIdClass) + "Field", "(I" + getNamer().getTypeDescriptorForSingleFieldIdentityGetKey(objectIdClass) + ")V");
}
visitor.visitInsn(Opcodes.RETURN);
Label endLabel = new Label();
visitor.visitLabel(endLabel);
visitor.visitLocalVariable("this", getClassEnhancer().getClassDescriptor(), null, startLabel, endLabel, 0);
visitor.visitLocalVariable(argNames[0], getNamer().getObjectIdFieldConsumerDescriptor(), null, startLabel, endLabel, 1);
visitor.visitLocalVariable(argNames[1], EnhanceUtils.CD_Object, null, startLabel, endLabel, 2);
visitor.visitLocalVariable("o", getNamer().getSingleFieldIdentityDescriptor(objectIdClass), null, l9, endLabel, 3);
visitor.visitMaxs(3, 4);
} else {
// User-provided app identity, and compound identity
// Put try-catch around the field setting (for reflection cases)
Label l0 = new Label();
Label l1 = new Label();
Label l2 = new Label();
visitor.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception");
Label startLabel = new Label();
visitor.visitLabel(startLabel);
visitor.visitVarInsn(Opcodes.ALOAD, 1);
Label l4 = new Label();
visitor.visitJumpInsn(Opcodes.IFNONNULL, l4);
visitor.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalArgumentException");
visitor.visitInsn(Opcodes.DUP);
visitor.visitLdcInsn("ObjectIdFieldConsumer is null");
visitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V");
visitor.visitInsn(Opcodes.ATHROW);
visitor.visitLabel(l4);
visitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
visitor.visitVarInsn(Opcodes.ALOAD, 2);
visitor.visitTypeInsn(Opcodes.INSTANCEOF, ACN_objectIdClass);
Label l5 = new Label();
visitor.visitJumpInsn(Opcodes.IFNE, l5);
visitor.visitTypeInsn(Opcodes.NEW, "java/lang/ClassCastException");
visitor.visitInsn(Opcodes.DUP);
visitor.visitLdcInsn("oid is not instanceof " + objectIdClass);
visitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/ClassCastException", "<init>", "(Ljava/lang/String;)V");
visitor.visitInsn(Opcodes.ATHROW);
visitor.visitLabel(l5);
visitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
visitor.visitVarInsn(Opcodes.ALOAD, 2);
visitor.visitTypeInsn(Opcodes.CHECKCAST, ACN_objectIdClass);
visitor.visitVarInsn(Opcodes.ASTORE, 3);
visitor.visitLabel(l0);
// Copy the PK members using the appropriate method for each field/property
Label reflectionFieldStart = null;
for (int i = 0; i < pkFieldNums.length; i++) {
AbstractMemberMetaData fmd = enhancer.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(pkFieldNums[i]);
String fieldTypeDesc = Type.getDescriptor(fmd.getType());
String typeMethodName = EnhanceUtils.getTypeNameForPersistableMethod(fmd.getType());
int pkFieldModifiers = ClassUtils.getModifiersForFieldOfClass(enhancer.getClassLoaderResolver(), objectIdClass, fmd.getName());
// Check if the PK field type is a PC (CompoundIdentity)
AbstractClassMetaData acmd = enhancer.getMetaDataManager().getMetaDataForClass(fmd.getType(), enhancer.getClassLoaderResolver());
if (acmd != null && acmd.getIdentityType() != IdentityType.NONDURABLE) {
// CompoundIdentity, this field of the PK is a PC
visitor.visitVarInsn(Opcodes.ALOAD, 1);
EnhanceUtils.addBIPUSHToMethod(visitor, fmd.getFieldId());
visitor.visitVarInsn(Opcodes.ALOAD, 0);
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getClassEnhancer().getASMClassName(), getNamer().getGetExecutionContextMethodName(), "()L" + getNamer().getExecutionContextAsmClassName() + ";");
visitor.visitVarInsn(Opcodes.ALOAD, 3);
// TODO Cater for property, or private field cases
visitor.visitFieldInsn(Opcodes.GETFIELD, ACN_objectIdClass, fmd.getName(), "L" + acmd.getObjectidClass().replace('.', '/') + ";");
visitor.visitInsn(Opcodes.ICONST_0);
visitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, getNamer().getExecutionContextAsmClassName(), "findObject", "(Ljava/lang/Object;Z)Ljava/lang/Object;");
visitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, getNamer().getObjectIdFieldConsumerAsmClassName(), "storeObjectField", "(ILjava/lang/Object;)V");
} else {
// Standard application-identity
if (fmd instanceof PropertyMetaData) {
// Field in PK is property, hence use getXXX in PK
visitor.visitVarInsn(Opcodes.ALOAD, 1);
EnhanceUtils.addBIPUSHToMethod(visitor, fmd.getFieldId());
visitor.visitVarInsn(Opcodes.ALOAD, 3);
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ACN_objectIdClass, ClassUtils.getJavaBeanGetterName(fmd.getName(), fmd.getTypeName().equals("boolean")), "()" + Type.getDescriptor(fmd.getType()));
visitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, getNamer().getObjectIdFieldConsumerAsmClassName(), "store" + typeMethodName + "Field", "(I" + EnhanceUtils.getTypeDescriptorForEnhanceMethod(fmd.getType()) + ")V");
} else if (Modifier.isPublic(pkFieldModifiers)) {
// Field in PK is public so access directly
visitor.visitVarInsn(Opcodes.ALOAD, 1);
EnhanceUtils.addBIPUSHToMethod(visitor, fmd.getFieldId());
visitor.visitVarInsn(Opcodes.ALOAD, 3);
visitor.visitFieldInsn(Opcodes.GETFIELD, ACN_objectIdClass, fmd.getName(), fieldTypeDesc);
visitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, getNamer().getObjectIdFieldConsumerAsmClassName(), "store" + typeMethodName + "Field", "(I" + EnhanceUtils.getTypeDescriptorForEnhanceMethod(fmd.getType()) + ")V");
} else {
// Field in PK is protected/private so use reflection, generating
// "Field field = o.getClass().getDeclaredField("pmIDFloat");"
// "field.setAccessible(true);"
// "fc.storeObjectField(1, field.get(o));"
visitor.visitVarInsn(Opcodes.ALOAD, 3);
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
visitor.visitLdcInsn(fmd.getName());
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;");
visitor.visitVarInsn(Opcodes.ASTORE, 4);
if (reflectionFieldStart == null) {
reflectionFieldStart = new Label();
visitor.visitLabel(reflectionFieldStart);
}
visitor.visitVarInsn(Opcodes.ALOAD, 4);
visitor.visitInsn(Opcodes.ICONST_1);
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "setAccessible", "(Z)V");
visitor.visitVarInsn(Opcodes.ALOAD, 1);
EnhanceUtils.addBIPUSHToMethod(visitor, fmd.getFieldId());
visitor.visitVarInsn(Opcodes.ALOAD, 4);
visitor.visitVarInsn(Opcodes.ALOAD, 3);
if (fmd.getTypeName().equals("boolean")) {
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getBoolean", "(Ljava/lang/Object;)Z");
} else if (fmd.getTypeName().equals("byte")) {
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getByte", "(Ljava/lang/Object;)B");
} else if (fmd.getTypeName().equals("char")) {
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getChar", "(Ljava/lang/Object;)C");
} else if (fmd.getTypeName().equals("double")) {
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getDouble", "(Ljava/lang/Object;)D");
} else if (fmd.getTypeName().equals("float")) {
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getFloat", "(Ljava/lang/Object;)F");
} else if (fmd.getTypeName().equals("int")) {
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getInt", "(Ljava/lang/Object;)I");
} else if (fmd.getTypeName().equals("long")) {
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getLong", "(Ljava/lang/Object;)L");
} else if (fmd.getTypeName().equals("short")) {
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "getShort", "(Ljava/lang/Object;)S");
} else if (fmd.getTypeName().equals("java.lang.String")) {
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
visitor.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
} else {
visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Field", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
}
visitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, getNamer().getObjectIdFieldConsumerAsmClassName(), "store" + typeMethodName + "Field", "(I" + EnhanceUtils.getTypeDescriptorForEnhanceMethod(fmd.getType()) + ")V");
}
}
}
// catch of the try-catch
visitor.visitLabel(l1);
Label l20 = new Label();
visitor.visitJumpInsn(Opcodes.GOTO, l20);
visitor.visitLabel(l2);
visitor.visitFrame(Opcodes.F_FULL, 4, new Object[] { getClassEnhancer().getASMClassName(), getClassEnhancer().getNamer().getObjectIdFieldConsumerAsmClassName(), "java/lang/Object", ACN_objectIdClass }, 1, new Object[] { "java/lang/Exception" });
visitor.visitVarInsn(Opcodes.ASTORE, 4);
visitor.visitLabel(l20);
visitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
visitor.visitInsn(Opcodes.RETURN);
Label endLabel = new Label();
visitor.visitLabel(endLabel);
visitor.visitLocalVariable("this", getClassEnhancer().getClassDescriptor(), null, startLabel, endLabel, 0);
visitor.visitLocalVariable(argNames[0], getNamer().getObjectIdFieldConsumerDescriptor(), null, startLabel, endLabel, 1);
visitor.visitLocalVariable(argNames[1], EnhanceUtils.CD_Object, null, startLabel, endLabel, 2);
visitor.visitLocalVariable("o", "L" + ACN_objectIdClass + ";", null, l0, endLabel, 3);
if (reflectionFieldStart != null) {
visitor.visitLocalVariable("field", "Ljava/lang/reflect/Field;", null, reflectionFieldStart, l2, 4);
visitor.visitMaxs(4, 5);
} else {
visitor.visitMaxs(4, 4);
}
}
}
} else {
// datastore/nondurable identity
Label startLabel = new Label();
visitor.visitLabel(startLabel);
visitor.visitInsn(Opcodes.RETURN);
Label endLabel = new Label();
visitor.visitLabel(endLabel);
visitor.visitLocalVariable("this", getClassEnhancer().getClassDescriptor(), null, startLabel, endLabel, 0);
visitor.visitLocalVariable(argNames[0], "L" + getNamer().getObjectIdFieldConsumerAsmClassName() + ";", null, startLabel, endLabel, 1);
visitor.visitLocalVariable(argNames[1], EnhanceUtils.CD_Object, null, startLabel, endLabel, 2);
visitor.visitMaxs(0, 3);
}
visitor.visitEnd();
}
use of org.datanucleus.metadata.AbstractMemberMetaData in project datanucleus-core by datanucleus.
the class RelationshipManagerImpl method process.
/* (non-Javadoc)
* @see org.datanucleus.state.RelationshipManager#process()
*/
public void process() {
Iterator iter = fieldChanges.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<Integer, List<RelationChange>> entry = (Map.Entry) iter.next();
int fieldNumber = entry.getKey().intValue();
List<RelationChange> changes = entry.getValue();
AbstractMemberMetaData mmd = ownerOP.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
ClassLoaderResolver clr = ec.getClassLoaderResolver();
RelationType relationType = mmd.getRelationType(clr);
if (relationType == RelationType.ONE_TO_ONE_BI) {
// 1-1 bidirectional
processOneToOneBidirectionalRelation(mmd, clr, ec, changes);
} else if (relationType == RelationType.MANY_TO_ONE_BI) {
// N-1 bidirectional
processManyToOneBidirectionalRelation(mmd, clr, ec, changes);
} else if (relationType == RelationType.ONE_TO_MANY_BI) {
// 1-N bidirectional
processOneToManyBidirectionalRelation(mmd, clr, ec, changes);
} else if (relationType == RelationType.MANY_TO_MANY_BI) {
// M-N bidirectional
processManyToManyBidirectionalRelation(mmd, clr, ec, changes);
}
}
}
use of org.datanucleus.metadata.AbstractMemberMetaData in project datanucleus-core by datanucleus.
the class RelationshipManagerImpl method processManyToOneBidirectionalRelation.
/**
* Method to process all N-1 bidirectional fields.
* Processes the case where we had an N-1 field set at this side previously to some value and now to
* some other value.That is, this object was in some collection/map originally, and now should be in some
* other collection/map. So in terms of an example this object "a" was in collection "b1.as" before and is
* now in "b2.as". The following changes are likely to be necessary
* <ul>
* <li>b1.getAs().remove(a) - remove it from b1.as if still present</li>
* <li>b2.getAs().add(a) - add it to b1.as if not present</li>
* </ul>
* @param mmd MetaData for the field
* @param clr ClassLoader resolver
* @param ec ExecutionContext
* @param changes List of changes to the collection
*/
protected void processManyToOneBidirectionalRelation(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
Object newValue = ownerOP.provideField(mmd.getAbsoluteFieldNumber());
if (oldValue != null) {
// Has been removed from a Collection/Map
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, pc, oldValue);
ObjectProvider oldOP = ec.findObjectProvider(oldValue);
if (oldOP != null && relatedMmd != null && oldOP.getLoadedFields()[relatedMmd.getAbsoluteFieldNumber()]) {
if (oldOP.isFieldLoaded(relatedMmd.getAbsoluteFieldNumber())) {
Object oldContainerValue = oldOP.provideField(relatedMmd.getAbsoluteFieldNumber());
if (oldContainerValue instanceof Collection) {
Collection oldColl = (Collection) oldContainerValue;
if (oldColl.contains(pc)) {
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("013006", StringUtils.toJVMIDString(pc), mmd.getFullFieldName(), relatedMmd.getFullFieldName(), StringUtils.toJVMIDString(oldValue)));
}
if (oldColl instanceof SCOCollection) {
// Avoid any cascade deletes that could have been fired by this action
((SCOCollection) oldColl).remove(pc, false);
} else {
oldColl.remove(pc);
}
}
}
}
} else {
if (oldOP != null) {
ec.removeObjectFromLevel2Cache(oldOP.getInternalObjectId());
}
}
}
if (newValue != null) {
// Add new value to the Collection
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, pc, newValue);
ObjectProvider newOP = ec.findObjectProvider(newValue);
if (newOP != null && relatedMmd != null && newOP.getLoadedFields()[relatedMmd.getAbsoluteFieldNumber()]) {
Object newContainerValue = newOP.provideField(relatedMmd.getAbsoluteFieldNumber());
if (newContainerValue instanceof Collection) {
Collection newColl = (Collection) newContainerValue;
if (!newColl.contains(pc)) {
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("013007", StringUtils.toJVMIDString(pc), mmd.getFullFieldName(), relatedMmd.getFullFieldName(), StringUtils.toJVMIDString(newValue)));
}
newColl.add(pc);
}
}
} else {
// Relation field not loaded so evict it from the L2 cache to avoid loading old field values
ec.removeObjectFromLevel2Cache(ec.getApiAdapter().getIdForObject(newValue));
}
}
}
}
}
use of org.datanucleus.metadata.AbstractMemberMetaData in project datanucleus-core by datanucleus.
the class RelationshipManagerImpl method relationRemove.
/* (non-Javadoc)
* @see org.datanucleus.state.RelationshipManager#relationRemove(int, java.lang.Object)
*/
public void relationRemove(int fieldNumber, Object val) {
if (ec.isManagingRelations()) {
return;
}
AbstractMemberMetaData mmd = ownerOP.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
RelationType relationType = mmd.getRelationType(ec.getClassLoaderResolver());
if (relationType != RelationType.ONE_TO_MANY_BI && relationType != RelationType.MANY_TO_MANY_BI) {
return;
}
Integer fieldKey = Integer.valueOf(fieldNumber);
List<RelationChange> changeList = fieldChanges.get(fieldKey);
if (changeList == null) {
changeList = new ArrayList();
fieldChanges.put(fieldKey, changeList);
}
ec.removeObjectFromLevel2Cache(ec.getApiAdapter().getIdForObject(val));
changeList.add(new RelationChange(ChangeType.REMOVE_OBJECT, val));
}
use of org.datanucleus.metadata.AbstractMemberMetaData in project datanucleus-core by datanucleus.
the class RelationshipManagerImpl method processManyToManyBidirectionalRelation.
/**
* Method to process all M-N bidirectional fields.
* @param mmd MetaData for the field
* @param clr ClassLoader resolver
* @param ec ExecutionContext
* @param changes List of changes to the collection
*/
protected void processManyToManyBidirectionalRelation(AbstractMemberMetaData mmd, ClassLoaderResolver clr, ExecutionContext ec, List<RelationChange> changes) {
for (RelationChange change : changes) {
if (change.type != ChangeType.ADD_OBJECT && change.type != ChangeType.REMOVE_OBJECT) {
continue;
}
ObjectProvider op = ec.findObjectProvider(change.value);
if (op == null && ec.getApiAdapter().isDetached(change.value)) {
// Provided value was detached, so get its attached equivalent
Object attached = ec.getAttachedObjectForId(ec.getApiAdapter().getIdForObject(change.value));
if (attached != null) {
op = ec.findObjectProvider(attached);
}
}
if (op != null) {
if (change.type == ChangeType.ADD_OBJECT) {
// make sure the element has the owner in its collection
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaData(clr)[0];
ec.removeObjectFromLevel2Cache(op.getInternalObjectId());
ec.removeObjectFromLevel2Cache(ownerOP.getInternalObjectId());
if (ownerOP.isFieldLoaded(mmd.getAbsoluteFieldNumber()) && !ownerOP.getLifecycleState().isDeleted) {
Collection currentVal = (Collection) ownerOP.provideField(mmd.getAbsoluteFieldNumber());
if (currentVal != null && !currentVal.contains(op.getObject())) {
currentVal.add(op.getObject());
}
}
if (op.isFieldLoaded(relatedMmd.getAbsoluteFieldNumber())) {
Collection currentVal = (Collection) op.provideField(relatedMmd.getAbsoluteFieldNumber());
if (currentVal != null && !currentVal.contains(ownerOP.getObject())) {
currentVal.add(ownerOP.getObject());
}
}
} else if (change.type == ChangeType.REMOVE_OBJECT) {
// make sure the element removes the owner from its collection
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaData(clr)[0];
ec.removeObjectFromLevel2Cache(op.getInternalObjectId());
ec.removeObjectFromLevel2Cache(ownerOP.getInternalObjectId());
if (ownerOP.isFieldLoaded(mmd.getAbsoluteFieldNumber()) && !ownerOP.getLifecycleState().isDeleted) {
Collection currentVal = (Collection) ownerOP.provideField(mmd.getAbsoluteFieldNumber());
if (!op.getLifecycleState().isDeleted && currentVal != null && currentVal.contains(op.getObject())) {
currentVal.remove(op.getObject());
} else {
// element is deleted so can't call remove since it may try to read fields from it
// so just unload the collection in the owner forcing it to be reloaded from the DB
ownerOP.unloadField(mmd.getName());
}
}
if (op.isFieldLoaded(relatedMmd.getAbsoluteFieldNumber()) && !op.getLifecycleState().isDeleted) {
Collection currentVal = (Collection) op.provideField(relatedMmd.getAbsoluteFieldNumber());
if (currentVal != null && currentVal.contains(ownerOP.getObject())) {
currentVal.remove(ownerOP.getObject());
}
}
}
}
}
}
Aggregations