You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2016/05/26 16:30:05 UTC

[2/4] isis git commit: ISIS-1414: moving the @RequestScoped initialization/close stuff out of IsisTransactionManager and IsisTransaction, and into PersistenceSession.

ISIS-1414: moving the @RequestScoped initialization/close stuff out of IsisTransactionManager and IsisTransaction, and into PersistenceSession.

Also:
- CommandService#startTransaction is no longer called.
- remove unused code/hashmap in PersistenceSession


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/21b27fe4
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/21b27fe4
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/21b27fe4

Branch: refs/heads/ISIS-1414
Commit: 21b27fe49790adc78a3fe7804ff4feba7790bbed
Parents: 0d32721
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Thu May 26 16:22:19 2016 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Thu May 26 17:26:54 2016 +0100

----------------------------------------------------------------------
 .../guides/_rgsvc_spi_CommandService.adoc       |   2 +-
 core/applib/pom.xml                             |   4 +
 .../services/command/spi/CommandService.java    |   2 +
 core/pom.xml                                    |   6 +
 .../runtime/services/ServiceInstantiator.java   |  36 +--
 .../changes/ChangedObjectsServiceInternal.java  |   1 +
 .../system/persistence/PersistenceSession.java  | 271 ++++++++++++++-----
 .../system/transaction/IsisTransaction.java     | 225 +++++----------
 .../transaction/IsisTransactionManager.java     | 134 ++-------
 9 files changed, 312 insertions(+), 369 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/adocs/documentation/src/main/asciidoc/guides/_rgsvc_spi_CommandService.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_rgsvc_spi_CommandService.adoc b/adocs/documentation/src/main/asciidoc/guides/_rgsvc_spi_CommandService.adoc
