FileDocCategorySizeDatePackage
CommitManager.javaAPI DocGlassfish v2 API30209Tue May 22 16:54:42 BST 2007oracle.toplink.essentials.internal.sessions

CommitManager

public class CommitManager extends Object
This class maintains a commit stack and resolves circular references.

Fields Summary
protected Vector
commitOrder
protected IdentityHashtable
processedCommits
Changed the folowing line to work like mergemanager. The commitManager will now track what has been processed as apposed to removing from the list objects that have been processed. This must be done to allow for customers modifying the changesets in events
protected IdentityHashtable
pendingCommits
protected IdentityHashtable
preModifyCommits
protected IdentityHashtable
postModifyCommits
protected IdentityHashtable
completedCommits
protected IdentityHashtable
shallowCommits
protected AbstractSession
session
protected boolean
isActive
protected Hashtable
dataModifications
protected Vector
objectsToDelete
Constructors Summary
public CommitManager(AbstractSession session)
Create the commit manager on the session. It must be initialized later on after the descriptors have been added.

        this.session = session;
        this.commitOrder = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
        this.isActive = false;

        // PERF - move to lazy initialization (3286091)
        //this.processedCommits = new IdentityHashtable(20);
        //this.pendingCommits = new IdentityHashtable(20);
        //this.preModifyCommits = new IdentityHashtable(20);
        //this.postModifyCommits = new IdentityHashtable(20);
        //this.completedCommits = new IdentityHashtable(20);
        //this.shallowCommits = new IdentityHashtable(20);
    
Methods Summary
public voidaddDataModificationEvent(DatabaseMapping mapping, java.lang.Object[] event)
Add the data query to be performed at the end of the commit. This is done to decrease dependencies and avoid deadlock.

        // For lack of inner class the array is being called an event.
        if (!getDataModifications().containsKey(mapping)) {
            getDataModifications().put(mapping, new Vector());
        }

        ((Vector)getDataModifications().get(mapping)).addElement(event);
    
public voidaddObjectToDelete(java.lang.Object objectToDelete)
Deletion are cached until the end.

        getObjectsToDelete().addElement(objectToDelete);
    
protected voidaddProcessedCommit(java.lang.Object domainObject)
add the commit of the object to the processed list.

        getProcessedCommits().put(domainObject, domainObject);
    
public voidcommitAllObjects(IdentityHashtable domainObjects)
Commit all of the objects as a single transaction. This should commit the object in the correct order to maintain referencial integrity.

        reinitialize();
        setPendingCommits(domainObjects);

        setIsActive(true);
        getSession().beginTransaction();
        try {
            // The commit order is all of the classes ordered by dependencies, this is done for dealock avoidance.
            for (Enumeration classesEnum = getCommitOrder().elements();
                     classesEnum.hasMoreElements();) {
                Class theClass = (Class)classesEnum.nextElement();

                for (Enumeration pendingEnum = getPendingCommits().elements();
                         pendingEnum.hasMoreElements();) {
                    Object objectToWrite = pendingEnum.nextElement();
                    if (objectToWrite.getClass() == theClass) {
                        removePendingCommit(objectToWrite);// I think removing while enumerating is ok.

                        WriteObjectQuery commitQuery = new WriteObjectQuery();
                        commitQuery.setObject(objectToWrite);
                        if (getSession().isUnitOfWork()) {
                            commitQuery.cascadeOnlyDependentParts();
                        } else {
                            commitQuery.cascadeAllParts();// Used in write all objects in session.
                        }
                        getSession().executeQuery(commitQuery);
                    }
                }
            }

            for (Enumeration mappingsEnum = getDataModifications().keys(), mappingEventsEnum = getDataModifications().elements();
                     mappingEventsEnum.hasMoreElements();) {
                Vector events = (Vector)mappingEventsEnum.nextElement();
                DatabaseMapping mapping = (DatabaseMapping)mappingsEnum.nextElement();
                for (Enumeration eventsEnum = events.elements(); eventsEnum.hasMoreElements();) {
                    Object[] event = (Object[])eventsEnum.nextElement();
                    mapping.performDataModificationEvent(event, getSession());
                }
            }

            Vector objects = getObjectsToDelete();
            reinitialize();
            for (Enumeration objectsToDeleteEnum = objects.elements();
                     objectsToDeleteEnum.hasMoreElements();) {
                getSession().deleteObject(objectsToDeleteEnum.nextElement());
            }
        } catch (RuntimeException exception) {
            getSession().rollbackTransaction();
            throw exception;
        } finally {
            reinitialize();
            setIsActive(false);
        }

        getSession().commitTransaction();
    
