use of org.apache.cayenne.graph.ArcId in project cayenne by apache.
the class DataContext method registerNewObject.
/**
* Registers a transient object with the context, recursively registering
* all transient persistent objects attached to this object via
* relationships.
* <p>
* <i>Note that since 3.0 this method takes Object as an argument instead of
* a {@link DataObject}.</i>
*
* @param object
* new object that needs to be made persistent.
*/
@Override
public void registerNewObject(Object object) {
if (object == null) {
throw new NullPointerException("Can't register null object.");
}
ObjEntity entity = getEntityResolver().getObjEntity((Persistent) object);
if (entity == null) {
throw new IllegalArgumentException("Can't find ObjEntity for Persistent class: " + object.getClass().getName() + ", class is likely not mapped.");
}
final Persistent persistent = (Persistent) object;
// sanity check - maybe already registered
if (persistent.getObjectId() != null) {
if (persistent.getObjectContext() == this) {
// already registered, just ignore
return;
} else if (persistent.getObjectContext() != null) {
throw new IllegalStateException("Persistent is already registered with another DataContext. " + "Try using 'localObjects()' instead.");
}
} else {
persistent.setObjectId(ObjectId.of(entity.getName()));
}
ClassDescriptor descriptor = getEntityResolver().getClassDescriptor(entity.getName());
if (descriptor == null) {
throw new IllegalArgumentException("Invalid entity name: " + entity.getName());
}
injectInitialValue(object);
// now we need to find all arc changes, inject missing value holders and
// pull in
// all transient connected objects
descriptor.visitProperties(new PropertyVisitor() {
public boolean visitToMany(ToManyProperty property) {
property.injectValueHolder(persistent);
if (!property.isFault(persistent)) {
Object value = property.readProperty(persistent);
@SuppressWarnings("unchecked") Collection<Map.Entry> collection = (value instanceof Map) ? ((Map) value).entrySet() : (Collection) value;
for (Object target : collection) {
if (target instanceof Persistent) {
Persistent targetDO = (Persistent) target;
// make sure it is registered
registerNewObject(targetDO);
getObjectStore().arcCreated(persistent.getObjectId(), targetDO.getObjectId(), new ArcId(property));
}
}
}
return true;
}
public boolean visitToOne(ToOneProperty property) {
Object target = property.readPropertyDirectly(persistent);
if (target instanceof Persistent) {
Persistent targetDO = (Persistent) target;
// make sure it is registered
registerNewObject(targetDO);
getObjectStore().arcCreated(persistent.getObjectId(), targetDO.getObjectId(), new ArcId(property));
}
return true;
}
public boolean visitAttribute(AttributeProperty property) {
return true;
}
});
}
use of org.apache.cayenne.graph.ArcId in project cayenne by apache.
the class ObjectDiff method addDiff.
void addDiff(NodeDiff diff, ObjectStore parent) {
boolean addDiff = true;
if (diff instanceof ArcOperation) {
ArcOperation arcDiff = (ArcOperation) diff;
Object targetId = arcDiff.getTargetNodeId();
ArcId arcId = arcDiff.getArcId();
ArcProperty property = (ArcProperty) getClassDescriptor().getProperty(arcId.getForwardArc());
if (property == null && arcId.getForwardArc().startsWith(ASTDbPath.DB_PREFIX)) {
addPhantomFkDiff(arcDiff);
addDiff = false;
} else if (property instanceof ToManyProperty) {
// record flattened op changes
ObjRelationship relationship = property.getRelationship();
if (relationship.isFlattened()) {
if (flatIds == null) {
flatIds = new HashMap<>();
}
ArcOperation oldOp = flatIds.put(arcDiff, arcDiff);
// "delete" cancels "create" and vice versa...
if (oldOp != null && oldOp.isDelete() != arcDiff.isDelete()) {
addDiff = false;
flatIds.remove(arcDiff);
if (otherDiffs != null) {
otherDiffs.remove(oldOp);
}
}
} else if (property.getComplimentaryReverseArc() == null) {
// register complimentary arc diff
ArcId arc = arcId.getReverseId();
// new ArcId(ASTDbPath.DB_PREFIX + property.getComplimentaryReverseDbRelationshipPath(), property.getName());
ArcOperation complimentaryOp = new ArcOperation(targetId, arcDiff.getNodeId(), arc, arcDiff.isDelete());
parent.registerDiff(targetId, complimentaryOp);
}
} else if (property instanceof ToOneProperty) {
if (currentArcSnapshot == null) {
currentArcSnapshot = new HashMap<>();
}
currentArcSnapshot.put(arcId.getForwardArc(), targetId);
} else {
String message = (property == null) ? "No property for arcId " + arcId : "Unrecognized property for arcId " + arcId + ": " + property;
throw new CayenneRuntimeException(message);
}
}
if (addDiff) {
if (otherDiffs == null) {
otherDiffs = new ArrayList<>(3);
}
otherDiffs.add(diff);
}
}
use of org.apache.cayenne.graph.ArcId in project cayenne by apache.
the class ObjectStore method postprocessAfterCommit.
/**
* Internal unsynchronized method to process objects state after commit.
*
* @since 1.2
*/
public void postprocessAfterCommit(GraphDiff parentChanges) {
// scan through changed objects, set persistence state to committed
for (Object id : changes.keySet()) {
Persistent object = objectMap.get(id);
switch(object.getPersistenceState()) {
case PersistenceState.DELETED:
objectMap.remove(id);
object.setObjectContext(null);
object.setPersistenceState(PersistenceState.TRANSIENT);
break;
case PersistenceState.NEW:
case PersistenceState.MODIFIED:
object.setPersistenceState(PersistenceState.COMMITTED);
break;
}
}
// re-register changed object ids
if (!parentChanges.isNoop()) {
parentChanges.apply(new GraphChangeHandler() {
@Override
public void arcCreated(Object nodeId, Object targetNodeId, ArcId arcId) {
}
@Override
public void arcDeleted(Object nodeId, Object targetNodeId, ArcId arcId) {
}
@Override
public void nodeCreated(Object nodeId) {
}
@Override
public void nodeIdChanged(Object nodeId, Object newId) {
processIdChange(nodeId, newId);
}
@Override
public void nodePropertyChanged(Object nodeId, String property, Object oldValue, Object newValue) {
}
@Override
public void nodeRemoved(Object nodeId) {
}
});
}
// create new instance of changes map so that event listeners who stored the
// original diff don't get affected
this.changes = new HashMap<>();
}
use of org.apache.cayenne.graph.ArcId in project cayenne by apache.
the class NestedCayenneContextIT method testCommitChangesToParent.
@Test
public void testCommitChangesToParent() {
clientContext.newObject(ClientMtTable1.class);
clientContext.newObject(ClientMtTable1.class);
clientContext.newObject(ClientMtTable1.class);
clientContext.newObject(ClientMtTable1.class);
clientContext.commitChanges();
final ObjectContext child = runtime.newContext(clientContext);
List<ClientMtTable1> objects = ObjectSelect.query(ClientMtTable1.class).select(child);
assertEquals(4, objects.size());
final ClientMtTable1 childNew = child.newObject(ClientMtTable1.class);
childNew.setGlobalAttribute1("NNN");
final ClientMtTable1 childModified = objects.get(0);
childModified.setGlobalAttribute1("MMM");
final ClientMtTable1 childCommitted = objects.get(1);
final ClientMtTable1 childHollow = objects.get(3);
child.invalidateObjects(childHollow);
queryInterceptor.runWithQueriesBlocked(() -> {
child.commitChangesToParent();
// * all modified child objects must be in committed state now
// * all modifications should be propagated to the parent
// * no actual commit should occur.
assertEquals(PersistenceState.COMMITTED, childNew.getPersistenceState());
assertEquals(PersistenceState.COMMITTED, childModified.getPersistenceState());
assertEquals(PersistenceState.COMMITTED, childCommitted.getPersistenceState());
assertEquals(PersistenceState.HOLLOW, childHollow.getPersistenceState());
ClientMtTable1 parentNew = (ClientMtTable1) clientContext.getGraphManager().getNode(childNew.getObjectId());
final ClientMtTable1 parentModified = (ClientMtTable1) clientContext.getGraphManager().getNode(childModified.getObjectId());
ClientMtTable1 parentCommitted = (ClientMtTable1) clientContext.getGraphManager().getNode(childCommitted.getObjectId());
ClientMtTable1 parentHollow = (ClientMtTable1) clientContext.getGraphManager().getNode(childHollow.getObjectId());
assertNotNull(parentNew);
assertEquals(PersistenceState.NEW, parentNew.getPersistenceState());
assertEquals("NNN", parentNew.getGlobalAttribute1());
assertNotNull(parentModified);
assertEquals(PersistenceState.MODIFIED, parentModified.getPersistenceState());
assertEquals("MMM", parentModified.getGlobalAttribute1());
assertNotNull(parentCommitted);
assertEquals(PersistenceState.COMMITTED, parentCommitted.getPersistenceState());
assertNotNull(parentHollow);
// check that arc changes got recorded in the parent context
GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
final int[] modifiedProperties = new int[1];
diffs.apply(new GraphChangeHandler() {
@Override
public void arcCreated(Object nodeId, Object targetNodeId, ArcId arcId) {
}
@Override
public void arcDeleted(Object nodeId, Object targetNodeId, ArcId arcId) {
}
@Override
public void nodeCreated(Object nodeId) {
}
@Override
public void nodeIdChanged(Object nodeId, Object newId) {
}
@Override
public void nodePropertyChanged(Object nodeId, String property, Object oldValue, Object newValue) {
if (nodeId.equals(parentModified.getObjectId())) {
modifiedProperties[0]++;
}
}
@Override
public void nodeRemoved(Object nodeId) {
}
});
assertEquals(1, modifiedProperties[0]);
});
}
use of org.apache.cayenne.graph.ArcId in project cayenne by apache.
the class NestedCayenneContextIT method testNullifyToOne.
/**
* A test case for CAY-698 bug.
*/
@Test
public void testNullifyToOne() {
ClientMtTable1 a = clientContext.newObject(ClientMtTable1.class);
ClientMtTable2 b = clientContext.newObject(ClientMtTable2.class);
a.addToTable2Array(b);
clientContext.commitChanges();
ObjectContext child = runtime.newContext(clientContext);
ObjectContext childPeer = runtime.newContext(clientContext);
ClientMtTable2 childP1 = SelectById.query(ClientMtTable2.class, b.getObjectId()).selectOne(child);
// trigger object creation in the peer nested DC
Cayenne.objectForPK(childPeer, b.getObjectId());
childP1.setTable1(null);
queryInterceptor.runWithQueriesBlocked(() -> {
child.commitChangesToParent();
assertEquals(PersistenceState.COMMITTED, childP1.getPersistenceState());
ClientMtTable2 parentP1 = (ClientMtTable2) clientContext.getGraphManager().getNode(childP1.getObjectId());
assertNotNull(parentP1);
assertEquals(PersistenceState.MODIFIED, parentP1.getPersistenceState());
assertNull(parentP1.getTable1());
// check that arc changes got recorded in the parent context
GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
final int[] arcDiffs = new int[1];
diffs.apply(new GraphChangeHandler() {
@Override
public void arcCreated(Object nodeId, Object targetNodeId, ArcId arcId) {
arcDiffs[0]++;
}
@Override
public void arcDeleted(Object nodeId, Object targetNodeId, ArcId arcId) {
arcDiffs[0]--;
}
@Override
public void nodeCreated(Object nodeId) {
}
@Override
public void nodeIdChanged(Object nodeId, Object newId) {
}
@Override
public void nodePropertyChanged(Object nodeId, String property, Object oldValue, Object newValue) {
}
@Override
public void nodeRemoved(Object nodeId) {
}
});
assertEquals(-2, arcDiffs[0]);
});
}
Aggregations