index ee3885b..a795586 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_rgsvc_spi_CommandService.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_rgsvc_spi_CommandService.adoc
@@ -56,7 +56,7 @@ public interface CommandService {
 <1> Instantiate the appropriate instance of the `Command` (as defined by the
 xref:rgsvc.adoc#_rgsvc_api_CommandContext[`CommandContext`] service).  Its members will be populated automatically by
 the framework.
-<2> (as of `1.13.0-SNAPSHOT`) is deprecated: the framework automatically populates the ``Command``'s `timestamp`,
+<2> (as of `1.13.0-SNAPSHOT`) is *NO LONGER CALLED* and is deprecated: the framework automatically populates the ``Command``'s `timestamp`,
 `user` and `transactionId` fields, so there is no need for the service implementation to initialize any of these.  In
 particular, the ``Command`` will already have been initialized with the provided `transactionId` argument.
 <3> Set the hint that the `Command` should be persisted if possible (when completed, see below).

http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/applib/pom.xml
----------------------------------------------------------------------
diff --git a/core/applib/pom.xml b/core/applib/pom.xml
index 4cb78cd..a38461c 100644
--- a/core/applib/pom.xml
+++ b/core/applib/pom.xml
@@ -102,6 +102,10 @@
             <artifactId>validation-api</artifactId>
         </dependency>
         <dependency>
+            <groupId>javax.transaction</groupId>
+            <artifactId>transaction-api</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.apache.geronimo.specs</groupId>
             <artifactId>geronimo-jcdi_1.0_spec</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java b/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
index da7434e..5d018de 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
@@ -34,6 +34,8 @@ public interface CommandService {
     Command create();
     
     /**
+     * DEPRECATED - this method is no longer called by the framework.
+     *
      * @deprecated - the framework automatically populates the {@link Command}'s {@link Command#getTimestamp()}, {@link Command#getUser()}  and {@link Command#getTransactionId()}, so there is no need for the service implementation to initialize any of these.  In particular, the {@link Command} will already have been initialized with the provided <tt>transactionId</tt> argument.
      */
     @Deprecated

http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 6770b0d..611c6bb 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -175,6 +175,7 @@
         <geronimo-jcdi_1.0_spec.version>1.0</geronimo-jcdi_1.0_spec.version>
 
         <validation-api.version>1.1.0.Final</validation-api.version>
+        <transaction-api.version>1.2</transaction-api.version>
 
         <javax-mail.version>1.4.7</javax-mail.version>
 
@@ -1890,6 +1891,11 @@ ${license.additional-notes}
                 <artifactId>validation-api</artifactId>
                 <version>${validation-api.version}</version>
             </dependency>
+            <dependency>
+                <groupId>javax.transaction</groupId>
+                <artifactId>transaction-api</artifactId>
+                <version>${transaction-api.version}</version>
+            </dependency>
 
 
             <!-- DataNucleus -->

http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServiceInstantiator.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServiceInstantiator.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServiceInstantiator.java
index 27ee048..bda20bd 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServiceInstantiator.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServiceInstantiator.java
@@ -19,22 +19,21 @@
 
 package org.apache.isis.core.runtime.services;
 
-import javassist.util.proxy.MethodFilter;
-import javassist.util.proxy.MethodHandler;
-import javassist.util.proxy.ProxyFactory;
-import javassist.util.proxy.ProxyObject;
-
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Map;
 import java.util.Set;
+
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.enterprise.context.RequestScoped;
+
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+
 import org.apache.isis.core.commons.config.IsisConfiguration;
 import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.commons.factory.InstanceCreationClassException;
@@ -44,6 +43,11 @@ import org.apache.isis.core.commons.lang.MethodExtensions;
 import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.metamodel.specloader.classsubstitutor.JavassistEnhanced;
 
+import javassist.util.proxy.MethodFilter;
+import javassist.util.proxy.MethodHandler;
+import javassist.util.proxy.ProxyFactory;
+import javassist.util.proxy.ProxyObject;
+
 /**
  * Instantiates the service, taking into account whether the service is annotated with
  * {@link RequestScoped} or not.
@@ -75,13 +79,6 @@ public final class ServiceInstantiator {
 
     // //////////////////////////////////////
 
-    private boolean ignoreFailures;
-    public void setIgnoreFailures(boolean ignoreFailures) {
-        this.ignoreFailures = ignoreFailures;
-    }
-
-    // //////////////////////////////////////
-
 
     /**
      * initially null, but checked before first use that has been set (through {@link #setConfiguration(org.apache.isis.core.commons.config.IsisConfiguration)}).
@@ -116,9 +113,6 @@ public final class ServiceInstantiator {
             //return Thread.currentThread().getContextClassLoader().loadClass(className);
             return Class.forName(className);
         } catch (final ClassNotFoundException ex) {
-            if(ignoreFailures) {
-                return null;
-            }
             throw new InitialisationException(String.format("Cannot find class '%s' for service", className));
         }
     }
@@ -219,21 +213,17 @@ public final class ServiceInstantiator {
                     } else {
                         T service = serviceByThread.get();
                         if(service == null) {
-                            // ignore; this could potentially happen during an application-level init (PersistenceSessionFactory#init)
-                            // it has also happened in past when enabling debugging, though the
-                            // new hashCode(), equals() and toString() checks above should mitigate.
-                            return null;
+                            // shouldn't happen...
+                            throw new IllegalStateException("No service of type " + cls + " is available on this ");
                         }
-                        final Object proxiedReturn = proxyMethod.invoke(service, args); 
+                        final Object proxiedReturn = proxyMethod.invoke(service, args);
                         return proxiedReturn;
                     }
                 }
             });
 
             return newInstance;
-        } catch (final InstantiationException e) {
-            throw new IsisException(e);
-        } catch (final IllegalAccessException e) {
+        } catch (final InstantiationException | IllegalAccessException e) {
             throw new IsisException(e);
         }
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/runtime/src/main/java/org/apache/isis/core/runtime/services/changes/ChangedObjectsServiceInternal.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/changes/ChangedObjectsServiceInternal.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/changes/ChangedObjectsServiceInternal.java
index fd5b618..8001b6b 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/changes/ChangedObjectsServiceInternal.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/changes/ChangedObjectsServiceInternal.java
@@ -260,6 +260,7 @@ public class ChangedObjectsServiceInternal {
     @Programmatic
     public void clearChangedObjectProperties() {
         enlistedObjectProperties.clear();
+        changedObjectProperties = null;
     }
 
     private static final Predicate<ObjectAdapter> IS_TRANSACTION_ID = new Predicate<ObjectAdapter>() {

http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
index f2eecbd..9cdd8cb 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
@@ -20,6 +20,7 @@ package org.apache.isis.core.runtime.system.persistence;
 
 import java.lang.reflect.Array;
 import java.lang.reflect.Modifier;
+import java.sql.Timestamp;
 import java.text.MessageFormat;
 import java.util.List;
 import java.util.Map;
@@ -29,6 +30,7 @@ import javax.jdo.FetchGroup;
 import javax.jdo.FetchPlan;
 import javax.jdo.PersistenceManager;
 import javax.jdo.PersistenceManagerFactory;
+import javax.jdo.listener.InstanceLifecycleListener;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -38,15 +40,26 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.isis.applib.RecoverableException;
+import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.applib.profiles.Localization;
 import org.apache.isis.applib.query.Query;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.bookmark.BookmarkService2;
+import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.command.Command2;
+import org.apache.isis.applib.services.command.Command3;
+import org.apache.isis.applib.services.command.CommandContext;
+import org.apache.isis.applib.services.command.spi.CommandService;
 import org.apache.isis.applib.services.eventbus.AbstractLifecycleEvent;
 import org.apache.isis.applib.services.eventbus.EventBusService;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer2;
+import org.apache.isis.applib.services.factory.FactoryService;
+import org.apache.isis.applib.services.iactn.Interaction;
+import org.apache.isis.applib.services.iactn.InteractionContext;
+import org.apache.isis.applib.services.metrics.MetricsService;
+import org.apache.isis.applib.services.user.UserService;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.components.SessionScopedComponent;
 import org.apache.isis.core.commons.config.IsisConfiguration;
@@ -112,8 +125,8 @@ import org.apache.isis.core.runtime.persistence.objectstore.transaction.Transact
 import org.apache.isis.core.runtime.persistence.query.PersistenceQueryFindAllInstances;
 import org.apache.isis.core.runtime.persistence.query.PersistenceQueryFindUsingApplibQueryDefault;
 import org.apache.isis.core.runtime.runner.opts.OptionHandlerFixtureAbstract;
+import org.apache.isis.core.runtime.services.RequestScopedService;
 import org.apache.isis.core.runtime.services.changes.ChangedObjectsServiceInternal;
-import org.apache.isis.core.runtime.services.metrics.MetricsServiceDefault;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.persistence.adaptermanager.OidAdapterHashMap;
 import org.apache.isis.core.runtime.system.persistence.adaptermanager.PojoAdapterHashMap;
@@ -176,6 +189,20 @@ public class PersistenceSession implements
     private final AuthenticationSession authenticationSession;
 
     private final ServicesInjector servicesInjector;
+
+    private final CommandContext commandContext;
+    private final CommandService commandService;
+
+    private final InteractionContext interactionContext;
+    private final EventBusService eventBusService ;
+    private final ChangedObjectsServiceInternal changedObjectsServiceInternal;
+    private final FactoryService factoryService;
+    private final MetricsService metricsService;
+    private final ClockService clockService;
+    private final UserService userService;
+    private final Bulk.InteractionContext bulkInteractionContext;
+
+
     /**
      * Used to create the {@link #persistenceManager} when {@link #open()}ed.
      */
@@ -196,7 +223,6 @@ public class PersistenceSession implements
      */
     private final Map<Class<?>, PersistenceQueryProcessor<?>> persistenceQueryProcessorByClass = Maps.newHashMap();
 
-    private final Map<ObjectSpecId, RootOid> registeredServices = Maps.newHashMap();
 
     private final boolean concurrencyCheckingGloballyEnabled;
 
@@ -217,21 +243,32 @@ public class PersistenceSession implements
             LOG.debug("creating " + this);
         }
 
+        this.servicesInjector = servicesInjector;
+        this.jdoPersistenceManagerFactory = jdoPersistenceManagerFactory;
+        this.fixturesInstalledFlag = fixturesInstalledFlag;
+
         // injected
         this.configuration = configuration;
         this.specificationLoader = specificationLoader;
         this.authenticationSession = authenticationSession;
-        this.fixturesInstalledFlag = fixturesInstalledFlag;
 
-        this.servicesInjector = servicesInjector;
-        this.jdoPersistenceManagerFactory = jdoPersistenceManagerFactory;
+        this.commandContext = lookupService(CommandContext.class);
+        this.commandService = lookupService(CommandService.class);
+        this.interactionContext = lookupService(InteractionContext.class);
+        this.eventBusService = lookupService(EventBusService.class);
+        this.changedObjectsServiceInternal = lookupService(ChangedObjectsServiceInternal.class);
+        this.metricsService = lookupService(MetricsService.class);
+        this.factoryService = lookupService(FactoryService.class);
+        this.clockService = lookupService(ClockService.class);
+        this.userService = lookupService(UserService.class);
+        this.bulkInteractionContext = lookupService(Bulk.InteractionContext.class);
 
         // sub-components
         final AdapterManager adapterManager = this;
         this.persistenceQueryFactory = new PersistenceQueryFactory(adapterManager, specificationLoader);
         this.transactionManager = new IsisTransactionManager(this, servicesInjector);
 
-        setState(State.NOT_INITIALIZED);
+        this.state = State.NOT_INITIALIZED;
 
         final boolean concurrencyCheckingGloballyDisabled =
                 configuration.getBoolean("isis.persistor.disableConcurrencyChecking", false);
@@ -285,39 +322,86 @@ public class PersistenceSession implements
                 new PersistenceQueryFindUsingApplibQueryProcessor(this));
 
         initServices();
+        startRequestOnRequestScopedServices();
+
+        if(metricsService instanceof InstanceLifecycleListener) {
+            final InstanceLifecycleListener metricsService = (InstanceLifecycleListener) this.metricsService;
+            persistenceManager.addInstanceLifecycleListener(metricsService, (Class[]) null);
+        }
+
+
+        final Command command = createCommand();
+        final UUID transactionId = UUID.randomUUID();
+        final Interaction interaction = factoryService.instantiate(Interaction.class);
+
+        final Timestamp timestamp = clockService.nowAsJavaSqlTimestamp();
+        final String userName = userService.getUser().getName();
+
+        command.setTimestamp(timestamp);
+        command.setUser(userName);
+        command.setTransactionId(transactionId);
+
+        interaction.setTransactionId(transactionId);
 
-        final MetricsServiceDefault metricsServiceDefault = servicesInjector.lookupService(MetricsServiceDefault.class);
-        persistenceManager.addInstanceLifecycleListener(metricsServiceDefault, (Class[])null);
+        commandContext.setCommand(command);
+        interactionContext.setInteraction(interaction);
 
-        setState(State.OPEN);
+        Bulk.InteractionContext.current.set(bulkInteractionContext);
+
+        this.state = State.OPEN;
     }
 
 
