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 2013/02/05 09:01:31 UTC

[2/2] git commit: ISIS-323: now publishing actions...

Updated Branches:
  refs/heads/dan/ISIS-323 1f558615a -> 695974a6a


ISIS-323: now publishing actions...

* courtesy of a little ThreadLocal hackery


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

Branch: refs/heads/dan/ISIS-323
Commit: 695974a6a52b37301189a4a31925ee76ac5c92b3
Parents: c23fa95
Author: Dan Haywood <da...@apache.org>
Authored: Tue Feb 5 07:44:22 2013 +0000
Committer: Dan Haywood <da...@apache.org>
Committed: Tue Feb 5 07:44:22 2013 +0000

----------------------------------------------------------------------
 .../isis/applib/annotation/PublishedAction.java    |    3 +-
 .../applib/services/publish/PublishingService.java |    3 +-
 .../actions/invoke/ActionInvocationFacet.java      |   40 ++++++
 .../metamodel/runtimecontext/ServicesInjector.java |    2 +-
 .../noruntime/RuntimeContextNoRuntime.java         |    2 +-
 .../services/ServicesInjectorDefault.java          |   48 ++++++--
 .../core/metamodel/spec/ObjectAdapterUtils.java    |   13 ++
 .../invoke/ActionInvocationFacetViaMethod.java     |   11 ++
 .../PersistenceMechanismInstallerAbstract.java     |  100 +--------------
 .../internal/RuntimeContextFromSession.java        |    2 +-
 .../PublishingServiceWithCanonicalizers.java       |   56 ++++++++
 .../system/transaction/IsisTransaction.java        |   37 +++++-
 .../system/transaction/IsisTransactionManager.java |   72 ++++++++++-
 .../PublishingServiceWithCanonicalizers.java       |   39 ------
 .../ActionInvocationFacetWrapTransaction.java      |    4 +-
 .../PersistenceSessionObjectStoreTest.java         |    9 +-
 ...StoreTransactionManager_EndTransactionTest.java |   29 +++-
 ...tStoreTransactionManager_InstantiationTest.java |   21 +---
 ...oreTransactionManager_StartTransactionTest.java |   12 +--
 .../system/transaction/IsisTransactionTest.java    |    1 +
 .../src/main/webapp/WEB-INF/isis.properties        |    6 +-
 21 files changed, 308 insertions(+), 202 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/applib/src/main/java/org/apache/isis/applib/annotation/PublishedAction.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/PublishedAction.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/PublishedAction.java
index 773c251..85bb39d 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/PublishedAction.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/PublishedAction.java
@@ -26,6 +26,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.util.List;
 
+import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.services.publish.CanonicalEvent;
 import org.apache.isis.applib.services.publish.PublishingService;
 
@@ -41,7 +42,7 @@ import org.apache.isis.applib.services.publish.PublishingService;
 public @interface PublishedAction {
     
     public interface EventCanonicalizer {
-        public CanonicalEvent canonicalizeAction(Object invoked, String actionMethodName, List<Object> args, Object actionResult);
+        public CanonicalEvent canonicalizeAction(Object invoked, Identifier actionIdentifier, List<Object> args, Object actionResult);
     }
     Class<? extends EventCanonicalizer> canonicalizeWith()  default EventCanonicalizer.class;
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/applib/src/main/java/org/apache/isis/applib/services/publish/PublishingService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/publish/PublishingService.java b/core/applib/src/main/java/org/apache/isis/applib/services/publish/PublishingService.java
index 2d47643..28f3499 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/publish/PublishingService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/publish/PublishingService.java
@@ -32,9 +32,8 @@ public interface PublishingService {
         @Hidden
         @Override
         public void publish(UUID guid, String currentUser, long currentTimestampEpoch, CanonicalEvent canonicalEvent) {
-            System.err.println("PUBLISHED OBJECT: " + guid + ":" + currentTimestampEpoch + ":" + currentTimestampEpoch + ":" + canonicalEvent.asString());
+            System.err.println("PUBLISHED: " + guid + ":" + currentUser + ":" + currentTimestampEpoch + ":" + canonicalEvent.asString());
         }
-        
     }
 }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/ActionInvocationFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/ActionInvocationFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/ActionInvocationFacet.java
index ba9bad8..e644e1f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/ActionInvocationFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/invoke/ActionInvocationFacet.java
@@ -19,9 +19,15 @@
 
 package org.apache.isis.core.metamodel.facets.actions.invoke;
 
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.isis.applib.Identifier;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.IdentifiedHolder;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 
 /**
  * Represents the mechanism by which the action should be invoked.
@@ -39,4 +45,38 @@ public interface ActionInvocationFacet extends Facet {
 
     public ObjectSpecification getOnType();
 
+    public static class CurrentInvocation {
+        private final ObjectAdapter target;
+        private final IdentifiedHolder action;
+        private final List<ObjectAdapter> parameters;
+        private final ObjectAdapter result;
+
+        public CurrentInvocation(ObjectAdapter target, IdentifiedHolder action, ObjectAdapter[] parameters, ObjectAdapter result) {
+            this(target, action, Arrays.asList(parameters), result);
+        }
+
+        public CurrentInvocation(ObjectAdapter target, IdentifiedHolder action, List<ObjectAdapter> parameters, ObjectAdapter result) {
+            this.target = target;
+            this.action = action;
+            this.parameters = parameters;
+            this.result = result;
+        }
+        
+        public ObjectAdapter getTarget() {
+            return target;
+        }
+        public IdentifiedHolder getAction() {
+            return action;
+        }
+        public List<ObjectAdapter> getParameters() {
+            return parameters;
+        }
+        
+        public ObjectAdapter getResult() {
+            return result;
+        }
+    }
+    
+    public static ThreadLocal<CurrentInvocation> currentInvocation = new ThreadLocal<CurrentInvocation>();
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/metamodel/src/main/java/org/apache/isis/core/metamodel/runtimecontext/ServicesInjector.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/runtimecontext/ServicesInjector.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/runtimecontext/ServicesInjector.java
index 17bf6c3..71f88fd 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/runtimecontext/ServicesInjector.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/runtimecontext/ServicesInjector.java
@@ -36,5 +36,5 @@ public interface ServicesInjector extends Injectable {
      */
     void injectServicesInto(List<Object> objects);
 
