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:16 UTC

[1/2] isis git commit: ISIS-1414: removing 'numberOfPropertiesModified' from ixn.xsd and MetricsService; this is xactn-scoped information, not request-scoped. Also introduced WithTransactionScoped as a means to indicate which of the request-scoped mem

Repository: isis
Updated Branches:
  refs/heads/master 0d327212a -> ad9cec42c


ISIS-1414: removing 'numberOfPropertiesModified' from ixn.xsd and MetricsService; this is xactn-scoped information, not request-scoped.    Also introduced WithTransactionScoped as a means to indicate which of the request-scoped members are really transaction-scoped.


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

Branch: refs/heads/master
Commit: ad9cec42cb3828f2f9c4d43c62bd787ccff94d81
Parents: 21b27fe
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Thu May 26 17:25:46 2016 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Thu May 26 17:26:54 2016 +0100

----------------------------------------------------------------------
 .../main/asciidoc/guides/_rgcms_schema-ixn.adoc |  7 +--
 .../src/main/asciidoc/schema/ixn/ixn-1.0.xsd    |  6 ---
 .../src/main/asciidoc/schema/ixn/ixn.xsd        |  6 ---
 core/applib/pom.xml                             |  4 +-
 .../isis/applib/services/iactn/Interaction.java | 20 +++------
 .../applib/services/metrics/MetricsService.java | 13 ------
 .../schema/utils/MemberExecutionDtoUtils.java   |  8 ----
 core/pom.xml                                    |  5 ---
 .../changes/ChangedObjectsServiceInternal.java  | 45 ++++++++++----------
 .../services/metrics/MetricsServiceDefault.java | 18 +++++---
 .../PublishingServiceInternalDefault.java       |  2 +-
 .../system/transaction/IsisTransaction.java     |  9 +++-
 .../transaction/WithTransactionScope.java       | 27 ++++++++++++
 .../service/support/TimestampService.java       |  8 ++--
 .../org/apache/isis/schema/ixn/ixn-1.0.xsd      |  6 ---
 15 files changed, 81 insertions(+), 103 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/adocs/documentation/src/main/asciidoc/guides/_rgcms_schema-ixn.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_rgcms_schema-ixn.adoc b/adocs/documentation/src/main/asciidoc/guides/_rgcms_schema-ixn.adoc
index 6acacd0..6aa0e94 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_rgcms_schema-ixn.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_rgcms_schema-ixn.adoc
@@ -187,8 +187,6 @@ The schema also defines a small number of supporting types:
         <xs:sequence>
             <xs:element name="loaded" type="com:differenceDto"/>
             <xs:element name="dirtied" type="com:differenceDto"/>
-            <xs:element name="propertiesModified"
-                        type="com:differenceDto"/>
         </xs:sequence>
     </xs:complexType>
 
@@ -203,9 +201,8 @@ The schema also defines a small number of supporting types:
 ----
 <1> the `metricsDto` captures the time to perform an execution, and also the differences in various object counts.
 <2> the `objectCountsDto` complex type is the set of before/after differences, one for each execution; the framework
-tracks number of objects loaded (read from) the database, the number of objects dirtied (will need to be saved back
-to the database), and the number of properties across all objects that changed.  Together these metrics give an idea of
-the "size" of this  particular execution.
+tracks number of objects loaded (read from) the database and the number of objects dirtied (will need to be saved back
+to the database).  Together these metrics give an idea of the "size" of this  particular execution.
 <3> the `exceptionDto` complex type defines a structure for capturing the stack trace of any exception that might occur
 in the course of invoking an action or editing a property.
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/adocs/documentation/src/main/asciidoc/schema/ixn/ixn-1.0.xsd
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/schema/ixn/ixn-1.0.xsd b/adocs/documentation/src/main/asciidoc/schema/ixn/ixn-1.0.xsd
index 3527234..77a733e 100644
--- a/adocs/documentation/src/main/asciidoc/schema/ixn/ixn-1.0.xsd
+++ b/adocs/documentation/src/main/asciidoc/schema/ixn/ixn-1.0.xsd
@@ -197,12 +197,6 @@
                     </xs:documentation>
                 </xs:annotation>
             </xs:element>