+
+    private void startRequestOnRequestScopedServices() {
+
+        final List<Object> registeredServices = servicesInjector.getRegisteredServices();
+
+        // tell the proxy of all request-scoped services to instantiate the underlying
+        // services, store onto the thread-local and inject into them...
+        for (final Object service : registeredServices) {
+            if(service instanceof RequestScopedService) {
+                ((RequestScopedService)service).__isis_startRequest(servicesInjector);
+            }
+        }
+        // ... and invoke all @PostConstruct
+        for (final Object service : registeredServices) {
+            if(service instanceof RequestScopedService) {
+                ((RequestScopedService)service).__isis_postConstruct();
+            }
+        }
+    }
+
     /**
-     * Creates {@link ObjectAdapter adapters} for the service list.
+     * Creates {@link ObjectAdapter adapters} for the service list, ensuring that these are mapped correctly,
+     * and have the same OIDs as in any previous sessions.
      */
     private void initServices() {
         final List<Object> registeredServices = servicesInjector.getRegisteredServices();
+
         for (final Object service : registeredServices) {
             final ObjectSpecification serviceSpecification =
                     specificationLoader.loadSpecification(service.getClass());
             serviceSpecification.markAsService();
-            final RootOid existingOid = getOidForService(serviceSpecification);
-            final ObjectAdapter serviceAdapter =
-                    existingOid == null
-                            ? adapterFor(service)
-                            : mapRecreatedPojo(existingOid, service);
-            if (serviceAdapter.getOid().isTransient()) {
-                remapAsPersistent(serviceAdapter, null);
-            }
 
-            if (existingOid == null) {
-                final RootOid persistentOid = (RootOid) serviceAdapter.getOid();
-                this.registeredServices.put(persistentOid.getObjectSpecId(), persistentOid);
-            }
+            final ObjectAdapter serviceAdapter = adapterFor(service);
+            remapAsPersistentIfRequired(serviceAdapter);
         }
     }
 