-    Object lookupService(Class<?> serviceClass);
+    <T> T lookupService(Class<T> serviceClass);
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/metamodel/src/main/java/org/apache/isis/core/metamodel/runtimecontext/noruntime/RuntimeContextNoRuntime.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/runtimecontext/noruntime/RuntimeContextNoRuntime.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/runtimecontext/noruntime/RuntimeContextNoRuntime.java
index e64cc69..86ece81 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/runtimecontext/noruntime/RuntimeContextNoRuntime.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/runtimecontext/noruntime/RuntimeContextNoRuntime.java
@@ -86,7 +86,7 @@ public class RuntimeContextNoRuntime extends RuntimeContextAbstract {
             }
 
             @Override
-            public Object lookupService(Class<?> serviceClass) {
+            public <T> T lookupService(Class<T> serviceClass) {
                 return null;
             }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefault.java
index 61594f6..387101b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjectorDefault.java
@@ -28,10 +28,7 @@ import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Collections;
 import java.util.List;
-
-import com.google.common.collect.Lists;
-
-import org.apache.log4j.Logger;
+import java.util.Map;
 
 import org.apache.isis.applib.DomainObjectContainer;
 import org.apache.isis.core.commons.ensure.Assert;
@@ -39,6 +36,13 @@ import org.apache.isis.core.commons.lang.CastUtils;
 import org.apache.isis.core.commons.lang.ToString;
 import org.apache.isis.core.metamodel.exceptions.MetaModelException;
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjectorAware;
+import org.apache.log4j.Logger;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 
 /**
  * Must be a thread-safe.
@@ -47,7 +51,14 @@ public class ServicesInjectorDefault implements ServicesInjectorSpi {
 
     private static final Logger LOG = Logger.getLogger(ServicesInjectorDefault.class);
 
+    /**
+     * If no key, not yet searched for type; otherwise the {@link Optional} indicates
+     * whether a service was found.
+     */
+    private final Map<Class<?>, Optional<Object>> servicesByType = Maps.newHashMap();
+
     private final List<Object> services = Lists.newArrayList();
+    
     private DomainObjectContainer container;
 
 
@@ -208,14 +219,31 @@ public class ServicesInjectorDefault implements ServicesInjectorSpi {
     }
 
     @Override
-    public Object lookupService(Class<?> serviceClass) {
-        for(final Object service: this.services) {
-            if(serviceClass.isAssignableFrom(service.getClass())) {
-                return service;
-            }
+    public <T> T lookupService(Class<T> serviceClass) {
+        locateAndCache(services, serviceClass);
+        @SuppressWarnings("unchecked")
+        Optional<T> optionalService = (Optional<T>) servicesByType.get(serviceClass);
+        return optionalService.orNull();
+    }
+
+    private void locateAndCache(List<Object> services, Class<?> serviceClass) {
+        if(servicesByType.containsKey(serviceClass)) {
+           return; 
         }
-        return null;
+
+        final Optional<Object> optionalService = Iterables.tryFind(services, ofType(serviceClass));
+        servicesByType.put(serviceClass, optionalService);
     }
 
+    private static final Predicate<Object> ofType(final Class<?> cls) {
+        return new Predicate<Object>() {
+            @Override
+            public boolean apply(Object input) {
+                return cls.isAssignableFrom(input.getClass());
+            }
+        };
+    };
+
+
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectAdapterUtils.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectAdapterUtils.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectAdapterUtils.java
index ee99c07..19b2672 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectAdapterUtils.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectAdapterUtils.java
@@ -16,8 +16,12 @@
  */
 package org.apache.isis.core.metamodel.spec;
 
+import java.util.List;
+
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 
+import com.google.common.collect.Lists;
+
 public final class ObjectAdapterUtils {
 
     private ObjectAdapterUtils() {
@@ -41,4 +45,13 @@ public final class ObjectAdapterUtils {
         return (String) obj;
     }
 
+
+    public static List<Object> unwrapObjects(final List<ObjectAdapter> adapters) {
+        List<Object> objects = Lists.newArrayList();
+        for (ObjectAdapter adapter : adapters) {
+            objects.add(unwrapObject(adapter));
+        }
+        return objects;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
index 8020f8d..a7efb9a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
@@ -21,6 +21,7 @@ package org.apache.isis.core.progmodel.facets.actions.invoke;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -31,10 +32,13 @@ import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
 import org.apache.isis.core.metamodel.adapter.util.InvokeUtils;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.ImperativeFacet;
+import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacet;
 import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacetAbstract;
+import org.apache.isis.core.metamodel.facets.actions.publish.PublishedActionFacet;
 import org.apache.isis.core.metamodel.facets.typeof.ElementSpecificationProviderFromTypeOfFacet;
 import org.apache.isis.core.metamodel.facets.typeof.TypeOfFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.specloader.ReflectiveActionException;
 
 public class ActionInvocationFacetViaMethod extends ActionInvocationFacetAbstract implements ImperativeFacet {
@@ -100,6 +104,13 @@ public class ActionInvocationFacetViaMethod extends ActionInvocationFacetAbstrac
             final ObjectAdapter resultAdapter = getAdapterManager().adapterFor(result);
             final TypeOfFacet typeOfFacet = getFacetHolder().getFacet(TypeOfFacet.class);
             resultAdapter.setElementSpecificationProvider(ElementSpecificationProviderFromTypeOfFacet.createFrom(typeOfFacet));
+            
+            PublishedActionFacet publishedActionFacet = getIdentified().getFacet(PublishedActionFacet.class);
+            ActionInvocationFacet.currentInvocation.set(
+                    publishedActionFacet != null
+                        ? new CurrentInvocation(inObject, getIdentified(), parameters, resultAdapter)
+                        :null);
+            
             return resultAdapter;
 
         } catch (final IllegalArgumentException e) {

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/runtime/src/main/java/org/apache/isis/core/runtime/installerregistry/installerapi/PersistenceMechanismInstallerAbstract.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/installerregistry/installerapi/PersistenceMechanismInstallerAbstract.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/installerregistry/installerapi/PersistenceMechanismInstallerAbstract.java
index bfde110..d8fc208 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/installerregistry/installerapi/PersistenceMechanismInstallerAbstract.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/installerregistry/installerapi/PersistenceMechanismInstallerAbstract.java
@@ -61,6 +61,7 @@ import org.apache.isis.core.runtime.persistence.objectstore.IsisObjectStoreLogge
 import org.apache.isis.core.runtime.persistence.objectstore.ObjectStoreSpi;
 import org.apache.isis.core.runtime.persistence.objectstore.algorithm.PersistAlgorithm;
 import org.apache.isis.core.runtime.persistence.objectstore.algorithm.PersistAlgorithmDefault;
+import org.apache.isis.core.runtime.persistence.objectstore.transaction.PublishingServiceWithCanonicalizers;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.TransactionalResource;
 import org.apache.isis.core.runtime.system.DeploymentType;
 import org.apache.isis.core.runtime.system.context.IsisContext;
@@ -72,7 +73,6 @@ import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSessionFactory;
 import org.apache.isis.core.runtime.system.transaction.EnlistedObjectDirtying;
 import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
-import org.apache.isis.core.runtime.system.transaction.PublishingServiceWithCanonicalizers;
 import org.apache.isis.core.runtime.systemdependencyinjector.SystemDependencyInjector;
 import org.apache.log4j.Logger;
 
@@ -161,7 +161,7 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
         final PersistenceSession persistenceSession = 
                 new PersistenceSession(persistenceSessionFactory, adapterFactory, objectFactory, servicesInjector, identifierGenerator, adapterManager, persistAlgorithm, objectStore);
         
-        final IsisTransactionManager transactionManager = createTransactionManager(persistenceSessionFactory, persistenceSession, objectStore);
+        final IsisTransactionManager transactionManager = createTransactionManager(servicesInjector, persistenceSession, objectStore);
         
         ensureThatArg(persistenceSession, is(not(nullValue())));
         ensureThatArg(transactionManager, is(not(nullValue())));
@@ -204,64 +204,9 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
      * 
      * <p>
      * By default returns a {@link IsisTransactionManager}.
-     * @param persistenceSessionFactory TODO
      */
-    protected IsisTransactionManager createTransactionManager(PersistenceSessionFactory persistenceSessionFactory, final EnlistedObjectDirtying enlistedObjectDirtying, final TransactionalResource transactionalResource) {
-        List<Object> services = persistenceSessionFactory.getServices();
-
-        final AuditingService auditingServiceIfAny = getServiceIfAny(services, AuditingService.class);
-        final PublishingServiceWithCanonicalizers publishingServiceIfAny = getPublishingServiceIfAny(services);
-        return new IsisTransactionManager(enlistedObjectDirtying, transactionalResource, auditingServiceIfAny, publishingServiceIfAny);
-    }
-
-    protected PublishingServiceWithCanonicalizers getPublishingServiceIfAny(List<Object> services) {
-        final PublishingService publishingService = getServiceIfAny(services, PublishingService.class);
-        if(publishingService == null) {
-            return null;
-        }
-        
-        PublishedObject.EventCanonicalizer objectEventCanonicalizer = getServiceIfAny(services, PublishedObject.EventCanonicalizer.class);
-        if(objectEventCanonicalizer == null) {
-            objectEventCanonicalizer = newDefaultObjectEventCanonicalizer();
-        }
-        
-        PublishedAction.EventCanonicalizer actionEventCanonicalizer = getServiceIfAny(services, PublishedAction.EventCanonicalizer.class);
-        if(actionEventCanonicalizer == null) {
-            actionEventCanonicalizer = newDefaultActionEventCanonicalizer();
-        }
-        
-        return new PublishingServiceWithCanonicalizers(publishingService, objectEventCanonicalizer, actionEventCanonicalizer);
-    }
-
-    protected EventCanonicalizer newDefaultObjectEventCanonicalizer() {
-        return new PublishedObject.EventCanonicalizer() {
-            @Override
-            public CanonicalEvent canonicalizeObject(final Object changedObject) {
-                return new CanonicalEvent.Default(oidStrFor(changedObject));
-            }
-        };
-    }
-
-    protected org.apache.isis.applib.annotation.PublishedAction.EventCanonicalizer newDefaultActionEventCanonicalizer() {
-        return new PublishedAction.EventCanonicalizer() {
-
-            @Override
-            public CanonicalEvent canonicalizeAction(Object invokedObject, String actionMethodName, List<Object> args, Object actionResult) {
-                return new CanonicalEvent.Default(oidStrFor(invokedObject + "#" + actionMethodName + appendResultIfAny(actionResult)) );
-            }
-
-            private String appendResultIfAny(Object actionResult) {
-                if(actionResult == null) {
-                    return "";
-                }
-                return "=" + oidStrFor(actionResult);
-            }
-        };
-    }
-
-    private static String oidStrFor(final Object changedObject) {
-        final ObjectAdapter adapter = IsisContext.getPersistenceSession().getAdapterManager().adapterFor(changedObject);
-        return adapter.getOid().enString(IsisContext.getOidMarshaller());
+    protected IsisTransactionManager createTransactionManager(ServicesInjectorSpi servicesInjectorSpi, final EnlistedObjectDirtying enlistedObjectDirtying, final TransactionalResource transactionalResource) {
+        return new IsisTransactionManager(enlistedObjectDirtying, transactionalResource, servicesInjectorSpi);
     }
 
 
@@ -366,6 +311,7 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
     }
 
 
+
     // ///////////////////////////////////////////
     // Non overridable.
     // ///////////////////////////////////////////
@@ -393,42 +339,6 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
     }
 
 
-    // ///////////////////////////////////////////
-    // caching services by type
-    // ///////////////////////////////////////////
-
-    /**
-     * If no key, not yet searched for type; otherwise the {@link Optional} indicates
-     * whether a service was found.
-     */
-    private final Map<Class<?>, Optional<Object>> servicesByType = Maps.newHashMap();
-
-    @SuppressWarnings("unchecked")
-    private <T> T getServiceIfAny(List<Object> services, Class<T> serviceClass) {
-        locateAndCache(services, serviceClass);
-        Optional<T> optionalService = (Optional<T>) servicesByType.get(serviceClass);
-        return optionalService.orNull();
-    }
-
-    private void locateAndCache(List<Object> services, Class<?> serviceClass) {
-        if(servicesByType.containsKey(serviceClass)) {
-           return; 
-        }
-
-        final Optional<Object> optionalService = Iterables.tryFind(services, ofType(serviceClass));
-        servicesByType.put(serviceClass, optionalService);
-    }
-
-    private static final Predicate<Object> ofType(final Class<?> cls) {
-        return new Predicate<Object>() {
-            @Override
-            public boolean apply(Object input) {
-                return cls.isAssignableFrom(input.getClass());
-            }
-        };
-    };
-
-
 
     // /////////////////////////////////////////////////////
     // Dependencies (from setters)

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/internal/RuntimeContextFromSession.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/internal/RuntimeContextFromSession.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/internal/RuntimeContextFromSession.java
index 755cf68..426b732 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/internal/RuntimeContextFromSession.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/internal/RuntimeContextFromSession.java
@@ -276,7 +276,7 @@ public class RuntimeContextFromSession extends RuntimeContextAbstract {
             }
 
             @Override
-            public Object lookupService(Class<?> serviceClass) {
+            public <T> T lookupService(Class<T> serviceClass) {
                 return getPersistenceSession().getServicesInjector().lookupService(serviceClass);
             }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/PublishingServiceWithCanonicalizers.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/PublishingServiceWithCanonicalizers.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/PublishingServiceWithCanonicalizers.java
new file mode 100644
index 0000000..a32c760
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/PublishingServiceWithCanonicalizers.java
@@ -0,0 +1,56 @@
+package org.apache.isis.core.runtime.persistence.objectstore.transaction;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.isis.applib.annotation.PublishedAction;
+import org.apache.isis.applib.annotation.PublishedObject;
+import org.apache.isis.applib.annotation.PublishedObject.EventCanonicalizer;
+import org.apache.isis.applib.services.publish.CanonicalEvent;
+import org.apache.isis.applib.services.publish.PublishingService;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.IdentifiedHolder;
+import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacet.CurrentInvocation;
+import org.apache.isis.core.metamodel.spec.ObjectAdapterUtils;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+
+/**
+ * Wrapper around {@link PublishingService} that also includes the
+ * {@link PublishedObject.EventCanonicalizer event} {@link PublishedAction.EventCanonicalizer canonicalizers}. 
+ */
+public class PublishingServiceWithCanonicalizers {
+
+    private final PublishingService publishingService;
+    private final PublishedObject.EventCanonicalizer defaultObjectEventCanonicalizer;
+    private final PublishedAction.EventCanonicalizer defaultActionEventCanonicalizer;
+    
+    public PublishingServiceWithCanonicalizers(PublishingService publishingService, EventCanonicalizer defaultObjectEventCanonicalizer, PublishedAction.EventCanonicalizer defaultActionEventCanonicalizer) {
+        this.publishingService = publishingService;
+        this.defaultObjectEventCanonicalizer = defaultObjectEventCanonicalizer;
+        this.defaultActionEventCanonicalizer = defaultActionEventCanonicalizer;
+    }
+
+    public void publishObject(PublishedObject.EventCanonicalizer eventCanonicalizer, UUID guid, String currentUser, long currentTimestampEpoch, ObjectAdapter changedAdapter) {
+        final PublishedObject.EventCanonicalizer eventCanonicalizerToUse = eventCanonicalizer != null? eventCanonicalizer: defaultObjectEventCanonicalizer;
+        final CanonicalEvent canonicalizedEvent = eventCanonicalizerToUse.canonicalizeObject(ObjectAdapterUtils.unwrapObject(changedAdapter));
+        
+        publishingService.publish(guid, currentUser, currentTimestampEpoch, canonicalizedEvent);
+    }
+
+    public void publishAction(PublishedAction.EventCanonicalizer value, UUID guid, String currentUser, long currentTimestampEpoch, CurrentInvocation currentInvocation) {
+        publishAction(value, guid, currentUser, currentTimestampEpoch, currentInvocation.getTarget(), currentInvocation.getAction(), currentInvocation.getParameters(), currentInvocation.getResult());
+    }
+
+    private void publishAction(PublishedAction.EventCanonicalizer eventCanonicalizer, UUID guid, String currentUser, long currentTimestampEpoch, ObjectAdapter targetAdapter, IdentifiedHolder action, List<ObjectAdapter> parameterAdapters, ObjectAdapter resultAdapter) {
+        final PublishedAction.EventCanonicalizer eventCanonicalizerToUse = eventCanonicalizer != null? eventCanonicalizer: defaultActionEventCanonicalizer;
+        final CanonicalEvent canonicalizedEvent = eventCanonicalizerToUse.canonicalizeAction(
+                ObjectAdapterUtils.unwrapObject(targetAdapter), 
+                action.getIdentifier(), 
+                ObjectAdapterUtils.unwrapObjects(parameterAdapters), 
+                ObjectAdapterUtils.unwrapObject(resultAdapter));
+        
+        publishingService.publish(guid, currentUser, currentTimestampEpoch, canonicalizedEvent);
+    }
+
+    
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/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 f6c306f..3893480 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
@@ -32,6 +32,8 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.UUID;
 
+import org.apache.isis.applib.annotation.PublishedAction.EventCanonicalizer;
+import org.apache.isis.applib.annotation.PublishedObject;
 import org.apache.isis.applib.clock.Clock;
 import org.apache.isis.applib.services.audit.AuditingService;
 import org.apache.isis.applib.services.publish.PublishingService;
@@ -45,6 +47,9 @@ import org.apache.isis.core.metamodel.adapter.ResolveState;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
 import org.apache.isis.core.metamodel.adapter.oid.OidMarshaller;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacet;
+import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacet.CurrentInvocation;
+import org.apache.isis.core.metamodel.facets.actions.publish.PublishedActionFacet;
 import org.apache.isis.core.metamodel.facets.object.audit.AuditableFacet;
 import org.apache.isis.core.metamodel.facets.object.publish.PublishedObjectFacet;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
@@ -52,6 +57,7 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectAssociationFilters;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.CreateObjectCommand;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.DestroyObjectCommand;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommand;
+import org.apache.isis.core.runtime.persistence.objectstore.transaction.PublishingServiceWithCanonicalizers;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.SaveObjectCommand;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.TransactionalResource;
 import org.apache.isis.core.runtime.system.context.IsisContext;
@@ -418,15 +424,36 @@ public class IsisTransaction implements TransactionScopedComponent {
         final String currentUser = getTransactionManager().getAuthenticationSession().getUserName();
         final long currentTimestampEpoch = currentTimestampEpoch();
         
-        for (ObjectAdapter changedAdapter : changedAdapters) {
-            PublishedObjectFacet publishedObjectFacet = changedAdapter.getSpecification().getFacet(PublishedObjectFacet.class);
+        publishedChangedObjects(changedAdapters, currentUser, currentTimestampEpoch);
+        publishActionIfRequired(currentUser, currentTimestampEpoch);
+    }
+
+    protected void publishedChangedObjects(final Set<ObjectAdapter> changedAdapters, final String currentUser, final long currentTimestampEpoch) {
+        for (final ObjectAdapter changedAdapter : changedAdapters) {
+            final PublishedObjectFacet publishedObjectFacet = changedAdapter.getSpecification().getFacet(PublishedObjectFacet.class);
             if(publishedObjectFacet == null) {
                 continue;
             }
-            publishingService.publishObject(publishedObjectFacet.value(), getGuid(), currentUser, currentTimestampEpoch, changedAdapter);
+            final PublishedObject.EventCanonicalizer canonicalizer = publishedObjectFacet.value();
+            publishingService.publishObject(canonicalizer, getGuid(), currentUser, currentTimestampEpoch, changedAdapter);
+        }
+    }
+
+    protected void publishActionIfRequired(final String currentUser, final long currentTimestampEpoch) {
+        try {
+            final CurrentInvocation currentInvocation = ActionInvocationFacet.currentInvocation.get();
+            if(currentInvocation == null) {
+                return;
+            } 
+            final PublishedActionFacet publishedActionFacet = currentInvocation.getAction().getFacet(PublishedActionFacet.class);
+            if(publishedActionFacet == null) {
+                return;
+            } 
+            final EventCanonicalizer canonicalizer = publishedActionFacet.value();
+            publishingService.publishAction(canonicalizer, guid, currentUser, currentTimestampEpoch, currentInvocation);
+        } finally {
+            ActionInvocationFacet.currentInvocation.set(null);
         }
-        
-        // TODO: use a ThreadLocal on ActionInvocationFacet to determine whether there is also a PublishedActionFacet to handle...
     }
 
     private static long currentTimestampEpoch() {

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/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 567fe01..edf67f5 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
@@ -28,16 +28,21 @@ import static org.hamcrest.CoreMatchers.nullValue;
 
 import java.util.List;
 
+import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.PublishedAction;
 import org.apache.isis.applib.annotation.PublishedObject;
 import org.apache.isis.applib.annotation.PublishedObject.EventCanonicalizer;
 import org.apache.isis.applib.services.audit.AuditingService;
+import org.apache.isis.applib.services.publish.CanonicalEvent;
 import org.apache.isis.applib.services.publish.PublishingService;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.components.SessionScopedComponent;
 import org.apache.isis.core.commons.debug.DebugBuilder;
 import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.services.ServicesInjectorSpi;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommand;
+import org.apache.isis.core.runtime.persistence.objectstore.transaction.PublishingServiceWithCanonicalizers;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.TransactionalResource;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.session.IsisSession;
@@ -74,11 +79,12 @@ public class IsisTransactionManager implements SessionScopedComponent {
     // constructor
     // ////////////////////////////////////////////////////////////////
 
-    public IsisTransactionManager(final EnlistedObjectDirtying objectPersistor, final TransactionalResource objectStore, final AuditingService auditingService, final PublishingServiceWithCanonicalizers publishingService) {
+    public IsisTransactionManager(final EnlistedObjectDirtying objectPersistor, final TransactionalResource objectStore, final ServicesInjectorSpi servicesInjectorSpi) {
         this.objectPersistor = objectPersistor;
         this.transactionalResource = objectStore;
-        this.auditingService = auditingService;
-        this.publishingService = publishingService;
+        
+        this.auditingService = (AuditingService) servicesInjectorSpi.lookupService(AuditingService.class);
+        this.publishingService = getPublishingServiceIfAny(servicesInjectorSpi);
     }
     
     
@@ -377,6 +383,66 @@ public class IsisTransactionManager implements SessionScopedComponent {
         getTransaction().addCommand(command);
     }
 
+    
+    // ///////////////////////////////////////////
+    // Publishing service
+    // ///////////////////////////////////////////
+
+    public PublishingServiceWithCanonicalizers getPublishingServiceIfAny(ServicesInjectorSpi servicesInjectorSpi) {
+        final PublishingService publishingService = servicesInjectorSpi.lookupService(PublishingService.class);
+        if(publishingService == null) {
+            return null;
+        }
+        
+        PublishedObject.EventCanonicalizer objectEventCanonicalizer = servicesInjectorSpi.lookupService(PublishedObject.EventCanonicalizer.class);
+        if(objectEventCanonicalizer == null) {
+            objectEventCanonicalizer = newDefaultObjectEventCanonicalizer();
+        }
+        
+        PublishedAction.EventCanonicalizer actionEventCanonicalizer = servicesInjectorSpi.lookupService(PublishedAction.EventCanonicalizer.class);
+        if(actionEventCanonicalizer == null) {
+            actionEventCanonicalizer = newDefaultActionEventCanonicalizer();
+        }
+        
+        return new PublishingServiceWithCanonicalizers(publishingService, objectEventCanonicalizer, actionEventCanonicalizer);
+    }
+
+
+    protected PublishedObject.EventCanonicalizer newDefaultObjectEventCanonicalizer() {
+        return new PublishedObject.EventCanonicalizer() {
+            @Override
+            public CanonicalEvent canonicalizeObject(final Object changedObject) {
+                return new CanonicalEvent.Default("CHANGED_OBJECT\n    "+oidStrFor(changedObject));
+            }
+        };
+    }
+
+    protected PublishedAction.EventCanonicalizer newDefaultActionEventCanonicalizer() {
+        return new PublishedAction.EventCanonicalizer() {
+
+            @Override
+            public CanonicalEvent canonicalizeAction(Object invokedObject, Identifier identifier, List<Object> args, Object actionResult) {
+                final StringBuilder buf = new StringBuilder();
+                buf.append("ACTION\n").append(identifier.toString());
+                buf.append("\n    target=").append(oidStrFor(invokedObject));
+                buf.append("\n      args=[");
+                for (Object arg : args) {
+                    buf.append("\n           ").append(oidStrFor(arg));
+                }
+                buf.append("\n      ]");
+                buf.append("\n    result=").append(actionResult != null ? oidStrFor(actionResult) : "void");
+                return new CanonicalEvent.Default(buf.toString()) ;
+            }
+        };
+    }
+
+    private static String oidStrFor(final Object changedObject) {
+        final ObjectAdapter adapter = IsisContext.getPersistenceSession().getAdapterManager().adapterFor(changedObject);
+        return adapter.getOid().enString(IsisContext.getOidMarshaller());
+    }
+
+
+    
     // //////////////////////////////////////////////////////////////
     // Hooks
     // //////////////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/PublishingServiceWithCanonicalizers.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/PublishingServiceWithCanonicalizers.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/PublishingServiceWithCanonicalizers.java
deleted file mode 100644
index df9b597..0000000
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/PublishingServiceWithCanonicalizers.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.apache.isis.core.runtime.system.transaction;
-
-import java.util.UUID;
-
-import org.apache.isis.applib.annotation.PublishedAction;
-import org.apache.isis.applib.annotation.PublishedObject;
-import org.apache.isis.applib.annotation.PublishedObject.EventCanonicalizer;
-import org.apache.isis.applib.services.publish.CanonicalEvent;
-import org.apache.isis.applib.services.publish.PublishingService;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-
-/**
- * Wrapper around {@link PublishingService} that also includes the
- * {@link PublishedObject.EventCanonicalizer event} {@link PublishedAction.EventCanonicalizer canonicalizers}. 
- * 
- * <p>
- * Acts as an internal contract between {@link IsisTransactionManager} and {@link IsisTransaction}.
- */
-public class PublishingServiceWithCanonicalizers {
-
-    private final PublishingService publishingService;
-    private final PublishedObject.EventCanonicalizer defaultObjectEventCanonicalizer;
-    private final PublishedAction.EventCanonicalizer defaultActionEventCanonicalizer;
-    
-    public PublishingServiceWithCanonicalizers(PublishingService publishingService, EventCanonicalizer defaultObjectEventCanonicalizer, PublishedAction.EventCanonicalizer defaultActionEventCanonicalizer) {
-        this.publishingService = publishingService;
-        this.defaultObjectEventCanonicalizer = defaultObjectEventCanonicalizer;
-        this.defaultActionEventCanonicalizer = defaultActionEventCanonicalizer;
-    }
-
-    public void publishObject(PublishedObject.EventCanonicalizer eventCanonicalizer, UUID guid, String currentUser, long currentTimestampEpoch, ObjectAdapter changedAdapter) {
-        PublishedObject.EventCanonicalizer eventCanonicalizerToUse = eventCanonicalizer != null? eventCanonicalizer: defaultObjectEventCanonicalizer;
-        CanonicalEvent canonicalizedEvent = eventCanonicalizerToUse.canonicalizeObject(changedAdapter.getObject());
-        
-        publishingService.publish(guid, currentUser, currentTimestampEpoch, canonicalizedEvent);
-    }
-
-    
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/runtime/src/main/java/org/apache/isis/core/runtime/transaction/facets/ActionInvocationFacetWrapTransaction.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/transaction/facets/ActionInvocationFacetWrapTransaction.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/transaction/facets/ActionInvocationFacetWrapTransaction.java
index 489a5d2..f743662 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/transaction/facets/ActionInvocationFacetWrapTransaction.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/transaction/facets/ActionInvocationFacetWrapTransaction.java
@@ -25,6 +25,7 @@ import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facetapi.DecoratingFacet;
 import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacet;
 import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacetAbstract;
+import org.apache.isis.core.metamodel.facets.actions.invoke.ActionInvocationFacet.CurrentInvocation;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
@@ -49,12 +50,13 @@ public class ActionInvocationFacetWrapTransaction extends ActionInvocationFacetA
 
     @Override
     public ObjectAdapter invoke(final ObjectAdapter targetAdapter, final ObjectAdapter[] parameterAdapters) {
-        return getTransactionManager().executeWithinTransaction(new TransactionalClosureWithReturnAbstract<ObjectAdapter>() {
+        final ObjectAdapter result = getTransactionManager().executeWithinTransaction(new TransactionalClosureWithReturnAbstract<ObjectAdapter>() {
             @Override
             public ObjectAdapter execute() {
                 return underlyingFacet.invoke(targetAdapter, parameterAdapters);
             }
         });
+        return result;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/PersistenceSessionObjectStoreTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/PersistenceSessionObjectStoreTest.java b/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/PersistenceSessionObjectStoreTest.java
index 27d5420..a7092c4 100644
--- a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/PersistenceSessionObjectStoreTest.java
+++ b/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/PersistenceSessionObjectStoreTest.java
@@ -57,6 +57,7 @@ import org.apache.isis.core.runtime.persistence.objectstore.transaction.CreateOb
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.DestroyObjectCommand;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommand;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PojoAdapterBuilder;
+import org.apache.isis.core.runtime.persistence.objectstore.transaction.PublishingServiceWithCanonicalizers;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.SaveObjectCommand;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PojoAdapterBuilder.Persistence;
 import org.apache.isis.core.runtime.system.persistence.AdapterManagerSpi;
@@ -66,7 +67,6 @@ import org.apache.isis.core.runtime.system.persistence.OidGenerator;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSessionFactory;
 import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
-import org.apache.isis.core.runtime.system.transaction.PublishingServiceWithCanonicalizers;
 import org.apache.isis.core.unittestsupport.jmock.auto.Mock;
 import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
@@ -177,12 +177,15 @@ public class PersistenceSessionObjectStoreTest {
             
         };
         
+        servicesInjector.setServices(Collections.emptyList());
+        
         context.checking(new Expectations(){{
             allowing(mockAuthenticationSession).getUserName();
             will(returnValue("sven"));
         }});
 
-        transactionManager = new IsisTransactionManager(persistenceSession, mockObjectStore, mockAuditingService, mockPublishingService) {
+        
+        transactionManager = new IsisTransactionManager(persistenceSession, mockObjectStore, servicesInjector) {
             @Override
             public AuthenticationSession getAuthenticationSession() {
                 return mockAuthenticationSession;
@@ -190,8 +193,6 @@ public class PersistenceSessionObjectStoreTest {
         };
         persistenceSession.setTransactionManager(transactionManager);
 
-        servicesInjector.setServices(Collections.emptyList());
-
         persistentAdapter = PojoAdapterBuilder.create().withOid("CUS|1").withPojo(new Customer()).with(Persistence.PERSISTENT).with(mockVersion).with(isisMetaModel.getSpecificationLoader()).build();
         transientAdapter = PojoAdapterBuilder.create().withOid("CUS|2").withPojo(new Customer()).with(Persistence.TRANSIENT).with(isisMetaModel.getSpecificationLoader()).build();
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_EndTransactionTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_EndTransactionTest.java b/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_EndTransactionTest.java
index 645eac4..0f33d80 100644
--- a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_EndTransactionTest.java
+++ b/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_EndTransactionTest.java
@@ -28,13 +28,16 @@ import java.util.Collections;
 import org.apache.isis.applib.services.audit.AuditingService;
 import org.apache.isis.applib.services.publish.PublishingService;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.metamodel.services.ServicesInjectorDefault;
+import org.apache.isis.core.metamodel.services.ServicesInjectorSpi;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
-import org.apache.isis.core.runtime.system.session.IsisSession;
 import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
-import org.apache.isis.core.runtime.system.transaction.PublishingServiceWithCanonicalizers;
 import org.apache.isis.core.unittestsupport.jmock.auto.Mock;
 import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
 import org.jmock.Expectations;
 import org.jmock.Sequence;
 import org.junit.Before;
@@ -54,11 +57,6 @@ public class ObjectStoreTransactionManager_EndTransactionTest {
     @Mock
     private TransactionalResource mockObjectStore;
 
-    @Mock
-    private AuditingService mockAuditingService;
-    @Mock
-    private PublishingServiceWithCanonicalizers mockPublishingService;
-
     private IsisTransactionManager transactionManager;
 
     @Before
@@ -68,7 +66,7 @@ public class ObjectStoreTransactionManager_EndTransactionTest {
             will(returnValue("sven"));
         }});
 
-        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore, mockAuditingService, mockPublishingService) {
+        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore, new ServicesInjectorDefault()) {
             @Override
             public AuthenticationSession getAuthenticationSession() {
                 return mockAuthenticationSession;
@@ -76,6 +74,21 @@ public class ObjectStoreTransactionManager_EndTransactionTest {
         };
     }
 
+    protected Matcher<Class<?>> anyClass() {
+        return new TypeSafeMatcher<Class<?>>() {
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("any class");
+            }
+
+            @Override
+            protected boolean matchesSafely(Class<?> item) {
+                return true;
+            }
+        };
+    }
+
     @Test
     public void endTransactionDecrementsTransactionLevel() throws Exception {
         // setup

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_InstantiationTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_InstantiationTest.java b/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_InstantiationTest.java
index d7618c7..aed593c 100644
--- a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_InstantiationTest.java
+++ b/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_InstantiationTest.java
@@ -19,42 +19,31 @@
 
 package org.apache.isis.core.runtime.persistence.objectstore.transaction;
 
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.apache.isis.applib.services.audit.AuditingService;
-import org.apache.isis.applib.services.publish.PublishingService;
+import org.apache.isis.core.metamodel.services.ServicesInjectorDefault;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
-import org.apache.isis.core.runtime.system.session.IsisSession;
 import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
-import org.apache.isis.core.runtime.system.transaction.PublishingServiceWithCanonicalizers;
 import org.apache.isis.core.unittestsupport.jmock.auto.Mock;
 import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
+import org.junit.Rule;
+import org.junit.Test;
 
 public class ObjectStoreTransactionManager_InstantiationTest {
 
     @Rule
     public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
 
-    
-    @Mock
-    private IsisSession mockSession;
     @Mock
     private PersistenceSession mockPersistenceSession;
     @Mock
     private TransactionalResource mockObjectStore;
 
-    @Mock
-    private AuditingService mockAuditingService;
-    @Mock
-    private PublishingServiceWithCanonicalizers mockPublishingService;
-
+    @SuppressWarnings("unused")
     private IsisTransactionManager transactionManager;
 
     @Test
     public void canInstantiate() throws Exception {
-        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore, mockAuditingService, mockPublishingService);
+        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore, new ServicesInjectorDefault());
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_StartTransactionTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_StartTransactionTest.java b/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_StartTransactionTest.java
index 42b01ea..8f975cf 100644
--- a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_StartTransactionTest.java
+++ b/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManager_StartTransactionTest.java
@@ -25,12 +25,10 @@ import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.CoreMatchers.sameInstance;
 import static org.junit.Assert.assertThat;
 
-import org.apache.isis.applib.services.audit.AuditingService;
+import org.apache.isis.core.metamodel.services.ServicesInjectorDefault;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
-import org.apache.isis.core.runtime.system.session.IsisSession;
 import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
 import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
-import org.apache.isis.core.runtime.system.transaction.PublishingServiceWithCanonicalizers;
 import org.apache.isis.core.unittestsupport.jmock.auto.Mock;
 import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
@@ -46,22 +44,16 @@ public class ObjectStoreTransactionManager_StartTransactionTest {
 
     
     @Mock
-    private IsisSession mockSession;
-    @Mock
     private PersistenceSession mockPersistenceSession;
     @Mock
     private TransactionalResource mockObjectStore;
 
-    @Mock
-    private AuditingService mockAuditingService;
-    @Mock
-    private PublishingServiceWithCanonicalizers mockPublishingService;
 
     private IsisTransactionManager transactionManager;
 
     @Before
     public void setUpTransactionManager() throws Exception {
-        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore, mockAuditingService, mockPublishingService);
+        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore, new ServicesInjectorDefault());
     }
 
     @Before

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/core/runtime/src/test/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionTest.java b/core/runtime/src/test/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionTest.java
index 7407bf8..699c44d 100644
--- a/core/runtime/src/test/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionTest.java
+++ b/core/runtime/src/test/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionTest.java
@@ -33,6 +33,7 @@ import org.apache.isis.core.runtime.persistence.objectstore.transaction.DestroyO
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommand;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommandContext;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PojoAdapterBuilder;
+import org.apache.isis.core.runtime.persistence.objectstore.transaction.PublishingServiceWithCanonicalizers;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.SaveObjectCommand;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PojoAdapterBuilder.Persistence;
 import org.apache.isis.core.runtime.system.transaction.IsisTransaction;

http://git-wip-us.apache.org/repos/asf/isis/blob/695974a6/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/webapp/WEB-INF/isis.properties
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/webapp/WEB-INF/isis.properties b/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/webapp/WEB-INF/isis.properties
index 118e77c..c7cc47f 100644
--- a/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/webapp/WEB-INF/isis.properties
+++ b/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/webapp/WEB-INF/isis.properties
@@ -163,12 +163,8 @@ isis.user-profile-store=in-memory
 isis.services = objstore.jdo.todo.ToDoItemsJdo,\
                 fixture.todo.ToDoItemsFixturesService,\
                 dom.audit.AuditServiceDemo,\
-                org.apache.isis.applib.services.publish.PublishingService$Stdout,\
+                org.apache.isis.applib.services.publish.PublishingService$Stderr,
 
-
-
-
-#
 # Specify the (optional) test fixtures
 #
 # Fixtures are used to seed the object store with an initial set of data.  For the