-            <xs:element name="propertiesModified" type="com:differenceDto">
-                <xs:annotation>
-                    <xs:documentation>The number of individual properties of objects that were modified (each such change would correspond to a separate call to AuditingService if configured).
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
         </xs:sequence>
 
     </xs:complexType>

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/adocs/documentation/src/main/asciidoc/schema/ixn/ixn.xsd
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/schema/ixn/ixn.xsd b/adocs/documentation/src/main/asciidoc/schema/ixn/ixn.xsd
index 3527234..77a733e 100644
--- a/adocs/documentation/src/main/asciidoc/schema/ixn/ixn.xsd
+++ b/adocs/documentation/src/main/asciidoc/schema/ixn/ixn.xsd
@@ -197,12 +197,6 @@
                     </xs:documentation>
                 </xs:annotation>
             </xs:element>
-            <xs:element name="propertiesModified" type="com:differenceDto">
-                <xs:annotation>
-                    <xs:documentation>The number of individual properties of objects that were modified (each such change would correspond to a separate call to AuditingService if configured).
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
         </xs:sequence>
 
     </xs:complexType>

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/core/applib/pom.xml
----------------------------------------------------------------------
diff --git a/core/applib/pom.xml b/core/applib/pom.xml
index a38461c..27c2239 100644
--- a/core/applib/pom.xml
+++ b/core/applib/pom.xml
@@ -102,8 +102,8 @@
             <artifactId>validation-api</artifactId>
         </dependency>
         <dependency>
-            <groupId>javax.transaction</groupId>
-            <artifactId>transaction-api</artifactId>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-jta_1.1_spec</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.geronimo.specs</groupId>

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/core/applib/src/main/java/org/apache/isis/applib/services/iactn/Interaction.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/iactn/Interaction.java b/core/applib/src/main/java/org/apache/isis/applib/services/iactn/Interaction.java
index dbf7083..5a70c18 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/iactn/Interaction.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/iactn/Interaction.java
@@ -549,8 +549,7 @@ public class Interaction implements HasTransactionId {
                         final Execution<?, ?> execution,
                         final Timestamp timestamp,
                         final int numberObjectsLoaded,
-                        final int numberObjectsDirtied,
-                        final int numberObjectPropertiesModified) {
+                        final int numberObjectsDirtied) {
 
                     execution.startedAt = timestamp;
 
@@ -562,7 +561,6 @@ public class Interaction implements HasTransactionId {
                     final ObjectCountsDto objectCountsDto = objectCountsFor(metricsDto);
                     numberObjectsLoadedFor(objectCountsDto).setBefore(numberObjectsLoaded);
                     numberObjectsDirtiedFor(objectCountsDto).setBefore(numberObjectsDirtied);
-                    numberObjectPropertiesModifiedFor(objectCountsDto).setBefore(numberObjectPropertiesModified);
                 }
 
             },
@@ -571,8 +569,7 @@ public class Interaction implements HasTransactionId {
                         final Execution<?, ?> execution,
                         final Timestamp timestamp,
                         final int numberObjectsLoaded,
-                        final int numberObjectsDirtied,
-                        final int numberObjectPropertiesModified) {
+                        final int numberObjectsDirtied) {
 
                     execution.completedAt = timestamp;
 
@@ -584,16 +581,11 @@ public class Interaction implements HasTransactionId {
                     final ObjectCountsDto objectCountsDto = objectCountsFor(metricsDto);
                     numberObjectsLoadedFor(objectCountsDto).setAfter(numberObjectsLoaded);
                     numberObjectsDirtiedFor(objectCountsDto).setAfter(numberObjectsDirtied);
-                    numberObjectPropertiesModifiedFor(objectCountsDto).setAfter(numberObjectPropertiesModified);
-
                 }
 
             };
 
             //region > helpers