protected voidcommitAllObjectsForClassWithChangeSet(UnitOfWorkChangeSet uowChangeSet, java.lang.Class theClass)
Commit all of the objects of the class type in the change set. This allows for the order of the classes to be processed optimally.

    
        // Although new objects should be first, there is an issue that new objects get added to non-new after the insert,
        // so the object would be written twice.
        commitChangedObjectsForClassWithChangeSet(uowChangeSet, theClass.getName());
        commitNewObjectsForClassWithChangeSet(uowChangeSet, theClass);
    
public voidcommitAllObjectsWithChangeSet(UnitOfWorkChangeSet uowChangeSet)
Commit all of the objects as a single transaction. This should commit the object in the correct order to maintain referencial integrity.

        reinitialize();
        setIsActive(true);
        getSession().beginTransaction();
        try {
            // PERF: if the number of classes in the project is large this loop can be a perf issue.
            // If only one class types changed, then avoid loop.
            if ((uowChangeSet.getObjectChanges().size() + uowChangeSet.getNewObjectChangeSets().size()) <= 1) {
                Enumeration classes = uowChangeSet.getNewObjectChangeSets().keys();
                if (classes.hasMoreElements()) {
                    Class theClass = (Class)classes.nextElement();
                    commitNewObjectsForClassWithChangeSet(uowChangeSet, theClass);
                }
                Enumeration classNames = uowChangeSet.getObjectChanges().keys();
                if (classNames.hasMoreElements()) {
                    String className = (String)classNames.nextElement();
                    commitChangedObjectsForClassWithChangeSet(uowChangeSet, className);
                }
            } else {
                // The commit order is all of the classes ordered by dependencies, this is done for dealock avoidance.
                for (Enumeration classesEnum = getCommitOrder().elements();
                         classesEnum.hasMoreElements();) {
                    Class theClass = (Class)classesEnum.nextElement();
                    commitAllObjectsForClassWithChangeSet(uowChangeSet, theClass);
                }
            }

            if (hasDataModifications()) {
                // Perform all batched up data modifications, done to avoid dependecies.
                for (Enumeration mappingsEnum = getDataModifications().keys(), mappingEventsEnum = getDataModifications().elements();
                         mappingEventsEnum.hasMoreElements();) {
                    Vector events = (Vector)mappingEventsEnum.nextElement();
                    DatabaseMapping mapping = (DatabaseMapping)mappingsEnum.nextElement();
                    for (Enumeration eventsEnum = events.elements(); eventsEnum.hasMoreElements();) {
                        Object[] event = (Object[])eventsEnum.nextElement();
                        mapping.performDataModificationEvent(event, getSession());
                    }
                }
            }

            if (hasObjectsToDelete()) {
                Vector objects = getObjectsToDelete();
                reinitialize();
                for (Enumeration objectsToDeleteEnum = objects.elements();
                         objectsToDeleteEnum.hasMoreElements();) {
                    getSession().deleteObject(objectsToDeleteEnum.nextElement());
                }
            }
        } catch (RuntimeException exception) {
            getSession().rollbackTransaction();
            throw exception;
        } finally {
            reinitialize();
            setIsActive(false);
        }

        getSession().commitTransaction();
    
protected voidcommitChangedObjectsForClassWithChangeSet(UnitOfWorkChangeSet uowChangeSet, java.lang.String className)
Commit changed of the objects of the class type in the change set. This allows for the order of the classes to be processed optimally.

        Hashtable objectChangesList = (Hashtable)uowChangeSet.getObjectChanges().get(className);
        if (objectChangesList != null) {// may be no changes for that class type.				
            ClassDescriptor descriptor = null;
            for (Enumeration pendingEnum = objectChangesList.elements();
                     pendingEnum.hasMoreElements();) {
                ObjectChangeSet changeSetToWrite = (ObjectChangeSet)pendingEnum.nextElement();
                if (descriptor == null) {
                    // Need a class to get descriptor, for some evil reason the keys are class name.
                    descriptor = getSession().getDescriptor(changeSetToWrite.getClassType(getSession()));
                }
                Object objectToWrite = changeSetToWrite.getUnitOfWorkClone();
                if ((!getProcessedCommits().containsKey(changeSetToWrite)) && (!getProcessedCommits().containsKey(objectToWrite))) {
                    addProcessedCommit(changeSetToWrite);
                    // Commit and resume on failure can cause a new change set to be in existing, so need to check here.
                    WriteObjectQuery commitQuery = null;
                    if (changeSetToWrite.isNew()) {
                        commitQuery = new InsertObjectQuery();
                    } else {
                        commitQuery = new UpdateObjectQuery();
                    }
                    commitQuery.setObjectChangeSet(changeSetToWrite);
                    commitQuery.setObject(objectToWrite);
                    commitQuery.cascadeOnlyDependentParts();
                    // removed checking session type to set cascade level
                    // will always be a unitOfWork so we need to cascade dependent parts
                    getSession().executeQuery(commitQuery);
                }
                ((UnitOfWorkImpl)getSession()).updateChangeTrackersIfRequired(objectToWrite, changeSetToWrite, (UnitOfWorkImpl)getSession(), descriptor);

                // after the query has executed lets clear the change detection policies
                // this is important for write changes and non deferred writes support
            }
        }
    