+    private void remapAsPersistentIfRequired(final ObjectAdapter serviceAdapter) {
+        if (serviceAdapter.getOid().isTransient()) {
+            remapAsPersistent(serviceAdapter, null);
+        }
+    }
+
+    private Command createCommand() {
+        final Command command = commandService.create();
+
+        servicesInjector.injectServicesInto(command);
+        return command;
+    }
+
     //endregion
 
     //region > close
@@ -335,11 +419,18 @@ public class PersistenceSession implements
      */
     public void close() {
 
-        if (getState() == State.CLOSED) {
+        if (state == State.CLOSED) {
             // nothing to do
             return;
         }
 
+        completeCommandFromInteractionAndClearDomainEvents();
+        transactionManager.flushTransaction();
+
+        Bulk.InteractionContext.current.set(null);
+
+        endRequestOnRequestScopeServices();
+
         try {
             final IsisTransaction currentTransaction = transactionManager.getTransaction();
             if (currentTransaction != null && !currentTransaction.getState().isComplete()) {
@@ -361,8 +452,6 @@ public class PersistenceSession implements
             LOG.error(
                 "close: failed to close JDO persistenceManager; continuing to avoid memory leakage");
         }
-        // TODO: REVIEW ... ??? this is a guess: don't set to null, because we need for -> transactionManager -> transaction -> messageBroker
-        // persistenceManager = null;
 
         try {
             oidAdapterMap.close();
@@ -378,9 +467,66 @@ public class PersistenceSession implements
             LOG.error("close: pojoAdapterMap#close() failed; continuing to avoid memory leakage");
         }
 
-        setState(State.CLOSED);
+        this.state = State.CLOSED;
+    }
+
+    private void endRequestOnRequestScopeServices() {
+        // tell the proxy of all request-scoped services to invoke @PreDestroy
+        // (if any) on all underlying services stored on their thread-locals...
+        for (final Object service : servicesInjector.getRegisteredServices()) {
+            if(service instanceof RequestScopedService) {
+                ((RequestScopedService)service).__isis_preDestroy();
+            }
+        }
+
+        // ... and then remove those underlying services from the thread-local
+        for (final Object service : servicesInjector.getRegisteredServices()) {
+            if(service instanceof RequestScopedService) {
+                ((RequestScopedService)service).__isis_endRequest();
+            }
+        }
+    }
+
+    private void completeCommandFromInteractionAndClearDomainEvents() {
+
+        final Command command = commandContext.getCommand();
+        final Interaction interaction = interactionContext.getInteraction();
+
+        if(command.getStartedAt() != null && command.getCompletedAt() == null) {
+            // the guard is in case we're here as the result of a redirect following a previous exception;just ignore.
+
+
+            // copy over from the most recent (which will be the top-level) interaction
+            Interaction.Execution priorExecution = interaction.getPriorExecution();
+            final Timestamp completedAt = priorExecution.getCompletedAt();
+            command.setCompletedAt(completedAt);
+        }
+
+        // ensureCommandsPersistedIfDirtyXactn
+
+        // ensure that any changed objects means that the command should be persisted
+        if(command.getMemberIdentifier() != null) {
+            if(metricsService.numberObjectsDirtied() > 0) {
+                command.setPersistHint(true);
+            }
+        }
+
+
+        commandService.complete(command);
+
+        if(command instanceof Command3) {
+            final Command3 command3 = (Command3) command;
+            command3.flushActionDomainEvents();
+        } else
+        if(command instanceof Command2) {
+            final Command2 command2 = (Command2) command;
+            command2.flushActionInteractionEvents();
+        }
+
+        interaction.clear();
     }
 
+
     //endregion
 
     //region > QuerySubmitter impl, findInstancesInTransaction
@@ -484,16 +630,8 @@ public class PersistenceSession implements
 
     private State state;
 
-    private State getState() {
-        return state;
-    }
-    
-    private void setState(final State state) {
-        this.state = state;
-    }
-    
     protected void ensureNotOpened() {
-        if (getState() != State.NOT_INITIALIZED) {
+        if (state != State.NOT_INITIALIZED) {
             throw new IllegalStateException("Persistence session has already been initialized");
         }
     }
@@ -510,7 +648,6 @@ public class PersistenceSession implements
     }
 
 
-
     //endregion
 
     //region > createTransientInstance, createViewModelInstance
@@ -657,31 +794,15 @@ public class PersistenceSession implements
         final List<Object> services = servicesInjector.getRegisteredServices();
         final List<ObjectAdapter> serviceAdapters = Lists.newArrayList();
         for (final Object servicePojo : services) {
-            serviceAdapters.add(getService(servicePojo));
+            ObjectAdapter serviceAdapter = getAdapterFor(servicePojo);
+            if(serviceAdapter == null) {
+                throw new IllegalStateException("ObjectAdapter for service " + servicePojo + " does not exist?!?");
+            }
+            serviceAdapters.add(serviceAdapter);
         }
         return serviceAdapters;
     }
 
-    private ObjectAdapter getService(final Object servicePojo) {
-        final ObjectSpecification serviceSpecification =
-                specificationLoader.loadSpecification(servicePojo.getClass());
-        final RootOid oid = getOidForService(serviceSpecification);
-        final ObjectAdapter serviceAdapter = mapRecreatedPojo(oid, servicePojo);
-
-        return serviceAdapter;
-    }
-
-    /**
-     * Returns the OID for the adapted service. This allows a service object to
-     * be given the same OID that it had when it was created in a different
-     * session.
-     */
-    private RootOid getOidForService(final ObjectSpecification serviceSpec) {
-        final ObjectSpecId serviceSpecId = serviceSpec.getSpecId();
-        final RootOid oid = this.registeredServices.get(serviceSpecId);
-        return oid;
-    }
-
     //endregion
 
     //region > helper: postEvent
@@ -699,7 +820,6 @@ public class PersistenceSession implements
     }
 
     void postEvent(final AbstractLifecycleEvent<Object> event, final Object pojo) {
-        final EventBusService eventBusService = getServicesInjector().lookupService(EventBusService.class);
         event.setSource(pojo);
         eventBusService.post(event);
     }