-            private static DifferenceDto numberObjectPropertiesModifiedFor(final ObjectCountsDto objectCountsDto) {
-                return MemberExecutionDtoUtils.numberObjectPropertiesModifiedFor(objectCountsDto);
-            }
 
             private static DifferenceDto numberObjectsDirtiedFor(final ObjectCountsDto objectCountsDto) {
                 return MemberExecutionDtoUtils.numberObjectsDirtiedFor(objectCountsDto);
@@ -617,20 +609,18 @@ public class Interaction implements HasTransactionId {
             //endregion
 
             abstract void syncMetrics(
-                    final Execution<?,?> teExecution,
+                    final Execution<?, ?> teExecution,
                     final Timestamp timestamp,
                     final int numberObjectsLoaded,
-                    final int numberObjectsDirtied,
-                    final int numberObjectPropertiesModified);
+                    final int numberObjectsDirtied);
         }
         private void syncMetrics(final When when, final Timestamp timestamp) {
             final MetricsService metricsService = interaction.metricsService;
 
             final int numberObjectsLoaded = metricsService.numberObjectsLoaded();
             final int numberObjectsDirtied = metricsService.numberObjectsDirtied();
-            final int numberObjectPropertiesModified = metricsService.numberObjectPropertiesModified();
 
-            when.syncMetrics(this, timestamp, numberObjectsLoaded, numberObjectsDirtied, numberObjectPropertiesModified);
+            when.syncMetrics(this, timestamp, numberObjectsLoaded, numberObjectsDirtied);
         }
 
         //endregion

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/core/applib/src/main/java/org/apache/isis/applib/services/metrics/MetricsService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/metrics/MetricsService.java b/core/applib/src/main/java/org/apache/isis/applib/services/metrics/MetricsService.java
index 4404418..2460d23 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/metrics/MetricsService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/metrics/MetricsService.java
@@ -61,19 +61,6 @@ public interface MetricsService {
     @Programmatic
     int numberObjectsDirtied();
 
-    /**
-     * The number of individual properties of objects that were modified; a good measure of the amount of work being done in the interaction.
-     * 
-     * <p>
-     *     Related to {@link #numberObjectsDirtied()}, corresponds to the number of times that {@link org.apache.isis.applib.services.audit.AuditingService3#audit(UUID, String, Bookmark, String, String, String, String, String, Timestamp)}  would be called if the transaction were to complete.
-     * </p>
-     * 
-     * <p>
-     *     Is captured within {@link MemberExecutionDto#getMetrics()} (accessible from {@link InteractionContext#getInteraction()}).
-     * </p>
-     */
-    @Programmatic
-    int numberObjectPropertiesModified();
 
 }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/core/applib/src/main/java/org/apache/isis/schema/utils/MemberExecutionDtoUtils.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/schema/utils/MemberExecutionDtoUtils.java b/core/applib/src/main/java/org/apache/isis/schema/utils/MemberExecutionDtoUtils.java
index f1309f5..121ea92 100644
--- a/core/applib/src/main/java/org/apache/isis/schema/utils/MemberExecutionDtoUtils.java
+++ b/core/applib/src/main/java/org/apache/isis/schema/utils/MemberExecutionDtoUtils.java
@@ -110,12 +110,4 @@ public final class MemberExecutionDtoUtils {
         }
         return differenceDto;
     }