protected voidcommitNewObjectsForClassWithChangeSet(UnitOfWorkChangeSet uowChangeSet, java.lang.Class theClass)
Commit all of the objects of the class type in the change set. This allows for the order of the classes to be processed optimally.

        IdentityHashtable newObjectChangesList = (IdentityHashtable)uowChangeSet.getNewObjectChangeSets().get(theClass);
        if (newObjectChangesList != null) {// may be no changes for that class type.				
            ClassDescriptor descriptor = getSession().getDescriptor(theClass);
            for (Enumeration pendingEnum = newObjectChangesList.elements();
                     pendingEnum.hasMoreElements();) {
                ObjectChangeSet changeSetToWrite = (ObjectChangeSet)pendingEnum.nextElement();
                Object objectToWrite = changeSetToWrite.getUnitOfWorkClone();
                if ((!getProcessedCommits().containsKey(changeSetToWrite)) && (!getProcessedCommits().containsKey(objectToWrite))) {
                    addProcessedCommit(changeSetToWrite);
                    InsertObjectQuery commitQuery = new InsertObjectQuery();
                    commitQuery.setObjectChangeSet(changeSetToWrite);
                    commitQuery.setObject(objectToWrite);
                    commitQuery.cascadeOnlyDependentParts();
                    // removed checking session type to set cascade level
                    // will always be a unitOfWork so we need to cascade dependent parts
                    getSession().executeQuery(commitQuery);
                }
                ((UnitOfWorkImpl)getSession()).updateChangeTrackersIfRequired(objectToWrite, changeSetToWrite, (UnitOfWorkImpl)getSession(), descriptor);

                //after the query has executed lets clear the change detection policies
                //this is important for write changes and non deferred writes support
            }
        }
    
public voiddeleteAllObjects(java.util.Vector objectsForDeletion)
delete all of the objects as a single transaction. This should delete the object in the correct order to maintain referencial integrity.

        setIsActive(true);
        getSession().beginTransaction();

        try {
            for (int index = getCommitOrder().size() - 1; index >= 0; index--) {
                Class theClass = (Class)getCommitOrder().elementAt(index);

                for (Enumeration objectsForDeletionEnum = objectsForDeletion.elements();
                         objectsForDeletionEnum.hasMoreElements();) {
                    Object objectToDelete = objectsForDeletionEnum.nextElement();
                    if (objectToDelete.getClass() == theClass) {
                        DeleteObjectQuery deleteQuery = new DeleteObjectQuery();
                        deleteQuery.setObject(objectToDelete);
                        deleteQuery.cascadeOnlyDependentParts();
                        getSession().executeQuery(deleteQuery);
                    }
                }
            }
        } catch (RuntimeException exception) {
            try {
                getSession().rollbackTransaction();
            } catch (Exception ignore) {
            }
            throw exception;
        } finally {
            setIsActive(false);
        }

        getSession().commitTransaction();
    
public java.util.VectorgetCommitOrder()
Return the order in which objects should be commited to the database. This order is based on ownership in the descriptors and is require for referencial integrity. The commit order is a vector of vectors, where the first vector is all root level classes, the second is classes owned by roots and so on.

        return commitOrder;
    
protected IdentityHashtablegetCompletedCommits()
Return any objects that have been written during this commit process.

        if (completedCommits == null) {
            // 2612538 - the default size of IdentityHashtable (32) is appropriate
            completedCommits = new IdentityHashtable();
        }
        return completedCommits;
    
protected java.util.HashtablegetDataModifications()
Used to store data querys to be performed at the end of the commit. This is done to decrease dependencies and avoid deadlock.

        if (dataModifications == null) {
            dataModifications = new Hashtable(10);
        }
        return dataModifications;
    
