All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nakedobjects.plugins.remoting.client.persistence.ClientSideTransactionManager Maven / Gradle / Ivy

package org.nakedobjects.plugins.remoting.client.persistence;

import org.apache.log4j.Logger;
import org.nakedobjects.metamodel.adapter.NakedObject;
import org.nakedobjects.metamodel.adapter.ResolveState;
import org.nakedobjects.metamodel.adapter.oid.Oid;
import org.nakedobjects.metamodel.adapter.version.Version;
import org.nakedobjects.metamodel.authentication.AuthenticationSession;
import org.nakedobjects.plugins.remoting.shared.ObjectEncoder;
import org.nakedobjects.plugins.remoting.shared.ServerFacade;
import org.nakedobjects.plugins.remoting.shared.data.ClientActionResultData;
import org.nakedobjects.plugins.remoting.shared.data.KnownObjects;
import org.nakedobjects.plugins.remoting.shared.data.ObjectData;
import org.nakedobjects.plugins.remoting.shared.data.ReferenceData;
import org.nakedobjects.plugins.remoting.shared.transaction.ClientSideTransaction;
import org.nakedobjects.plugins.remoting.shared.transaction.ClientTransactionEvent;
import org.nakedobjects.runtime.context.NakedObjectsContext;
import org.nakedobjects.runtime.persistence.ConcurrencyException;
import org.nakedobjects.runtime.persistence.PersistenceSessionTransactionManagement;
import org.nakedobjects.runtime.persistence.adaptermanager.AdapterManagerProxy;
import org.nakedobjects.runtime.transaction.NakedObjectTransactionManagerAbstract;
import org.nakedobjects.runtime.transaction.PersistenceCommand;
import org.nakedobjects.runtime.transaction.messagebroker.MessageBroker;
import org.nakedobjects.runtime.transaction.updatenotifier.UpdateNotifier;

public class ClientSideTransactionManager extends NakedObjectTransactionManagerAbstract {

    final static Logger LOG = Logger.getLogger(ClientSideTransactionManager.class);

    private final AdapterManagerProxy adapterManager;
    private final PersistenceSessionTransactionManagement transactionManagement;
    private final ServerFacade connection;
    private final ObjectEncoder encoder;
    
    ////////////////////////////////////////////////////////////////
    // Constructor
    ////////////////////////////////////////////////////////////////

    public ClientSideTransactionManager(
            final AdapterManagerProxy adapterManager, 
            final PersistenceSessionTransactionManagement transactionManagement, 
            final ServerFacade connection, 
            final ObjectEncoder encoder) {
        this.adapterManager = adapterManager;
        this.transactionManagement = transactionManagement;
        this.connection = connection;
        this.encoder = encoder;
    }

    

    ////////////////////////////////////////////////////////////////
    // start, addCommand, flush, end
    ////////////////////////////////////////////////////////////////
    