-    public static DifferenceDto numberObjectPropertiesModifiedFor(final ObjectCountsDto objectCountsDto) {
-        DifferenceDto differenceDto = objectCountsDto.getPropertiesModified();
-        if(differenceDto == null) {
-            differenceDto = new DifferenceDto();
-            objectCountsDto.setPropertiesModified(differenceDto);
-        }
-        return differenceDto;
-    }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 611c6bb..6564bf4 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -1891,11 +1891,6 @@ ${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/ad9cec42/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 8001b6b..f450729 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
@@ -25,7 +25,6 @@ import java.util.Set;
 import javax.enterprise.context.RequestScoped;
 
 import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
@@ -38,10 +37,11 @@ import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.spec.feature.Contributed;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
+import org.apache.isis.core.runtime.system.transaction.WithTransactionScope;
 
 @DomainService(nature = NatureOfService.DOMAIN)
 @RequestScoped
-public class ChangedObjectsServiceInternal {
+public class ChangedObjectsServiceInternal implements WithTransactionScope {
 
     /**
      * Used for auditing: this contains the pre- values of every property of every object enlisted.
@@ -209,19 +209,9 @@ public class ChangedObjectsServiceInternal {
         return previous == null;
     }
 
-
-    @Programmatic
-    public boolean hasChangedAdapters() {
-        final Set<Map.Entry<AdapterAndProperty, PreAndPostValues>> changedObjectProperties = getChangedObjectProperties();
-
-        final Set<ObjectAdapter> changedAdapters = Sets.newHashSet(
-                        Iterables.transform(
-                                changedObjectProperties,
-                                AdapterAndProperty.Functions.GET_ADAPTER)
-                        );
-        return !changedAdapters.isEmpty();
-    }
-
+    /**
+     * Intended to be called at the end of the transaction.  Use {@link #resetForNextTransaction()} once fully read.
+     */
     @Programmatic
     public Set<Map.Entry<AdapterAndProperty, PreAndPostValues>> getChangedObjectProperties() {
         return changedObjectProperties != null
@@ -257,12 +247,6 @@ public class ChangedObjectsServiceInternal {
                 Sets.filter(processedObjectProperties1.entrySet(), PreAndPostValues.Predicates.CHANGED));
     }
 
-    @Programmatic
-    public void clearChangedObjectProperties() {
-        enlistedObjectProperties.clear();
-        changedObjectProperties = null;
-    }
-
     private static final Predicate<ObjectAdapter> IS_TRANSACTION_ID = new Predicate<ObjectAdapter>() {
         @Override
         public boolean apply(ObjectAdapter input) {
@@ -285,9 +269,26 @@ public class ChangedObjectsServiceInternal {
         return changeKindByEnlistedAdapter.size();
     }
 
+    /**
+     * Must be called only after {@link #getChangedObjectProperties()} has been called at least once.
+     */
     @Programmatic
     public int numberObjectPropertiesModified() {
-        return enlistedObjectProperties.size();
+        if(changedObjectProperties == null) {
+            throw new IllegalStateException("getChangedObjectProperties() has not yet been called");
+        }
+        return changedObjectProperties.size();
+    }
+
+    /**
+     * Intended to be called at the end of a transaction.  (This service really ought to be considered
+     * a transaction-scoped service; since that isn't yet supported by the framework, we have to manually reset).
+     */
+    @Override
+    @Programmatic
+    public void resetForNextTransaction() {
+        enlistedObjectProperties.clear();
+        changedObjectProperties = null;
     }
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/core/runtime/src/main/java/org/apache/isis/core/runtime/services/metrics/MetricsServiceDefault.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/metrics/MetricsServiceDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/metrics/MetricsServiceDefault.java
index f06c81d..604e097 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/metrics/MetricsServiceDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/metrics/MetricsServiceDefault.java
@@ -31,10 +31,11 @@ import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.metrics.MetricsService;
 import org.apache.isis.core.runtime.services.changes.ChangedObjectsServiceInternal;
+import org.apache.isis.core.runtime.system.transaction.WithTransactionScope;
 
 @RequestScoped
 @DomainService(nature = NatureOfService.DOMAIN)
-public class MetricsServiceDefault implements MetricsService, InstanceLifecycleListener, LoadLifecycleListener {
+public class MetricsServiceDefault implements MetricsService, InstanceLifecycleListener, LoadLifecycleListener, WithTransactionScope {
 
     private AtomicInteger numberLoaded = new AtomicInteger(0);
 
@@ -48,20 +49,23 @@ public class MetricsServiceDefault implements MetricsService, InstanceLifecycleL
         return changedObjectsServiceInternal.numberObjectsDirtied();
     }
 
-    @Override
-    public int numberObjectPropertiesModified() {
-        return changedObjectsServiceInternal.numberObjectPropertiesModified();
-    }
-
     @Programmatic
     @Override
     public void postLoad(final InstanceLifecycleEvent event) {
         numberLoaded.incrementAndGet();
     }
 
+    /**
+     * Intended to be called at the end of a transaction.  (This service really ought to be considered
+     * a transaction-scoped service; since that isn't yet supported by the framework, we have to manually reset).
+     */
+    @Programmatic
+    @Override
+    public void resetForNextTransaction() {
+        numberLoaded.set(0);
+    }
 
     @Inject
     ChangedObjectsServiceInternal changedObjectsServiceInternal;
 
-
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/core/runtime/src/main/java/org/apache/isis/core/runtime/services/publish/PublishingServiceInternalDefault.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/publish/PublishingServiceInternalDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/publish/PublishingServiceInternalDefault.java
index 3d570b8..c063506 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/publish/PublishingServiceInternalDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/publish/PublishingServiceInternalDefault.java
@@ -183,7 +183,7 @@ public class PublishingServiceInternalDefault implements PublishingServiceIntern
         }
 
         final int numberLoaded = metricsService.numberObjectsLoaded();
-        final int numberObjectPropertiesModified = metricsService.numberObjectPropertiesModified();
+        final int numberObjectPropertiesModified = changedObjectsServiceInternal.numberObjectPropertiesModified();
         final PublishedObjects publishedObjects = newPublishedObjects(numberLoaded, numberObjectPropertiesModified,
                 changeKindByPublishedAdapter);
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/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 98535f7..c79977b 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
@@ -27,6 +27,7 @@ import com.google.common.collect.Lists;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.isis.applib.services.metrics.MetricsService;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.authentication.MessageBroker;
 import org.apache.isis.core.commons.components.TransactionScopedComponent;
@@ -172,6 +173,7 @@ public class IsisTransaction implements TransactionScopedComponent {
     private final PublishingServiceInternal publishingServiceInternal;
     private final AuditingServiceInternal auditingServiceInternal;
     private final ChangedObjectsServiceInternal changedObjectsServiceInternal;
+    private final MetricsService metricsService;
 
     private final UUID transactionId;
         
@@ -194,7 +196,7 @@ public class IsisTransaction implements TransactionScopedComponent {
         this.publishingServiceInternal = lookupService(PublishingServiceInternal.class);
         this.auditingServiceInternal = lookupService(AuditingServiceInternal.class);
         this.changedObjectsServiceInternal = lookupService(ChangedObjectsServiceInternal.class);
-
+        this.metricsService = lookupService(MetricsService.class);
 
         this.transactionId = transactionId;
 
@@ -411,7 +413,10 @@ public class IsisTransaction implements TransactionScopedComponent {
             setAbortCause(new IsisTransactionManagerException(ex));
             throw ex;
         } finally {
-            changedObjectsServiceInternal.clearChangedObjectProperties();
+            changedObjectsServiceInternal.resetForNextTransaction();
+            if(metricsService instanceof WithTransactionScope) {
+                ((WithTransactionScope) metricsService).resetForNextTransaction();
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/WithTransactionScope.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/WithTransactionScope.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/WithTransactionScope.java
new file mode 100644
index 0000000..c0b156a
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/WithTransactionScope.java
@@ -0,0 +1,27 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.core.runtime.system.transaction;
+
+/**
+ * Hacky workaround since we don't currently support @TransactionScoped.
+ */
+public interface WithTransactionScope {
+    void resetForNextTransaction();
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/core/runtime/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/service/support/TimestampService.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/service/support/TimestampService.java b/core/runtime/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/service/support/TimestampService.java
index fb18cfe..b270f39 100644
--- a/core/runtime/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/service/support/TimestampService.java
+++ b/core/runtime/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/service/support/TimestampService.java
@@ -22,7 +22,6 @@ import javax.enterprise.context.RequestScoped;
 import javax.inject.Inject;
 import javax.jdo.listener.InstanceLifecycleEvent;
 
-import org.apache.isis.applib.DomainObjectContainer;
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.applib.annotation.Programmatic;
@@ -30,6 +29,7 @@ import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.jdosupport.IsisJdoSupport;
 import org.apache.isis.applib.services.timestamp.HoldsUpdatedAt;
 import org.apache.isis.applib.services.timestamp.HoldsUpdatedBy;
+import org.apache.isis.applib.services.user.UserService;
 
 @RequestScoped
 @DomainService(
@@ -54,11 +54,9 @@ public class TimestampService implements
         final Object pi = event.getPersistentInstance();
 
         if(pi instanceof org.datanucleus.enhancement.Persistable) {
-            boolean isPersistent =
-                    ((org.datanucleus.enhancement.Persistable)pi).dnIsPersistent();
 
             if(pi instanceof HoldsUpdatedBy) {
-                ((HoldsUpdatedBy)pi).setUpdatedBy(container.getUser().getName());
+                ((HoldsUpdatedBy)pi).setUpdatedBy(userService.getUser().getName());
             }
             if(pi instanceof HoldsUpdatedAt) {
                 ((HoldsUpdatedAt)pi).setUpdatedAt(clockService.nowAsJavaSqlTimestamp());
@@ -72,7 +70,7 @@ public class TimestampService implements
     }
 
     @Inject
-    DomainObjectContainer container;
+    UserService userService;
 
     @Inject
     ClockService clockService;

http://git-wip-us.apache.org/repos/asf/isis/blob/ad9cec42/core/schema/src/main/resources/org/apache/isis/schema/ixn/ixn-1.0.xsd
----------------------------------------------------------------------
diff --git a/core/schema/src/main/resources/org/apache/isis/schema/ixn/ixn-1.0.xsd b/core/schema/src/main/resources/org/apache/isis/schema/ixn/ixn-1.0.xsd
index 359eca0..53afb2d 100644
--- a/core/schema/src/main/resources/org/apache/isis/schema/ixn/ixn-1.0.xsd
+++ b/core/schema/src/main/resources/org/apache/isis/schema/ixn/ixn-1.0.xsd
@@ -197,12 +197,6 @@
                     </xs:documentation>
                 </xs:annotation>
             </xs:element>
-            <xs:element name="propertiesModified" type="com:differenceDto">
-                <xs:annotation>
-                    <xs:documentation>The number of individual properties of objects that were modified (each such change would correspond to a separate call to AuditingService if configured).
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
         </xs:sequence>
 
     </xs:complexType>


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

Posted by da...@apache.org.
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/master
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) {