protected java.util.VectorgetObjectsToDelete()
Deletion are cached until the end.

        if (objectsToDelete == null) {
            objectsToDelete = new Vector(5);
        }
        return objectsToDelete;
    
protected IdentityHashtablegetPendingCommits()
Return any objects that should be written during this commit process.

        if (pendingCommits == null) {
            // 2612538 - the default size of IdentityHashtable (32) is appropriate
            pendingCommits = new IdentityHashtable();
        }
        return pendingCommits;
    
protected IdentityHashtablegetPostModifyCommits()
Return any objects that should be written during post modify commit process. These objects should be order by their ownership constraints to maintain referencial integrity.

        if (postModifyCommits == null) {
            // 2612538 - the default size of IdentityHashtable (32) is appropriate
            postModifyCommits = new IdentityHashtable();
        }
        return postModifyCommits;
    
protected IdentityHashtablegetPreModifyCommits()
Return any objects that should be written during pre modify commit process. These objects should be order by their ownership constraints to maintain referencial integrity.

        if (preModifyCommits == null) {
            // 2612538 - the default size of IdentityHashtable (32) is appropriate
            preModifyCommits = new IdentityHashtable();
        }
        return preModifyCommits;
    
protected IdentityHashtablegetProcessedCommits()
Return any objects that should be written during this commit process.

        if (processedCommits == null) {
            // 2612538 - the default size of IdentityHashtable (32) is appropriate
            processedCommits = new IdentityHashtable();
        }
        return processedCommits;
    
protected AbstractSessiongetSession()
Return the session that this is managing commits for.

        return session;
    
protected IdentityHashtablegetShallowCommits()
Return any objects that have been shallow comitted during this commit process.

        if (shallowCommits == null) {
            // 2612538 - the default size of IdentityHashtable (32) is appropriate
            shallowCommits = new IdentityHashtable();
        }
        return shallowCommits;
    
protected booleanhasDataModifications()

        return ((dataModifications != null) && (!dataModifications.isEmpty()));
    
protected booleanhasObjectsToDelete()

        return ((objectsToDelete != null) && (!objectsToDelete.isEmpty()));
    
public voidinitializeCommitOrder()
Reset the commit order from the session's descriptors. This uses the constraint dependencies in the descriptor's mappings, to decide which descriptors are dependent on which other descriptors. Multiple computations of the commit order should produce the same ordering. This is done to improve performance on unit of work writes through decreasing the stack size, and acts as a deadlock avoidance mechansim.

        Vector descriptors = Helper.buildVectorFromMapElements(getSession().getDescriptors());

        // Must ensure uniqueness, some descriptor my be register twice for interfaces.
        descriptors = Helper.addAllUniqueToVector(new Vector(descriptors.size()), descriptors);
        Object[] descriptorsArray = new Object[descriptors.size()];
        for (int index = 0; index < descriptors.size(); index++) {
            descriptorsArray[index] = descriptors.elementAt(index);
        }
        TOPSort.quicksort(descriptorsArray, new DescriptorCompare());
        descriptors = new Vector(descriptors.size());
        for (int index = 0; index < descriptorsArray.length; index++) {
            descriptors.addElement(descriptorsArray[index]);
        }

        CommitOrderCalculator calculator = new CommitOrderCalculator(getSession());
        calculator.addNodes(descriptors);
        calculator.calculateMappingDependencies();
        calculator.orderCommits();
        descriptors = calculator.getOrderedDescriptors();

        calculator = new CommitOrderCalculator(getSession());
        calculator.addNodes(descriptors);
        calculator.calculateSpecifiedDependencies();
        calculator.orderCommits();

        setCommitOrder(calculator.getOrderedClasses());
    
public booleanisActive()
Return if the commit manager is active.

        return isActive;
    
public booleanisCommitCompleted(java.lang.Object domainObject)
Return if the object has been commited. This should be called by any query that is writing an object, if true the query should not write the object.

        return getCompletedCommits().containsKey(domainObject);
    
public booleanisCommitInPostModify(java.lang.Object domainObject)
Return if the object is being in progress of being post modify commit. This should be called by any query that is writing an object, if true the query must force a shallow insert of the object if it is new.

        return getPostModifyCommits().containsKey(domainObject);
    
public booleanisCommitInPreModify(java.lang.Object domainObject)
Return if the object is being in progress of being pre modify commit. This should be called by any query that is writing an object, if true the query must force a shallow insert of the object if it is new.

        return getPreModifyCommits().containsKey(domainObject);
    