    public void startTransaction() {
        ensureTransactionNotInProgress();
        if (LOG.isDebugEnabled()) {
            LOG.debug("startTransaction");
        }
        
        // just in case...?
        transactionManagement.clearAllDirty();
        
        createTransaction();
    }

    
    /**
     * Overridable hook.
     * 
     * 

* The provided {@link MessageBroker} and {@link UpdateNotifier} are obtained from * the hook methods ({@link #createMessageBroker()} and {@link #createUpdateNotifier()}). * * @see #createMessageBroker() * @see #createUpdateNotifier() */ protected ClientSideTransaction createTransaction(MessageBroker messageBroker, UpdateNotifier updateNotifier) { return new ClientSideTransaction(this, messageBroker, updateNotifier); } public void addCommand(final PersistenceCommand command) { // does nothing } public boolean flushTransaction() { return false; } public void endTransaction() { ensureTransactionInProgress(); if (LOG.isDebugEnabled()) { LOG.debug("endTransaction"); } if (getTransaction().isEmpty()) { if (LOG.isDebugEnabled()) { LOG.debug(" no transaction commands to process"); } } else { endNonEmptyTransaction(); } getTransaction().commit(); } private void endNonEmptyTransaction() { final KnownObjects knownObjects = new KnownObjects(); final ClientTransactionEvent[] transactionEntries = getTransaction().getEntries(); final ReferenceData[] data = asData(transactionEntries, knownObjects); final int[] eventTypes = asEventTypes(transactionEntries); ClientActionResultData results; try { results = connection.executeClientAction(getAuthenticationSession(), data, eventTypes); } catch (final ConcurrencyException e) { if (LOG.isInfoEnabled()) { LOG.info("concurrency conflict: " + e.getMessage()); } final Oid oid = e.getSource(); if (oid == null) { throw e; } else { final NakedObject failedObject = transactionManagement.reload(oid); throw new ConcurrencyException("Object automatically reloaded: " + failedObject.getSpecification().getTitle(failedObject), e); } } if (results != null) { handleResults(transactionEntries, results); } } private int[] asEventTypes( final ClientTransactionEvent[] entries ) { final int numberOfEvents = entries.length; final int[] types = new int[numberOfEvents]; for (int i = 0; i < numberOfEvents; i++) { types[i] = entries[i].getType(); } return types; } private ReferenceData[] asData( final ClientTransactionEvent[] entries, final KnownObjects knownObjects ) { final int numberOfEvents = entries.length; final ReferenceData[] data = new ReferenceData[numberOfEvents]; for (int i = 0; i < numberOfEvents; i++) { switch (entries[i].getType()) { case ClientTransactionEvent.ADD: data[i] = encoder.createMakePersistentGraph(entries[i].getObject(), knownObjects); break; case ClientTransactionEvent.CHANGE: data[i] = encoder.createGraphForChangedObject(entries[i].getObject(), knownObjects); break; case ClientTransactionEvent.DELETE: data[i] = encoder.createIdentityData(entries[i].getObject()); break; } } return data; } private void handleResults( final ClientTransactionEvent[] entries, final ClientActionResultData results) { final int numberOfEvents = entries.length; final int[] eventTypes = asEventTypes(entries); final ReferenceData[] persistedUpdates = results.getPersisted(); final Version[] changedVersions = results.getChanged(); for (int i = 0; i < numberOfEvents; i++) { switch (eventTypes[i]) { case ClientTransactionEvent.ADD: // causes OID to be updated final ReferenceData update = persistedUpdates[i]; Oid updatedOid = update.getOid(); adapterManager.remapUpdated(updatedOid); final NakedObject adapter = adapterManager.getAdapterFor(updatedOid); adapter.changeState(ResolveState.RESOLVED); entries[i].getObject().setOptimisticLock(update.getVersion()); break; case ClientTransactionEvent.CHANGE: entries[i].getObject().setOptimisticLock(changedVersions[i]); getUpdateNotifier().addChangedObject(entries[i].getObject()); break; } } final ObjectData[] updates = results.getUpdates(); for (int i = 0; i < updates.length; i++) { if (LOG.isDebugEnabled()) { LOG.debug("update " + updates[i].getOid()); } encoder.restore(updates[i]); } for (int i = 0; i < numberOfEvents; i++) { switch (eventTypes[i]) { case ClientTransactionEvent.DELETE: getUpdateNotifier().addDisposedObject(entries[i].getObject()); break; } } } public void abortTransaction() { ensureTransactionInProgress(); if (LOG.isDebugEnabled()) { LOG.debug("abortTransaction"); } getTransaction().abort(); } ////////////////////////////////////////////////////////////////// // Not public API ////////////////////////////////////////////////////////////////// public void addMakePersistent(NakedObject object) { ensureTransactionInProgress(); getTransaction().addMakePersistent(object); } public void addObjectChanged(NakedObject object) { ensureTransactionInProgress(); getTransaction().addObjectChanged(object); } public void addDestroyObject(NakedObject object) { ensureTransactionInProgress(); getTransaction().addDestroyObject(object); } ////////////////////////////////////////////////////////////////// // Dependencies (from context) ////////////////////////////////////////////////////////////////// private AuthenticationSession getAuthenticationSession() { return NakedObjectsContext.getAuthenticationSession(); } } // Copyright (c) Naked Objects Group Ltd.





© 2015 - 2025 Weber Informatics LLC | Privacy Policy