ConnectionManagerIF connMan = _pb.serviceConnectionManager();
boolean saveBatchMode = connMan.isBatchMode();
Swizzling swizzlingStrategy = _tx.getKit().getSwizzlingStrategy();
LockManager lockManager = LockManager.getInstance();
Identity[] lockOrder = (Identity[]) _order.toArray(new Identity[_order.size()]);
ObjectCache cache = _pb.serviceObjectCache();
boolean isInsertVerified = _tx.getKit().isInsertVerified();
ArrayList changedCollections = new ArrayList();
// sort objects in the order of oid.hashCode to avoid deadlocks
Arrays.sort(lockOrder, new Comparator()
{
public int compare(Object o1, Object o2)
{
return o1.hashCode() - o2.hashCode();
}
public boolean equals(Object obj)
{
return false;
}
});
try {
// mark dirty objects and lock them for write
// also handle dependent objects and if there were inserted once,
// repeat this process for their dependants ("cascade create")
ArrayList newObjects = new ArrayList();
int countNewObjects;
do
{
newObjects.clear();
countNewObjects = 0;
for (int i = 0; i < lockOrder.length; i++)
{
Identity oid = lockOrder[i];
ContextEntry entry = (ContextEntry) _objects.get(oid);
State state = entry.state;
if (entry.userObject == null) // invalidated
{
continue;
}
if (entry.handler == null) // materialized
{
if (!state.isDeleted())
{
Object[][] origFields = (Object[][]) _checkpointed.get(oid);
Object[][] newFields = getFields(entry.userObject, true, !isCommit);
if (origFields == null)
{
entry.needsCacheSwizzle = true;
newObjects.addAll(
handleDependentReferences(oid, entry.userObject,
null, newFields[0], newFields[2]));
newObjects.addAll(
handleDependentCollections(oid, entry.userObject,
null, newFields[1], newFields[3]));
}
else
{
if (isModified(origFields[0], newFields[0]))
{
entry.state = state.markDirty();
entry.needsCacheSwizzle = true;
lockManager.ensureLock(oid, _tx, LockType.WRITE_LOCK, _pb);
newObjects.addAll(
handleDependentReferences(oid, entry.userObject,
origFields[0], newFields[0], newFields[2]));
}
if (isModified(origFields[1], newFields[1]))
{
// there are modified collections,
// so we need to lock the object and to swizzle it to cache
entry.needsCacheSwizzle = true;
lockManager.ensureLock(oid, _tx, LockType.WRITE_LOCK, _pb);
newObjects.addAll(
handleDependentCollections(oid, entry.userObject,
origFields[1], newFields[1], newFields[3]));
changedCollections.add(oid);
}
}
}
}
}
countNewObjects = newObjects.size();
if (countNewObjects > 0)
{
// new objects are not locked, so we don't need to ensure the order
lockOrder = (Identity[]) newObjects.toArray(
new Identity[countNewObjects]);
}
}
while (countNewObjects > 0);
// Swizzle the context objects and the cache objects
for (Iterator it = _order.iterator(); it.hasNext(); )
{
Identity oid = (Identity) it.next();
ContextEntry entry = (ContextEntry) _objects.get(oid);
if (entry.needsCacheSwizzle)
{
entry.userObject = swizzlingStrategy.getRealTarget(entry.userObject);
entry.cacheObject = swizzlingStrategy.swizzle(
// we create the special ObjectCache implememntation
// that returns cacheObject, not userObject
entry.userObject, entry.cacheObject, _pb, new ObjectCache()
{
public Object lookup(Identity anOid)
{
ContextEntry ent = (ContextEntry) _objects.get(anOid);
return (ent == null ? null : ent.cacheObject);
}
public boolean contains(Identity oid)
{
return lookup(oid) != null;
}
public void cache(Identity anOid, Object obj)
{
// do nothing
}
public boolean cacheIfNew(Identity oid, Object obj)
{
return false;
}
public void clear()
{
// do nothing
}
public void remove(Identity anOid)
{
// do nothing
}
});
}
}
// Cascade delete for dependent objects
int countCascadeDeleted;
do
{
countCascadeDeleted = 0;
// Use intermediate new ArrayList(_order) because _order
// may be changed during cascade delete
for (Iterator it = (new ArrayList(_order)).iterator(); it.hasNext(); )
{
Identity oid = (Identity) it.next();
ContextEntry entry = (ContextEntry) _objects.get(oid);
if (entry.state.isDeleted())
{
countCascadeDeleted += doCascadeDelete(oid, entry.userObject);
}
}
}
while (countCascadeDeleted > 0);
// perform database operations
connMan.setBatchMode(true);
try
{
for (Iterator it = _order.iterator(); it.hasNext(); )
{
Identity oid = (Identity) it.next();
ContextEntry entry = (ContextEntry) _objects.get(oid);
State state = entry.state;
if (!state.needsInsert() && !state.needsUpdate()
&& !state.needsDelete())
{
if (changedCollections.contains(oid)) {
_pb.store(entry.cacheObject, state);
}
continue;
}
if (state.needsInsert())
{
if (isInsertVerified)
{
// PB verifies object existence by default
_pb.store(entry.cacheObject);
}
else
{
// PB migth already created the object by auto-update
if (cache.lookup(oid) == null) {
_pb.store(entry.cacheObject, state);
}
}
}