@@ -851,7 +971,8 @@ public class PersistenceSession implements
             result = persistenceManager.getObjectById(cls, jdoObjectId);
         } catch (final RuntimeException e) {
 
-            final List<ExceptionRecognizer> exceptionRecognizers = getServicesInjector().lookupServices(ExceptionRecognizer.class);
+            Class<ExceptionRecognizer> serviceClass = ExceptionRecognizer.class;
+            final List<ExceptionRecognizer> exceptionRecognizers = lookupServices(serviceClass);
             for (ExceptionRecognizer exceptionRecognizer : exceptionRecognizers) {
                 if(exceptionRecognizer instanceof ExceptionRecognizer2) {
                     final ExceptionRecognizer2 recognizer = (ExceptionRecognizer2) exceptionRecognizer;
@@ -1967,9 +2088,6 @@ public class PersistenceSession implements
     public void enlistDeletingAndInvokeIsisRemovingCallbackFacet(final Persistable pojo) {
         ObjectAdapter adapter = adapterFor(pojo);
 
-        final ChangedObjectsServiceInternal changedObjectsServiceInternal =
-                getServicesInjector().lookupService(ChangedObjectsServiceInternal.class);
-
         changedObjectsServiceInternal.enlistDeleting(adapter);
 
         CallbackFacet.Util.callCallback(adapter, RemovingCallbackFacet.class);
@@ -2159,10 +2277,6 @@ public class PersistenceSession implements
             CallbackFacet.Util.callCallback(adapter, PersistedCallbackFacet.class);
             postLifecycleEventIfRequired(adapter, PersistedLifecycleEventFacet.class);
 
-
-            final ChangedObjectsServiceInternal changedObjectsServiceInternal =
-                    getServicesInjector().lookupService(ChangedObjectsServiceInternal.class);
-
             changedObjectsServiceInternal.enlistCreated(adapter);
 
         } else {
@@ -2207,10 +2321,6 @@ public class PersistenceSession implements
         CallbackFacet.Util.callCallback(adapter, UpdatingCallbackFacet.class);
         postLifecycleEventIfRequired(adapter, UpdatingLifecycleEventFacet.class);
 
-
-        final ChangedObjectsServiceInternal changedObjectsServiceInternal =
-                getServicesInjector().lookupService(ChangedObjectsServiceInternal.class);
-
         changedObjectsServiceInternal.enlistUpdating(adapter);
 
         ensureRootObject(pojo);
@@ -2275,6 +2385,25 @@ public class PersistenceSession implements
 
     //endregion
 
+    //region > helpers: lookupService, lookupServices
+
+    private <T> T lookupService(Class<T> serviceType) {
+        T service = lookupServiceIfAny(serviceType);
+        if(service == null) {
+            throw new IllegalStateException("Could not locate service of type '" + serviceType + "'");
+        }
+        return service;
+    }
+
+    private <T> T lookupServiceIfAny(final Class<T> serviceType) {
+        return servicesInjector.lookupService(serviceType);
+    }
+
+    private <T> List<T> lookupServices(final Class<T> serviceClass) {
+        return servicesInjector.lookupServices(serviceClass);
+    }
+    //endregion
+
     //region > toString
 
     @Override
@@ -2285,6 +2414,8 @@ public class PersistenceSession implements
 
     //endregion
 
+
+
 }
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java
index 516bcb6..98535f7 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java
@@ -19,7 +19,6 @@
 
 package org.apache.isis.core.runtime.system.transaction;
 
-import java.sql.Timestamp;
 import java.util.List;
 import java.util.UUID;
 
@@ -28,15 +27,6 @@ import com.google.common.collect.Lists;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.isis.applib.annotation.Bulk;
-import org.apache.isis.applib.services.actinvoc.ActionInvocationContext;
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.Command2;
-import org.apache.isis.applib.services.command.Command3;
-import org.apache.isis.applib.services.command.CommandContext;
-import org.apache.isis.applib.services.command.spi.CommandService;
-import org.apache.isis.applib.services.iactn.Interaction;
-import org.apache.isis.applib.services.iactn.InteractionContext;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.authentication.MessageBroker;
 import org.apache.isis.core.commons.components.TransactionScopedComponent;
@@ -137,14 +127,6 @@ public class IsisTransaction implements TransactionScopedComponent {
 
 
         /**
-         * Whether it is valid to {@link IsisTransaction#flush() flush} this
-         * {@link IsisTransaction transaction}.
-         */
-        public boolean canFlush() {
-            return this == IN_PROGRESS;
-        }
-
-        /**
          * Whether it is valid to {@link IsisTransaction#commit() commit} this
          * {@link IsisTransaction transaction}.
          */
@@ -177,32 +159,24 @@ public class IsisTransaction implements TransactionScopedComponent {
         }
     }
 
-
     private static final Logger LOG = LoggerFactory.getLogger(IsisTransaction.class);
 
+    //region > constructor, fields
+
     private final List<PersistenceCommand> persistenceCommands = Lists.newArrayList();
     private final IsisTransactionManager transactionManager;
     private final MessageBroker messageBroker;
 
     private final ServicesInjector servicesInjector;
 
-    private final CommandContext commandContext;
-    private final CommandService commandService;
-
-    private final InteractionContext interactionContext;
     private final PublishingServiceInternal publishingServiceInternal;
     private final AuditingServiceInternal auditingServiceInternal;
     private final ChangedObjectsServiceInternal changedObjectsServiceInternal;
 
-
     private final UUID transactionId;
         
-    private State state;
     private IsisException abortCause;
 
-
-
-
     public IsisTransaction(
             final IsisTransactionManager transactionManager,
             final MessageBroker messageBroker,
@@ -217,11 +191,6 @@ public class IsisTransaction implements TransactionScopedComponent {
         this.messageBroker = messageBroker;
         this.servicesInjector = servicesInjector;
         
-        this.commandContext = lookupService(CommandContext.class);
-        this.commandService = lookupService(CommandService.class);
-
-        this.interactionContext = lookupService(InteractionContext.class);
-
         this.publishingServiceInternal = lookupService(PublishingServiceInternal.class);
         this.auditingServiceInternal = lookupService(AuditingServiceInternal.class);
         this.changedObjectsServiceInternal = lookupService(ChangedObjectsServiceInternal.class);
@@ -236,19 +205,19 @@ public class IsisTransaction implements TransactionScopedComponent {
         }
     }
 
+    //endregion
 
-    // ////////////////////////////////////////////////////////////////
-    // GUID
-    // ////////////////////////////////////////////////////////////////
+    //region > transactionId
 
     public final UUID getTransactionId() {
         return transactionId;
     }
-    
-    
-    // ////////////////////////////////////////////////////////////////
-    // State
-    // ////////////////////////////////////////////////////////////////
+
+    //endregion
+
+    //region > state
+
+    private State state;
 
     public State getState() {
         return state;
@@ -258,10 +227,10 @@ public class IsisTransaction implements TransactionScopedComponent {
         this.state = state;
     }
 
-    
-    // //////////////////////////////////////////////////////////
-    // Commands
-    // //////////////////////////////////////////////////////////
+    //endregion
+
+    //region > commands
+
 
     /**
      * Add the non-null command to the list of commands to execute at the end of
@@ -298,11 +267,41 @@ public class IsisTransaction implements TransactionScopedComponent {
         persistenceCommands.add(command);
     }
 
+    private boolean alreadyHasCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
+        return getCommand(commandClass, onObject) != null;
+    }
+
+    private boolean alreadyHasCreate(final ObjectAdapter onObject) {
+        return alreadyHasCommand(CreateObjectCommand.class, onObject);
+    }
+
+    private boolean alreadyHasDestroy(final ObjectAdapter onObject) {
+        return alreadyHasCommand(DestroyObjectCommand.class, onObject);
+    }
+
+    private PersistenceCommand getCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
+        for (final PersistenceCommand command : persistenceCommands) {
+            if (command.onAdapter().equals(onObject)) {
+                if (commandClass.isAssignableFrom(command.getClass())) {
+                    return command;
+                }
+            }
+        }
+        return null;
+    }
+
+    private void removeCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
+        final PersistenceCommand toDelete = getCommand(commandClass, onObject);
+        persistenceCommands.remove(toDelete);
+    }
 
+    private void removeCreate(final ObjectAdapter onObject) {
+        removeCommand(CreateObjectCommand.class, onObject);
+    }
 
-    // ////////////////////////////////////////////////////////////////
-    // flush
-    // ////////////////////////////////////////////////////////////////
+    //endregion
+
+    //region > flush
 
     public synchronized final void flush() {
 
@@ -382,10 +381,9 @@ public class IsisTransaction implements TransactionScopedComponent {
         
     }
 
+    //endregion
 
-    // ////////////////////////////////////////////////////////////////
-    // preCommit, commit
-    // ////////////////////////////////////////////////////////////////
+    //region > preCommit, commit
 
     synchronized void preCommit() {
         ensureThatState(getState().canCommit(), is(true), "state is: " + getState());
@@ -403,68 +401,20 @@ public class IsisTransaction implements TransactionScopedComponent {
         }
 
         try {
-            // ensureCommandsPersistedIfDirtyXactn
-            final Command command = commandContext.getCommand();
-
-            // ensure that any changed objects means that the command should be persisted
-            final boolean hasChangedAdapters = changedObjectsServiceInternal.hasChangedAdapters();
-            if(hasChangedAdapters && command.getMemberIdentifier() != null) {
-                command.setPersistHint(true);
-            }
-
             auditingServiceInternal.audit();
 
             publishingServiceInternal.publishObjects();
             doFlush();
 
-            final ActionInvocationContext actionInvocationContext = lookupService(ActionInvocationContext.class);
-            if(actionInvocationContext != null) {
-                Bulk.InteractionContext.current.set(null);
-            }
-
-            completeCommandAndInteractionAndClearDomainEvents();
-            doFlush();
-
 
         } catch (final RuntimeException ex) {
             setAbortCause(new IsisTransactionManagerException(ex));
-            completeCommandAndInteractionAndClearDomainEvents();
             throw ex;
         } finally {
             changedObjectsServiceInternal.clearChangedObjectProperties();
         }
     }
 
-    private void completeCommandAndInteractionAndClearDomainEvents() {
-
-        final Command command = commandContext.getCommand();
-        final Interaction interaction = interactionContext.getInteraction();
-
-        if(command.getStartedAt() != null && command.getCompletedAt() == null) {
-            // the guard is in case we're here as the result of a redirect following a previous exception;just ignore.
-
-            // copy over from the most recent interaction
-            Interaction.Execution priorExecution = interaction.getPriorExecution();
-            final Timestamp completedAt = priorExecution.getCompletedAt();
-            command.setCompletedAt(completedAt);
-        }
-
-        commandService.complete(command);
-
-        if(command instanceof Command3) {
-            final Command3 command3 = (Command3) command;
-            command3.flushActionDomainEvents();
-        } else
-        if(command instanceof Command2) {
-            final Command2 command2 = (Command2) command;
-            command2.flushActionInteractionEvents();
-        }
-
-        interaction.clear();
-    }
-
-
-    // ////////////////////////////////////////////////////////////////
 
     public synchronized void commit() {
         ensureThatState(getState().canCommit(), is(true), "state is: " + getState());
@@ -485,12 +435,14 @@ public class IsisTransaction implements TransactionScopedComponent {
     }
 
 
-    
-    // ////////////////////////////////////////////////////////////////
-    // markAsAborted
-    // ////////////////////////////////////////////////////////////////
+    //endregion
 
-    public synchronized final void markAsAborted() {
+    //region > abortCause, markAsAborted
+
+    /**
+     * internal API called by IsisTransactionManager only
+     */
+    synchronized final void markAsAborted() {
         ensureThatState(getState().canAbort(), is(true), "state is: " + getState());
         if (LOG.isInfoEnabled()) {
             LOG.info("abort transaction " + this);
@@ -499,12 +451,6 @@ public class IsisTransaction implements TransactionScopedComponent {
         setState(State.ABORTED);
     }
 
-    
-    
-    /////////////////////////////////////////////////////////////////////////
-    // handle exceptions on load, flush or commit
-    /////////////////////////////////////////////////////////////////////////
-
 
     /**
      * Indicate that the transaction must be aborted, and that there is
@@ -532,63 +478,25 @@ public class IsisTransaction implements TransactionScopedComponent {
         abortCause = null;
     }
 
-    
-    // //////////////////////////////////////////////////////////
-    // Helpers
-    // //////////////////////////////////////////////////////////
 
-    private boolean alreadyHasCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
-        return getCommand(commandClass, onObject) != null;
-    }
+    //endregion
 
-    private boolean alreadyHasCreate(final ObjectAdapter onObject) {
-        return alreadyHasCommand(CreateObjectCommand.class, onObject);
-    }
-
-    private boolean alreadyHasDestroy(final ObjectAdapter onObject) {
-        return alreadyHasCommand(DestroyObjectCommand.class, onObject);
-    }
-
-    private PersistenceCommand getCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
-        for (final PersistenceCommand command : persistenceCommands) {
-            if (command.onAdapter().equals(onObject)) {
-                if (commandClass.isAssignableFrom(command.getClass())) {
-                    return command;
-                }
-            }
-        }
-        return null;
-    }
-
-    private void removeCommand(final Class<?> commandClass, final ObjectAdapter onObject) {
-        final PersistenceCommand toDelete = getCommand(commandClass, onObject);
-        persistenceCommands.remove(toDelete);
-    }
-
-    private void removeCreate(final ObjectAdapter onObject) {
-        removeCommand(CreateObjectCommand.class, onObject);
-    }
-
-    // ////////////////////////////////////////////////////////////////
-    // toString
-    // ////////////////////////////////////////////////////////////////
+    //region > toString
 
     @Override
     public String toString() {
         return appendTo(new ToString(this)).toString();
     }
 
-    protected ToString appendTo(final ToString str) {
+    private ToString appendTo(final ToString str) {
         str.append("state", state);
         str.append("commands", persistenceCommands.size());
         return str;
     }
 
+    //endregion
 
-    // ////////////////////////////////////////////////////////////////
-    // Depenendencies (from constructor)
-    // ////////////////////////////////////////////////////////////////
-
+    //region > getMessageBroker
 
     /**
      * The {@link org.apache.isis.core.commons.authentication.MessageBroker} for this transaction.
@@ -602,11 +510,9 @@ public class IsisTransaction implements TransactionScopedComponent {
         return messageBroker;
     }
 
+    //endregion
 
-    ////////////////////////////////////////////////////////////////////////
-    // Dependencies (lookup)
-    ////////////////////////////////////////////////////////////////////////
-
+    //region > helpers: lookupService etc
     private <T> T lookupService(Class<T> serviceType) {
         T service = lookupServiceIfAny(serviceType);
         if(service == null) {
@@ -618,4 +524,9 @@ public class IsisTransaction implements TransactionScopedComponent {
     private <T> T lookupServiceIfAny(final Class<T> serviceType) {
         return servicesInjector.lookupService(serviceType);
     }
+
+    //endregion
+
 }
+
+

http://git-wip-us.apache.org/repos/asf/isis/blob/21b27fe4/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java
index deb0072..6589cb0 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java
@@ -19,22 +19,16 @@
 
 package org.apache.isis.core.runtime.system.transaction;
 
-import java.sql.Timestamp;
-import java.util.List;
 import java.util.UUID;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.isis.applib.annotation.Bulk;
-import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandContext;
 import org.apache.isis.applib.services.command.spi.CommandService;
-import org.apache.isis.applib.services.factory.FactoryService;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactn.InteractionContext;
-import org.apache.isis.applib.services.user.UserService;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.authentication.MessageBroker;
 import org.apache.isis.core.commons.components.SessionScopedComponent;
@@ -42,7 +36,6 @@ import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.metamodel.adapter.oid.OidMarshaller;
 import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommand;
-import org.apache.isis.core.runtime.services.RequestScopedService;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.runtime.system.session.IsisSession;
@@ -68,15 +61,9 @@ public class IsisTransactionManager implements SessionScopedComponent {
 
     private final ServicesInjector servicesInjector;
 
-    private final FactoryService factoryService;
     private final CommandContext commandContext;
-    private final CommandService commandService;
-
     private final InteractionContext interactionContext;
 
-    private final ClockService clockService;
-    private final UserService userService;
-
 
     // ////////////////////////////////////////////////////////////////
     // constructor
@@ -89,14 +76,8 @@ public class IsisTransactionManager implements SessionScopedComponent {
         this.persistenceSession = persistenceSession;
         this.servicesInjector = servicesInjector;
 
-        this.factoryService = lookupService(FactoryService.class);
         this.commandContext = lookupService(CommandContext.class);
-        this.commandService = lookupService(CommandService.class);
-
         this.interactionContext = lookupService(InteractionContext.class);
-
-        this.clockService = lookupService(ClockService.class);
-        this.userService = lookupService(UserService.class);
     }
 
     public PersistenceSession getPersistenceSession() {
@@ -262,40 +243,29 @@ public class IsisTransactionManager implements SessionScopedComponent {
         if (getTransaction() == null || getTransaction().getState().isComplete()) {
             noneInProgress = true;
 
-            startRequestOnRequestScopedServices();
+            // previously we called __isis_startRequest here on all RequestScopedServices.  This is now
+            // done earlier, in PersistenceSession#open(). If we introduce support for @TransactionScoped
+            // services, then this would be the place to initialize them.
 
-            // note that at this point there may not be an EventBusService initialized.  The PersistenceSession has
-            // logic to suppress the posting of the ObjectCreatedEvent for the special case of Command objects.
 
-            final Command command;
-            final UUID transactionId;
+            // allow the command to be overridden (if running as a background command with a parent command supplied)
+
+            final Interaction interaction = interactionContext.getInteraction();
 
+            final Command command;
             if (existingCommandIfAny != null) {
-                command = existingCommandIfAny;
-                transactionId = command.getTransactionId();
-            }
-            else {
-                command = createCommand();
-                transactionId = UUID.randomUUID();
+                commandContext.setCommand(existingCommandIfAny);
+                interaction.setTransactionId(existingCommandIfAny.getTransactionId());
             }
-            final Interaction interaction = factoryService.instantiate(Interaction.class);
-
-            initCommandAndInteraction(transactionId, command, interaction);
+            command = commandContext.getCommand();
+            final UUID transactionId = command.getTransactionId();
 
-            commandContext.setCommand(command);
-            interactionContext.setInteraction(interaction);
-
-            initOtherApplibServicesIfConfigured();
 
             final MessageBroker messageBroker = MessageBroker.acquire(getAuthenticationSession());
             this.transaction = new IsisTransaction(this, messageBroker, servicesInjector, transactionId);
             transactionLevel = 0;
 
             persistenceSession.startTransaction();
-
-            // a no-op; the command will have been populated already
-            // in the earlier call to #createCommandAndInitAndSetAsContext(...).
-            commandService.startTransaction(command, transactionId);
         }
 
         transactionLevel++;
@@ -305,80 +275,6 @@ public class IsisTransactionManager implements SessionScopedComponent {
         }
     }
 
-    private void initOtherApplibServicesIfConfigured() {
-        
-        final Bulk.InteractionContext bic = lookupServiceIfAny(Bulk.InteractionContext.class);
-        if(bic != null) {
-            Bulk.InteractionContext.current.set(bic);
-        }
-    }
-
-    private void startRequestOnRequestScopedServices() {
-
-        final List<Object> registeredServices = servicesInjector.getRegisteredServices();
-
-        // tell the proxy of all request-scoped services to instantiate the underlying
-        // services, store onto the thread-local and inject into them...
-        for (final Object service : registeredServices) {
-            if(service instanceof RequestScopedService) {
-                ((RequestScopedService)service).__isis_startRequest(servicesInjector);
-            }
-        }
-        // ... and invoke all @PostConstruct
-        for (final Object service : registeredServices) {
-            if(service instanceof RequestScopedService) {
-                ((RequestScopedService)service).__isis_postConstruct();
-            }
-        }
-    }
-
-    private void endRequestOnRequestScopeServices() {
-        // tell the proxy of all request-scoped services to invoke @PreDestroy
-        // (if any) on all underlying services stored on their thread-locals...
-        for (final Object service : servicesInjector.getRegisteredServices()) {
-            if(service instanceof RequestScopedService) {
-                ((RequestScopedService)service).__isis_preDestroy();
-            }
-        }
-
-        // ... and then remove those underlying services from the thread-local
-        for (final Object service : servicesInjector.getRegisteredServices()) {
-            if(service instanceof RequestScopedService) {
-                ((RequestScopedService)service).__isis_endRequest();
-            }
-        }
-    }
-
-    private Command createCommand() {
-        final Command command = commandService.create();
-
-        servicesInjector.injectServicesInto(command);
-        return command;
-    }
-
-    /**
-     * Sets up {@link Command#getTransactionId()}, {@link Command#getUser()} and {@link Command#getTimestamp()}.
-     *
-     * The remaining properties are set further down the call-stack, if an action is actually performed
-     * @param transactionId
-     * @param interaction
-     */
-    private void initCommandAndInteraction(
-            final UUID transactionId,
-            final Command command,
-            final Interaction interaction) {
-
-        final Timestamp timestamp = clockService.nowAsJavaSqlTimestamp();
-        final String userName = userService.getUser().getName();
-
-        command.setTimestamp(timestamp);
-        command.setUser(userName);
-        command.setTransactionId(transactionId);
-
-        interaction.setTransactionId(transactionId);
-    }
-
-
     // //////////////////////////////////////////////////////
     // flush
     // //////////////////////////////////////////////////////
@@ -498,9 +394,11 @@ public class IsisTransactionManager implements SessionScopedComponent {
                     transactionLevel = 1; // because the transactionLevel was decremented earlier
                 }
             }
-            
-            
-            endRequestOnRequestScopeServices();
+
+
+            // previously we called __isis_endRequest here on all RequestScopedServices.  This is now
+            // done later, in PersistenceSession#close(). If we introduce support for @TransactionScoped
+            // services, then this would be the place to finalize them.
 
             if(abortCause != null) {