public booleanisShallowCommitted(java.lang.Object domainObject)
Return if the object is shallow committed. This is required to resolve bidirection references.

        return getShallowCommits().containsKey(domainObject);
    
public voidmarkCommitCompleted(java.lang.Object domainObject)
Mark the commit of the object as being fully completed. This should be called by any query that has finished writing an object.

        getPreModifyCommits().remove(domainObject);
        getPostModifyCommits().remove(domainObject);
        // If not in a unit of work commit and the commit of this object is done reset the comitt manager
        if ((!isActive()) && getPostModifyCommits().isEmpty() && getPreModifyCommits().isEmpty()) {
            reinitialize();
            return;
        }
        getCompletedCommits().put(domainObject, domainObject);// Treat as set.
    
public voidmarkPostModifyCommitInProgress(java.lang.Object domainObject)
Add an object as being in progress of being commited. This should be called by any query that is writing an object.

        getPreModifyCommits().remove(domainObject);
        getPostModifyCommits().put(domainObject, domainObject);// Use as set.
    
public voidmarkPreModifyCommitInProgress(java.lang.Object domainObject)
Add an object as being in progress of being commited. This should be called by any query that is writing an object.

        removePendingCommit(domainObject);
        addProcessedCommit(domainObject);
        getPreModifyCommits().put(domainObject, domainObject);// Use as set.
    
public voidmarkShallowCommit(java.lang.Object domainObject)
Mark the object as shallow committed. This is required to resolve bidirection references.

        getShallowCommits().put(domainObject, domainObject);// Use as set.
    
public voidreinitialize()
Reset the commits. This must be done before a new commit process is begun.

        setPendingCommits(null);
        setProcessedCommits(null);
        setPreModifyCommits(null);
        setPostModifyCommits(null);
        setCompletedCommits(null);
        setShallowCommits(null);
        setObjectsToDelete(null);
        setDataModifications(null);
    
protected voidremovePendingCommit(java.lang.Object domainObject)
Remove the commit of the object from pending.

        getPendingCommits().remove(domainObject);
    
public voidsetCommitOrder(java.util.Vector commitOrder)
Set the order in which objects should be commited to the database. This order is based on ownership in the descriptors and is require for referencial integrity. The commit order is a vector of vectors, where the first vector is all root level classes, the second is classes owned by roots and so on.

        this.commitOrder = commitOrder;
    
protected voidsetCompletedCommits(IdentityHashtable completedCommits)
Set the objects that have been written during this commit process.

        this.completedCommits = completedCommits;
    
protected voidsetDataModifications(java.util.Hashtable dataModifications)
Used to store data querys to be performed at the end of the commit. This is done to decrease dependencies and avoid deadlock.

        this.dataModifications = dataModifications;
    
public voidsetIsActive(boolean isActive)
Set if the commit manager is active.

        this.isActive = isActive;
    
protected voidsetObjectsToDelete(java.util.Vector objectsToDelete)
Deletion are cached until the end.

        this.objectsToDelete = objectsToDelete;
    
protected voidsetPendingCommits(IdentityHashtable pendingCommits)
Set the objects that should be written during this commit process.

        this.pendingCommits = pendingCommits;
    
protected voidsetPostModifyCommits(IdentityHashtable postModifyCommits)
Set any objects that should be written during post modify commit process. These objects should be order by their ownership constraints to maintain referencial integrity.

        this.postModifyCommits = postModifyCommits;
    
protected voidsetPreModifyCommits(IdentityHashtable preModifyCommits)
Set any objects that should be written during pre modify commit process. These objects should be order by their ownership constraints to maintain referencial integrity.

        this.preModifyCommits = preModifyCommits;
    
protected voidsetProcessedCommits(IdentityHashtable processedCommits)
Set the objects that should be written during this commit process.

        this.processedCommits = processedCommits;
    
protected voidsetSession(AbstractSession session)
Set the session that this is managing commits for.

        this.session = session;
    
protected voidsetShallowCommits(IdentityHashtable shallowCommits)
Set any objects that have been shallow comitted during this commit process.

        this.shallowCommits = shallowCommits;
    
public java.lang.StringtoString()
Print the in progress depth.

        int size = 0;
        if (preModifyCommits != null) {
            size += getPreModifyCommits().size();
        }
        if (postModifyCommits != null) {
            size += getPostModifyCommits().size();
        }
        Object[] args = { new Integer(size) };
        return Helper.getShortClassName(getClass()) + ToStringLocalization.buildMessage("commit_depth", args);