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/01 18:31:19 UTC

[2/3] ISIS-323: first cut

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/audit/markerifc/AuditableMarkerInterfaceFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/audit/markerifc/AuditableMarkerInterfaceFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/audit/markerifc/AuditableMarkerInterfaceFacetFactory.java
new file mode 100644
index 0000000..0ab519c
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/audit/markerifc/AuditableMarkerInterfaceFacetFactory.java
@@ -0,0 +1,45 @@
+/*
+ *  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.metamodel.facets.object.audit.markerifc;
+
+
+import org.apache.isis.applib.marker.Auditable;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facetapi.FeatureType;
+import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
+
+
+public class AuditableMarkerInterfaceFacetFactory extends FacetFactoryAbstract {
+
+    public AuditableMarkerInterfaceFacetFactory() {
+        super(FeatureType.OBJECTS_ONLY);
+    }
+
+    @Override
+    public void process(ProcessClassContext processClassContext) {
+        final Class<?> cls = processClassContext.getCls();
+        if(!Auditable.class.isAssignableFrom(cls)) {
+            return;
+        }
+        FacetUtil.addFacet(new AuditableFacetMarkerInterface(
+                processClassContext.getFacetHolder()));
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/publish/PublishedObjectFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/publish/PublishedObjectFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/publish/PublishedObjectFacet.java
new file mode 100644
index 0000000..f64a668
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/publish/PublishedObjectFacet.java
@@ -0,0 +1,34 @@
+/*
+ *  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.metamodel.facets.object.publish;
+
+import java.util.UUID;
+
+import org.apache.isis.applib.annotation.PublishedObject;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.SingleValueFacet;
+
+/**
+ * Indicates that changes to an object's properties are to be published has, specifying the means by which 
+ * a canonical event representing these changes should be created.
+ */
+public interface PublishedObjectFacet extends SingleValueFacet<PublishedObject.EventCanonicalizer> {
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/publish/PublishedObjectFacetAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/publish/PublishedObjectFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/publish/PublishedObjectFacetAbstract.java
new file mode 100644
index 0000000..1fa0cbc
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/publish/PublishedObjectFacetAbstract.java
@@ -0,0 +1,37 @@
+/*
+ *  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.metamodel.facets.object.publish;
+
+import org.apache.isis.applib.annotation.PublishedObject;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.SingleValueFacetAbstract;
+
+public abstract class PublishedObjectFacetAbstract extends SingleValueFacetAbstract<PublishedObject.EventCanonicalizer> implements PublishedObjectFacet {
+
+    public static Class<? extends Facet> type() {
+        return PublishedObjectFacet.class;
+    }
+
+    public PublishedObjectFacetAbstract(final PublishedObject.EventCanonicalizer eventCanonicalizer, final FacetHolder holder) {
+        super(type(), eventCanonicalizer, holder);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/publish/PublishedActionAnnotationFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/publish/PublishedActionAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/publish/PublishedActionAnnotationFacetFactory.java
new file mode 100644
index 0000000..7e94563
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/publish/PublishedActionAnnotationFacetFactory.java
@@ -0,0 +1,60 @@
+/*
+ *  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.progmodel.facets.actions.publish;
+
+import org.apache.isis.applib.annotation.PublishedAction;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facetapi.FeatureType;
+import org.apache.isis.core.metamodel.facets.Annotations;
+import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
+import org.apache.isis.core.metamodel.facets.actions.publish.PublishedActionFacet;
+
+public class PublishedActionAnnotationFacetFactory extends FacetFactoryAbstract {
+
+    public PublishedActionAnnotationFacetFactory() {
+        super(FeatureType.ACTIONS_ONLY);
+    }
+
+    @Override
+    public void process(final ProcessMethodContext processMethodContext) {
+        final PublishedAction annotation = Annotations.getAnnotation(processMethodContext.getMethod(), PublishedAction.class);
+        FacetUtil.addFacet(create(annotation, processMethodContext.getFacetHolder()));
+    }
+
+    private PublishedActionFacet create(final PublishedAction annotation, final FacetHolder holder) {
+        return annotation == null ? null : new PublishedActionFacetAnnotation(newEventCanonicalizer(annotation.canonicalizeWith()), holder);
+    }
+
+    private static PublishedAction.EventCanonicalizer newEventCanonicalizer(final Class<? extends PublishedAction.EventCanonicalizer> value) {
+        if(value == null) {
+            return null;
+        }
+        try {
+            return (PublishedAction.EventCanonicalizer) value.newInstance();
+        } catch (final InstantiationException e) {
+            return null;
+        } catch (final IllegalAccessException e) {
+            return null;
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/publish/PublishedActionFacetAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/publish/PublishedActionFacetAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/publish/PublishedActionFacetAnnotation.java
new file mode 100644
index 0000000..c6ce0aa
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/publish/PublishedActionFacetAnnotation.java
@@ -0,0 +1,32 @@
+/*
+ *  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.progmodel.facets.actions.publish;
+
+import org.apache.isis.applib.annotation.PublishedAction;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.actions.publish.PublishedActionFacetAbstract;
+
+public class PublishedActionFacetAnnotation extends PublishedActionFacetAbstract {
+
+    public PublishedActionFacetAnnotation(PublishedAction.EventCanonicalizer eventCanonicalizer, final FacetHolder holder) {
+        super(eventCanonicalizer, holder);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/object/publish/PublishedObjectAnnotationFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/object/publish/PublishedObjectAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/object/publish/PublishedObjectAnnotationFacetFactory.java
new file mode 100644
index 0000000..e02d21c
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/object/publish/PublishedObjectAnnotationFacetFactory.java
@@ -0,0 +1,60 @@
+/*
+ *  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.progmodel.facets.object.publish;
+
+import org.apache.isis.applib.annotation.PublishedObject;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facetapi.FeatureType;
+import org.apache.isis.core.metamodel.facets.Annotations;
+import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
+import org.apache.isis.core.metamodel.facets.object.publish.PublishedObjectFacet;
+
+public class PublishedObjectAnnotationFacetFactory extends FacetFactoryAbstract {
+
+    public PublishedObjectAnnotationFacetFactory() {
+        super(FeatureType.OBJECTS_ONLY);
+    }
+
+    @Override
+    public void process(ProcessClassContext processClassContext) {
+        super.process(processClassContext);
+        final PublishedObject annotation = Annotations.getAnnotation(processClassContext.getCls(), PublishedObject.class);
+        FacetUtil.addFacet(create(annotation, processClassContext.getFacetHolder()));
+    }
+
+    private PublishedObjectFacet create(final PublishedObject annotation, final FacetHolder holder) {
+        return annotation == null ? null : new PublishedObjectFacetAnnotation(newEventCanonicalizer(annotation.canonicalizeWith()), holder);
+    }
+
+    private static PublishedObject.EventCanonicalizer newEventCanonicalizer(final Class<? extends PublishedObject.EventCanonicalizer> value) {
+        if(value == null) {
+            return null;
+        }
+        try {
+            return (PublishedObject.EventCanonicalizer) value.newInstance();
+        } catch (final InstantiationException e) {
+            return null;
+        } catch (final IllegalAccessException e) {
+            return null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/object/publish/PublishedObjectFacetAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/object/publish/PublishedObjectFacetAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/object/publish/PublishedObjectFacetAnnotation.java
new file mode 100644
index 0000000..a939471
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/object/publish/PublishedObjectFacetAnnotation.java
@@ -0,0 +1,36 @@
+/*
+ *  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.progmodel.facets.object.publish;
+
+import java.util.UUID;
+
+import org.apache.isis.applib.annotation.PublishedObject;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.object.publish.PublishedObjectFacetAbstract;
+
+public class PublishedObjectFacetAnnotation extends PublishedObjectFacetAbstract {
+
+    public PublishedObjectFacetAnnotation(PublishedObject.EventCanonicalizer eventCanonicalizer, final FacetHolder holder) {
+        super(eventCanonicalizer, holder);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
index 5bb4242..d92f62a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
+++ b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.progmodels.dflt;
 
+import org.apache.isis.core.metamodel.facets.object.audit.annotation.AuditableAnnotationFacetFactory;
+import org.apache.isis.core.metamodel.facets.object.audit.markerifc.AuditableMarkerInterfaceFacetFactory;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModelAbstract;
 import org.apache.isis.core.progmodel.facets.actions.bulk.annotation.BulkAnnotationFacetFactory;
 import org.apache.isis.core.progmodel.facets.actions.debug.annotation.DebugAnnotationFacetFactory;
@@ -29,6 +31,7 @@ import org.apache.isis.core.progmodel.facets.actions.notcontributed.annotation.N
 import org.apache.isis.core.progmodel.facets.actions.notinservicemenu.annotation.NotInServiceMenuAnnotationFacetFactory;
 import org.apache.isis.core.progmodel.facets.actions.notinservicemenu.method.NotInServiceMenuMethodFacetFactory;
 import org.apache.isis.core.progmodel.facets.actions.prototype.annotation.PrototypeAnnotationFacetFactory;
+import org.apache.isis.core.progmodel.facets.actions.publish.PublishedActionAnnotationFacetFactory;
 import org.apache.isis.core.progmodel.facets.actions.semantics.ActionSemanticsAnnotationFacetFactory;
 import org.apache.isis.core.progmodel.facets.actions.semantics.ActionSemanticsFallbackFacetFactory;
 import org.apache.isis.core.progmodel.facets.actions.semantics.IdempotentAnnotationFacetFactory;
@@ -106,6 +109,7 @@ import org.apache.isis.core.progmodel.facets.object.orderfields.FieldOrderAnnota
 import org.apache.isis.core.progmodel.facets.object.parseable.ParseableFacetFactory;
 import org.apache.isis.core.progmodel.facets.object.plural.annotation.PluralAnnotationFacetFactory;
 import org.apache.isis.core.progmodel.facets.object.plural.staticmethod.PluralMethodFacetFactory;
+import org.apache.isis.core.progmodel.facets.object.publish.PublishedObjectAnnotationFacetFactory;
 import org.apache.isis.core.progmodel.facets.object.regex.annotation.RegExFacetAnnotationForTypeFacetFactory;
 import org.apache.isis.core.progmodel.facets.object.title.TitleMethodFacetFactory;
 import org.apache.isis.core.progmodel.facets.object.title.annotation.TitleAnnotationFacetFactory;
@@ -433,6 +437,13 @@ public final class ProgrammingModelFacetsJava5 extends ProgrammingModelAbstract
         // so we can dogfood the NO applib "value" types
         addFactory(ValueFacetFactory.class);
 
+        // services
+        addFactory(AuditableAnnotationFacetFactory.class);
+        addFactory(AuditableMarkerInterfaceFacetFactory.class);
+
+        addFactory(PublishedActionAnnotationFacetFactory.class);
+        addFactory(PublishedObjectAnnotationFacetFactory.class);
+
         addFactory(FacetsAnnotationFacetFactory.class);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/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 21b2960..f5bfe2f 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
@@ -25,20 +25,25 @@ import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.nullValue;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
-import org.apache.log4j.Logger;
-
 import org.apache.isis.applib.DomainObjectContainer;
+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.config.InstallerAbstract;
 import org.apache.isis.core.commons.config.IsisConfiguration;
 import org.apache.isis.core.commons.factory.InstanceUtil;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapterFactory;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.runtimecontext.RuntimeContext;
 import org.apache.isis.core.metamodel.services.ServicesInjectorDefault;
 import org.apache.isis.core.metamodel.services.ServicesInjectorSpi;
-import org.apache.isis.core.metamodel.services.container.DomainObjectContainerDefault;
 import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
 import org.apache.isis.core.metamodel.specloader.classsubstitutor.ClassSubstitutor;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
@@ -63,12 +68,18 @@ import org.apache.isis.core.runtime.system.persistence.AdapterManagerSpi;
 import org.apache.isis.core.runtime.system.persistence.IdentifierGenerator;
 import org.apache.isis.core.runtime.system.persistence.IdentifierGeneratorDefault;
 import org.apache.isis.core.runtime.system.persistence.ObjectFactory;
-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.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;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
 
 /**
  * An abstract implementation of {@link PersistenceMechanismInstaller} that will
@@ -86,6 +97,9 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
     private static final String LOGGING_PROPERTY = org.apache.isis.core.runtime.logging.Logger.PROPERTY_ROOT + "persistenceSession";
     private static final Logger LOG = Logger.getLogger(PersistenceMechanismInstallerAbstract.class);
 
+
+
+    
     private SystemDependencyInjector installerLookup;
 
     public PersistenceMechanismInstallerAbstract(final String name) {
@@ -99,6 +113,10 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
         super(type, name);
     }
 
+    
+    //////////////////////////////////////////////////////////////////////
+    // createPersistenceSessionFactory
+    //////////////////////////////////////////////////////////////////////
 
     @Override
     public PersistenceSessionFactory createPersistenceSessionFactory(final DeploymentType deploymentType) {
@@ -106,6 +124,11 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
     }
 
 
+    //////////////////////////////////////////////////////////////////////
+    // createPersistenceSession
+    //////////////////////////////////////////////////////////////////////
+
+
     /**
      * Creates a {@link PersistenceSession} with internal (thread-safe) components obtained from the provided {@link PersistenceSessionFactory}.
      * 
@@ -114,6 +137,7 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
      */
     @Override
     public PersistenceSession createPersistenceSession(final PersistenceSessionFactory persistenceSessionFactory) {
+
         if (LOG.isDebugEnabled()) {
             LOG.debug("installing " + this.getClass().getName());
         }
@@ -140,7 +164,7 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
         final PersistenceSession persistenceSession = 
                 new PersistenceSession(persistenceSessionFactory, adapterFactory, objectFactory, servicesInjector, identifierGenerator, adapterManager, persistAlgorithm, objectStore);
         
-        final IsisTransactionManager transactionManager = createTransactionManager(persistenceSession, objectStore);
+        final IsisTransactionManager transactionManager = createTransactionManager(persistenceSessionFactory, persistenceSession, objectStore);
         
         ensureThatArg(persistenceSession, is(not(nullValue())));
         ensureThatArg(transactionManager, is(not(nullValue())));
@@ -148,11 +172,11 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
         persistenceSession.setDirtiableSupport(true);
         persistenceSession.setTransactionManager(transactionManager);
         
-        // ... and finally return
         return persistenceSession;
     }
 
-    
+
+
     // ///////////////////////////////////////////
     // Mandatory hook methods
     // ///////////////////////////////////////////
@@ -177,14 +201,70 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
         return new PersistAlgorithmDefault();
     }
 
+
     /**
      * Hook method to return an {@link IsisTransactionManager}.
      * 
      * <p>
      * By default returns a {@link IsisTransactionManager}.
+     * @param persistenceSessionFactory TODO
      */
-    protected IsisTransactionManager createTransactionManager(final EnlistedObjectDirtying persistor, final TransactionalResource objectStore) {
-        return new IsisTransactionManager(persistor, objectStore);
+    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());
     }
 
 
@@ -287,9 +367,8 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
         final String configuredClassName = configuration.getString(PersistenceConstants.DOMAIN_OBJECT_CONTAINER_CLASS_NAME, PersistenceConstants.DOMAIN_OBJECT_CONTAINER_NAME_DEFAULT);
         return InstanceUtil.createInstance(configuredClassName, PersistenceConstants.DOMAIN_OBJECT_CONTAINER_NAME_DEFAULT, DomainObjectContainer.class);
     }
-    
 
-    
+
     // ///////////////////////////////////////////
     // Non overridable.
     // ///////////////////////////////////////////
@@ -317,6 +396,43 @@ 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)
     // /////////////////////////////////////////////////////
@@ -336,7 +452,6 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
         return installerLookup;
     }
 
-    
     // /////////////////////////////////////////////////////
     // Dependencies (from context)
     // /////////////////////////////////////////////////////
@@ -344,8 +459,7 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
     protected SpecificationLoaderSpi getSpecificationLoader() {
         return IsisContext.getSpecificationLoader();
     }
-    
-    
+
     // /////////////////////////////////////////////////////
     // Guice
     // /////////////////////////////////////////////////////
@@ -354,9 +468,4 @@ public abstract class PersistenceMechanismInstallerAbstract extends InstallerAbs
     public List<Class<?>> getTypes() {
         return listOf(PersistenceSessionFactory.class);
     }
-
-
-    
-    
-    
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/PersistenceSessionFactoryDelegating.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/PersistenceSessionFactoryDelegating.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/PersistenceSessionFactoryDelegating.java
index 85d87df..cf3680d 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/PersistenceSessionFactoryDelegating.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/PersistenceSessionFactoryDelegating.java
@@ -19,7 +19,6 @@
 
 package org.apache.isis.core.runtime.persistence;
 
-import static org.apache.isis.core.commons.ensure.Ensure.ensureThatArg;
 import static org.apache.isis.core.commons.ensure.Ensure.ensureThatState;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
@@ -38,7 +37,6 @@ import org.apache.isis.core.metamodel.runtimecontext.RuntimeContext;
 import org.apache.isis.core.metamodel.services.ServicesInjectorSpi;
 import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
 import org.apache.isis.core.metamodel.specloader.classsubstitutor.ClassSubstitutor;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorComposite;
 import org.apache.isis.core.runtime.persistence.adaptermanager.PojoRecreator;
 import org.apache.isis.core.runtime.system.DeploymentType;
@@ -60,6 +58,7 @@ public class PersistenceSessionFactoryDelegating implements PersistenceSessionFa
     
     private List<Object> serviceList;
 
+
     private Boolean fixturesInstalled;
     
     private PojoRecreator pojoRecreator;
@@ -96,6 +95,7 @@ public class PersistenceSessionFactoryDelegating implements PersistenceSessionFa
         // check prereq dependencies injected
         ensureThatState(serviceList, is(notNullValue()));
 
+
         // a bit of a workaround, but required if anything in the metamodel (for
         // example, a
         // ValueSemanticsProvider for a date value type) needs to use the Clock
@@ -142,6 +142,7 @@ public class PersistenceSessionFactoryDelegating implements PersistenceSessionFa
     }
 
 
+
     @Override
     public final void shutdown() {
         doShutdown();

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/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 46a7543..9983657 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
@@ -30,7 +30,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.UUID;
 
+import org.apache.isis.applib.clock.Clock;
+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.commons.components.TransactionScopedComponent;
 import org.apache.isis.core.commons.ensure.Ensure;
 import org.apache.isis.core.commons.exceptions.IsisException;
@@ -39,6 +44,9 @@ import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 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.object.audit.AuditableFacet;
+import org.apache.isis.core.metamodel.facets.object.publish.PublishedObjectFacet;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociationFilters;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.CreateObjectCommand;
@@ -164,7 +172,6 @@ public class IsisTransaction implements TransactionScopedComponent {
         public boolean isComplete() {
             return isComplete;
         }
-
     }
 
 
@@ -178,11 +185,22 @@ public class IsisTransaction implements TransactionScopedComponent {
     private final UpdateNotifier updateNotifier;
     private final List<IsisException> exceptions = Lists.newArrayList();
 
+    /**
+     * could be null if none has been registered
+     */
+    private final AuditingService auditingService;
+    /**
+     * could be null if none has been registered
+     */
+    private final PublishingServiceWithCanonicalizers publishingService;
+
     private State state;
 
     private RuntimeException cause;
+    
+    private final UUID guid;
 
-    public IsisTransaction(final IsisTransactionManager transactionManager, final MessageBroker messageBroker, final UpdateNotifier updateNotifier, final TransactionalResource objectStore) {
+    public IsisTransaction(final IsisTransactionManager transactionManager, final MessageBroker messageBroker, final UpdateNotifier updateNotifier, final TransactionalResource objectStore, final AuditingService auditingService, PublishingServiceWithCanonicalizers publishingService) {
         
         ensureThatArg(transactionManager, is(not(nullValue())), "transaction manager is required");
         ensureThatArg(messageBroker, is(not(nullValue())), "message broker is required");
@@ -191,6 +209,10 @@ public class IsisTransaction implements TransactionScopedComponent {
         this.transactionManager = transactionManager;
         this.messageBroker = messageBroker;
         this.updateNotifier = updateNotifier;
+        this.auditingService = auditingService;
+        this.publishingService = publishingService;
+        
+        this.guid = UUID.randomUUID();
 
         this.state = State.IN_PROGRESS;
 
@@ -201,6 +223,14 @@ public class IsisTransaction implements TransactionScopedComponent {
     }
 
     // ////////////////////////////////////////////////////////////////
+    // GUID
+    // ////////////////////////////////////////////////////////////////
+
+    public final UUID getGuid() {
+        return guid;
+    }
+    
+    // ////////////////////////////////////////////////////////////////
     // State
     // ////////////////////////////////////////////////////////////////
 
@@ -345,7 +375,6 @@ public class IsisTransaction implements TransactionScopedComponent {
     private void doFlush() {
         
         try {
-            doAudit(getAuditEntries());
             
             objectStore.execute(Collections.unmodifiableList(commands));
             
@@ -367,13 +396,65 @@ public class IsisTransaction implements TransactionScopedComponent {
     }
 
     
-    /**
-     * Hook method for subtypes to audit as required.
-     */
-    protected void doAudit(Set<Entry<AdapterAndProperty, PreAndPostValues>> auditEntries) {
-        for (Entry<AdapterAndProperty, PreAndPostValues> auditEntry : auditEntries) {
-            LOG.info(auditEntry.getKey() + ": " + auditEntry.getValue());
+    protected void doAudit(final Set<Entry<AdapterAndProperty, PreAndPostValues>> changedObjectProperties) {
+        if(auditingService == null) {
+            return;
+        }
+        
+        // else
+        final String currentUser = getAuthenticationSession().getUserName();
+        final long currentTimestampEpoch = currentTimestampEpoch();
+        for (Entry<AdapterAndProperty, PreAndPostValues> auditEntry : changedObjectProperties) {
+            auditChangedProperty(currentUser, currentTimestampEpoch, auditEntry);
+        }
+    }
+
+    protected void doPublish(final Set<ObjectAdapter> changedAdapters) {
+        if(publishingService == null) {
+            return;
+        }
+
+        // else
+        final String currentUser = getAuthenticationSession().getUserName();
+        final long currentTimestampEpoch = currentTimestampEpoch();
+        
+        for (ObjectAdapter changedAdapter : changedAdapters) {
+            PublishedObjectFacet publishedObjectFacet = changedAdapter.getSpecification().getFacet(PublishedObjectFacet.class);
+            if(publishedObjectFacet == null) {
+                continue;
+            }
+            publishingService.publishObject(publishedObjectFacet.value(), getGuid(), currentUser, currentTimestampEpoch, changedAdapter);
+        }
+        
+        // TODO: use a ThreadLocal on ActionInvocationFacet to determine whether there is also a PublishedActionFacet to handle...
+    }
+
+    private static long currentTimestampEpoch() {
+        return Clock.getTime();
+    }
+
+    private void auditChangedProperty(final String currentUser, final long currentTimestampEpoch, final Entry<AdapterAndProperty, PreAndPostValues> auditEntry) {
+        final AdapterAndProperty aap = auditEntry.getKey();
+        final ObjectAdapter adapter = aap.getAdapter();
+        if(!adapter.getSpecification().containsFacet(AuditableFacet.class)) {
+            return;
         }
+        final RootOid oid = (RootOid) adapter.getOid();
+        final String objectType = oid.getObjectSpecId().asString();
+        final String identifier = oid.getIdentifier();
+        final PreAndPostValues papv = auditEntry.getValue();
+        final String preValue = asString(papv.getPre());
+        final String postValue = asString(papv.getPost());
+        auditingService.audit(currentUser, currentTimestampEpoch, objectType, identifier, preValue, postValue);
+    }
+
+    private static String asString(Object object) {
+        return object != null? object.toString(): null;
+    }
+
+
+    protected AuthenticationSession getAuthenticationSession() {
+        return IsisContext.getAuthenticationSession();
     }
 
 
@@ -399,8 +480,10 @@ public class IsisTransaction implements TransactionScopedComponent {
         }
         
         try {
+            doAudit(getChangedObjectProperties());
             doFlush();
             setState(State.COMMITTED);
+            doPublish(getChangedObjects());
         } catch (final RuntimeException ex) {
             setAbortCause(ex);
             throw ex;
@@ -408,6 +491,9 @@ public class IsisTransaction implements TransactionScopedComponent {
     }
 
     
+
+
+
     // ////////////////////////////////////////////////////////////////
     // abort
     // ////////////////////////////////////////////////////////////////
@@ -535,6 +621,7 @@ public class IsisTransaction implements TransactionScopedComponent {
     }
 
     public static class AdapterAndProperty {
+        
         private final ObjectAdapter objectAdapter;
         private final ObjectAssociation property;
         
@@ -602,7 +689,7 @@ public class IsisTransaction implements TransactionScopedComponent {
    
     
     ////////////////////////////////////////////////////////////////////////
-    // Auditing
+    // Auditing/Publishing object tracking
     ////////////////////////////////////////////////////////////////////////
 
     public static class PreAndPostValues {
@@ -648,29 +735,54 @@ public class IsisTransaction implements TransactionScopedComponent {
     }
     
    
-    private final Map<AdapterAndProperty, PreAndPostValues> auditLog = Maps.newLinkedHashMap();
+    private final Map<AdapterAndProperty, PreAndPostValues> changedObjectProperties = Maps.newLinkedHashMap();
+    private final Set<ObjectAdapter> changedObjects = Sets.newLinkedHashSet();
     
 
+    /**
+     * For object stores to record the current values of an {@link ObjectAdapter} that has enlisted
+     * into the transaction, prior to updating its values.
+     * 
+     * <p>
+     * The values of the {@link ObjectAdapter} after being updated are captured when the
+     * audit entries are requested, in {@link #getChangedObjectProperties()}.
+     * 
+     * <p>
+     * Supported by the JDO object store; check documentation for support in other objectstores.
+     */
     public void auditDirty(ObjectAdapter adapter) {
         for (ObjectAssociation property : adapter.getSpecification().getAssociations(ObjectAssociationFilters.PROPERTIES)) {
-            audit(adapter, property);
+            changedObjectProperty(adapter, property);
         }
     }
     
-    private void audit(ObjectAdapter adapter, ObjectAssociation property) {
+    private void changedObjectProperty(ObjectAdapter adapter, ObjectAssociation property) {
         final AdapterAndProperty aap = AdapterAndProperty.of(adapter, property);
         PreAndPostValues papv = PreAndPostValues.pre(aap.getPropertyValue());
-        auditLog.put(aap, papv);
+        changedObjectProperties.put(aap, papv);
+        changedObjects.add(adapter);
     }
 
 
-    public Set<Entry<AdapterAndProperty, PreAndPostValues>> getAuditEntries() {
-        updatePostValues(auditLog.entrySet());
+    /**
+     * Returns the pre- and post-values of all {@link ObjectAdapter}s that were enlisted and dirtied
+     * in this transaction.
+     * 
+     * <p>
+     * This requires that the object store called {@link #auditDirty(ObjectAdapter)} for each object being
+     * enlisted.
+     * 
+     * <p>
+     * Supported by the JDO object store (since it calls {@link #auditDirty(ObjectAdapter)}); 
+     * check documentation for support in other object stores.
+     */
+    public Set<Entry<AdapterAndProperty, PreAndPostValues>> getChangedObjectProperties() {
+        updatePostValues(changedObjectProperties.entrySet());
 
-        return Collections.unmodifiableSet(Sets.filter(auditLog.entrySet(), PreAndPostValues.CHANGED));
+        return Collections.unmodifiableSet(Sets.filter(changedObjectProperties.entrySet(), PreAndPostValues.CHANGED));
     }
 
-    private void updatePostValues(Set<Entry<AdapterAndProperty, PreAndPostValues>> entrySet) {
+    private static void updatePostValues(Set<Entry<AdapterAndProperty, PreAndPostValues>> entrySet) {
         for (Entry<AdapterAndProperty, PreAndPostValues> entry : entrySet) {
             final AdapterAndProperty aap = entry.getKey();
             final PreAndPostValues papv = entry.getValue();
@@ -679,13 +791,15 @@ public class IsisTransaction implements TransactionScopedComponent {
         }
     }
 
+    private Set<ObjectAdapter> getChangedObjects() {
+        return changedObjects;
+    }
 
     
     ////////////////////////////////////////////////////////////////////////
     // Dependencies (from context)
     ////////////////////////////////////////////////////////////////////////
 
-    
     protected AdapterManager getAdapterManager() {
         return IsisContext.getPersistenceSession().getAdapterManager();
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/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 e5d10d8..e8a3305 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,19 @@ import static org.hamcrest.CoreMatchers.nullValue;
 
 import java.util.List;
 
-import org.apache.log4j.Logger;
-
+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.PublishingService;
 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.runtime.persistence.ObjectPersistenceException;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommand;
 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;
+import org.apache.log4j.Logger;
 
 public class IsisTransactionManager implements SessionScopedComponent {
 
@@ -49,6 +52,15 @@ public class IsisTransactionManager implements SessionScopedComponent {
 
     private int transactionLevel;
     
+    /**
+     * Could be null.
+     */
+    private final AuditingService auditingService;
+    /**
+     * Could be null.
+     */
+    private final PublishingServiceWithCanonicalizers publishingService;
+
     private IsisSession session;
 
     /**
@@ -61,9 +73,11 @@ public class IsisTransactionManager implements SessionScopedComponent {
     // constructor
     // ////////////////////////////////////////////////////////////////
 
-    public IsisTransactionManager(final EnlistedObjectDirtying objectPersistor, final TransactionalResource objectStore) {
+    public IsisTransactionManager(final EnlistedObjectDirtying objectPersistor, final TransactionalResource objectStore, final AuditingService auditingService, final PublishingServiceWithCanonicalizers publishingService) {
         this.objectPersistor = objectPersistor;
         this.transactionalResource = objectStore;
+        this.auditingService = auditingService;
+        this.publishingService = publishingService;
     }
     
     
@@ -234,7 +248,7 @@ public class IsisTransactionManager implements SessionScopedComponent {
         ensureThatArg(messageBroker, is(not(nullValue())));
         ensureThatArg(updateNotifier, is(not(nullValue())));
 
-        return new IsisTransaction(this, messageBroker, updateNotifier, getTransactionalResource());
+        return new IsisTransaction(this, messageBroker, updateNotifier, getTransactionalResource(), auditingService, publishingService);
     }
     
 

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/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
new file mode 100644
index 0000000..df9b597
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/PublishingServiceWithCanonicalizers.java
@@ -0,0 +1,39 @@
+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/1f558615/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 524e47c..523af9b 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
@@ -33,6 +33,8 @@ import org.junit.Before;
 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.commons.config.IsisConfiguration;
 import org.apache.isis.core.commons.matchers.IsisMatchers;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -63,6 +65,7 @@ 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;
@@ -93,6 +96,10 @@ public class PersistenceSessionObjectStoreTest {
     private ObjectFactory objectFactory;
     @Mock
     private PersistAlgorithm mockPersistAlgorithm;
+    @Mock
+    private AuditingService mockAuditingService;
+    @Mock
+    private PublishingServiceWithCanonicalizers mockPublishingService;
 
     @Mock
     private CreateObjectCommand createObjectCommand;
@@ -128,6 +135,7 @@ public class PersistenceSessionObjectStoreTest {
 
         context.ignoring(mockRuntimeContext);
         context.ignoring(mockConfiguration);
+        context.ignoring(mockAuditingService);
 
         isisMetaModel = new IsisMetaModel(mockRuntimeContext, new ProgrammingModelFacetsJava5(), new CustomerRepository());
         isisMetaModel.init();
@@ -165,7 +173,7 @@ public class PersistenceSessionObjectStoreTest {
             
         };
         
-        transactionManager = new IsisTransactionManager(persistenceSession, mockObjectStore);
+        transactionManager = new IsisTransactionManager(persistenceSession, mockObjectStore, mockAuditingService, mockPublishingService);
         persistenceSession.setTransactionManager(transactionManager);
 
         servicesInjector.setServices(Collections.emptyList());

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManagerAbstractTestCase.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManagerAbstractTestCase.java b/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManagerAbstractTestCase.java
deleted file mode 100644
index b22455e..0000000
--- a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/ObjectStoreTransactionManagerAbstractTestCase.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- *  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.persistence.objectstore.transaction;
-
-import org.jmock.Expectations;
-import org.junit.Rule;
-
-import org.apache.isis.core.runtime.persistence.objectstore.transaction.TransactionalResource;
-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.unittestsupport.jmock.auto.Mock;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
-
-public abstract class ObjectStoreTransactionManagerAbstractTestCase {
-
-    @Rule
-    public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
-
-    protected IsisTransactionManager transactionManager;
-    @Mock
-    protected IsisSession mockSession;
-    @Mock
-    protected PersistenceSession mockPersistenceSession;
-    @Mock
-    protected TransactionalResource mockObjectStore;
-
-
-    // //////////////////////////////////////////////////
-    // Helpers
-    // //////////////////////////////////////////////////
-
-    protected void ignoreCallsToPersistenceSession() {
-        context.checking(new Expectations() {
-            {
-                ignoring(mockPersistenceSession);
-            }
-        });
-    }
-
-    protected void ignoreCallsToObjectStore() {
-        context.checking(new Expectations() {
-            {
-                ignoring(mockObjectStore);
-            }
-        });
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/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 8bb1461..ae29134 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
@@ -25,25 +25,50 @@ import static org.junit.Assert.assertThat;
 
 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.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.jmock.Expectations;
 import org.jmock.Sequence;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
-import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommand;
-import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
+public class ObjectStoreTransactionManager_EndTransactionTest {
+
+    @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;
 
-public class ObjectStoreTransactionManager_EndTransactionTest extends ObjectStoreTransactionManagerAbstractTestCase {
+    private IsisTransactionManager transactionManager;
 
     @Before
     public void setUpTransactionManager() throws Exception {
-        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore);
+        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore, mockAuditingService, mockPublishingService);
     }
 
     @Test
     public void endTransactionDecrementsTransactionLevel() throws Exception {
         // setup
-        ignoreCallsToObjectStore();
+        context.ignoring(mockObjectStore);
         transactionManager.startTransaction();
         transactionManager.startTransaction();
 
@@ -55,7 +80,7 @@ public class ObjectStoreTransactionManager_EndTransactionTest extends ObjectStor
     @Test
     public void endTransactionCommitsTransactionWhenLevelDecrementsDownToZero() throws Exception {
         // setup
-        ignoreCallsToObjectStore();
+        context.ignoring(mockObjectStore);
         transactionManager.startTransaction();
 
         context.checking(new Expectations() {
@@ -71,7 +96,7 @@ public class ObjectStoreTransactionManager_EndTransactionTest extends ObjectStor
     @Test
     public void startTransactionInteractsWithObjectStore() throws Exception {
         // setup
-        ignoreCallsToPersistenceSession();
+        context.ignoring(mockPersistenceSession);
 
         context.checking(new Expectations() {
             {
@@ -85,7 +110,7 @@ public class ObjectStoreTransactionManager_EndTransactionTest extends ObjectStor
     @Test
     public void endTransactionInteractsWithObjectStore() throws Exception {
         // setup
-        ignoreCallsToPersistenceSession();
+        context.ignoring(mockPersistenceSession);
 
         context.checking(new Expectations() {
             {

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/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 fbff96e..d7618c7 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,15 +19,42 @@
 
 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.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;
 
-public class ObjectStoreTransactionManager_InstantiationTest extends ObjectStoreTransactionManagerAbstractTestCase {
+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;
+
+    private IsisTransactionManager transactionManager;
 
     @Test
     public void canInstantiate() throws Exception {
-        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore);
+        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore, mockAuditingService, mockPublishingService);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/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 c7205ab..42b01ea 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,28 +25,53 @@ 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.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;
 import org.jmock.Expectations;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
-import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
-import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
+public class ObjectStoreTransactionManager_StartTransactionTest {
+
+    @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;
 
-public class ObjectStoreTransactionManager_StartTransactionTest extends ObjectStoreTransactionManagerAbstractTestCase {
+    private IsisTransactionManager transactionManager;
 
     @Before
     public void setUpTransactionManager() throws Exception {
-        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore);
+        transactionManager = new IsisTransactionManager(mockPersistenceSession, mockObjectStore, mockAuditingService, mockPublishingService);
     }
 
     @Before
     public void setUpExpectations() throws Exception {
-        ignoreCallsToPersistenceSession();
+        context.ignoring(mockPersistenceSession);
     }
 
     @Test
     public void startTransactionCreateTransactionIfNone() throws Exception {
-        ignoreCallsToObjectStore();
+        context.ignoring(mockObjectStore);
 
         assertThat(transactionManager.getTransaction(), is(nullValue()));
         transactionManager.startTransaction();
@@ -55,7 +80,7 @@ public class ObjectStoreTransactionManager_StartTransactionTest extends ObjectSt
 
     @Test
     public void startTransactionDoesNotOverwriteTransactionIfHasOne() throws Exception {
-        ignoreCallsToObjectStore();
+        context.ignoring(mockObjectStore);
 
         // cause a transaction to be created
         transactionManager.startTransaction();
@@ -68,7 +93,7 @@ public class ObjectStoreTransactionManager_StartTransactionTest extends ObjectSt
 
     @Test
     public void startTransactionIncrementsTransactionLevel() throws Exception {
-        ignoreCallsToObjectStore();
+        context.ignoring(mockObjectStore);
 
         assertThat(transactionManager.getTransactionLevel(), is(0));
         transactionManager.startTransaction();

http://git-wip-us.apache.org/repos/asf/isis/blob/1f558615/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/TransactionTest.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/TransactionTest.java b/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/TransactionTest.java
deleted file mode 100644
index b78c7d2..0000000
--- a/core/runtime/src/test/java/org/apache/isis/core/runtime/persistence/objectstore/transaction/TransactionTest.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- *  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.persistence.objectstore.transaction;
-
-import java.util.Collections;
-
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.hamcrest.CoreMatchers;
-import org.jmock.Expectations;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.apache.isis.core.commons.matchers.IsisMatchers;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.runtime.persistence.ObjectPersistenceException;
-import org.apache.isis.core.runtime.persistence.objectstore.ObjectStoreSpi;
-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.PersistenceCommandContext;
-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;
-import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
-import org.apache.isis.core.runtime.system.transaction.MessageBroker;
-import org.apache.isis.core.runtime.system.transaction.UpdateNotifier;
-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;
-
-public class TransactionTest {
-
-    @Rule
-    public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
-    
-    private IsisTransaction transaction;
-
-    private ObjectAdapter transientAdapter1;
-    private ObjectAdapter transientAdapter2;
-
-    private ObjectAdapter persistentAdapter1;
-    private ObjectAdapter persistentAdapter2;
-
-    @Mock
-    private ObjectStoreSpi mockObjectStore;
-
-    @Mock
-    private IsisTransactionManager mockTransactionManager;
-    @Mock
-    private MessageBroker mockMessageBroker;
-    @Mock
-    private UpdateNotifier mockUpdateNotifier;
-
-    private PersistenceCommand command;
-    private PersistenceCommand command2;
-    private PersistenceCommand command3;
-
-    private CreateObjectCommand createCreateCommand(final ObjectAdapter object, final String name) {
-        return new CreateObjectCommand() {
-
-            @Override
-            public void execute(final PersistenceCommandContext context) throws ObjectPersistenceException {
-            }
-
-            @Override
-            public ObjectAdapter onAdapter() {
-                return object;
-            }
-
-            @Override
-            public String toString() {
-                return name;
-            }
-        };
-    }
-
-    private DestroyObjectCommand createDestroyCommand(final ObjectAdapter object, final String name) {
-        return new DestroyObjectCommand() {
-
-            @Override
-            public void execute(final PersistenceCommandContext context) throws ObjectPersistenceException {
-            }
-
-            @Override
-            public ObjectAdapter onAdapter() {
-                return object;
-            }
-
-            @Override
-            public String toString() {
-                return name;
-            }
-        };
-    }
-
-    private SaveObjectCommand createSaveCommand(final ObjectAdapter object, final String name) {
-        return new SaveObjectCommand() {
-            @Override
-            public void execute(final PersistenceCommandContext context) throws ObjectPersistenceException {
-            }
-
-            @Override
-            public ObjectAdapter onAdapter() {
-                return object;
-            }
-
-            @Override
-            public String toString() {
-                return name;
-            }
-        };
-    }
-
-    private SaveObjectCommand createSaveCommandThatAborts(final ObjectAdapter object, final String name) {
-        return new SaveObjectCommand() {
-            @Override
-            public void execute(final PersistenceCommandContext context) throws ObjectPersistenceException {
-                throw new ObjectPersistenceException();
-            }
-
-            @Override
-            public ObjectAdapter onAdapter() {
-                return object;
-            }
-
-            @Override
-            public String toString() {
-                return name;
-            }
-        };
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        Logger.getRootLogger().setLevel(Level.OFF);
-
-        transaction = new IsisTransaction(mockTransactionManager, mockMessageBroker, mockUpdateNotifier, mockObjectStore);
-        
-        transientAdapter1 = PojoAdapterBuilder.create().with(Persistence.TRANSIENT).withIdentifier("1").build();
-        transientAdapter2 = PojoAdapterBuilder.create().with(Persistence.TRANSIENT).withIdentifier("2").build();
-        persistentAdapter1 = PojoAdapterBuilder.create().with(Persistence.PERSISTENT).withIdentifier("3").build();
-        persistentAdapter2 = PojoAdapterBuilder.create().with(Persistence.PERSISTENT).withIdentifier("4").build();
-    }
-    
-    @Test
-    public void abort_neverDelegatesToObjectStore() throws Exception {
-
-        command = createSaveCommand(transientAdapter1, "command 1");
-        command2 = createSaveCommand(transientAdapter2, "command 2");
-
-        context.checking(new Expectations() {
-            {
-                never(mockObjectStore);
-            }
-        });
-
-        transaction.addCommand(command);
-        transaction.addCommand(command2);
-        transaction.abort();
-    }
-
-
-    @Test
-    public void commit_delegatesToObjectStoreToExecutesAllCommands() throws Exception {
-
-        command = createSaveCommand(transientAdapter1, "command 1");
-        command2 = createSaveCommandThatAborts(transientAdapter2, "command 2");
-
-        context.checking(new Expectations() {
-            {
-                one(mockObjectStore).execute(with(IsisMatchers.listContainingAll(command, command2)));
-            }
-        });
-        
-        transaction.addCommand(command);
-        transaction.addCommand(command2);
-        transaction.commit();
-    }
-
-    @Test
-    public void commit_disregardsSecondSaveCommandOnSameAdapter() throws Exception {
-
-        command = createSaveCommand(persistentAdapter1, "command 1");
-        command2 = createSaveCommand(persistentAdapter1, "command 2");
-
-        context.checking(new Expectations() {
-            {
-                one(mockObjectStore).execute(with(IsisMatchers.listContainingAll(command)));
-            }
-        });
-        
-        transaction.addCommand(command);
-        transaction.addCommand(command2);
-        transaction.commit();
-    }
-
-
-    @Test
-    public void commit_disregardsSaveCommandsForObjectBeingCreated() throws Exception {
-
-        command = createCreateCommand(transientAdapter1, "command 1");
-        command2 = createSaveCommandThatAborts(transientAdapter1, "command 2");
-
-        context.checking(new Expectations() {
-            {
-                one(mockObjectStore).execute(with(IsisMatchers.listContainingAll(command)));
-            }
-        });
-        
-        transaction.addCommand(command);
-        transaction.addCommand(command2);
-        transaction.commit();
-    }
-
-    @Test
-    public void commit_destroyCausesPrecedingSaveCommandsToBeDisregarded() throws Exception {
-
-        command = createSaveCommand(persistentAdapter1, "command 1");
-        command2 = createSaveCommand(persistentAdapter2, "command 2");
-        command3 = createDestroyCommand(persistentAdapter1, "command 3");
-
-        context.checking(new Expectations() {
-            {
-                one(mockObjectStore).execute(with(IsisMatchers.listContainingAll(command2, command3)));
-            }
-        });
-        
-        transaction.addCommand(command);
-        transaction.addCommand(command2);
-        transaction.addCommand(command3);
-        transaction.commit();
-    }
-
-    @Test
-    public void commit_ignoresBothCreateAndDestroyCommandsWhenForSameObject() throws Exception {
-
-        command = createSaveCommand(persistentAdapter1, "command 1");
-        command2 = createSaveCommand(persistentAdapter2, "command 2");
-        command3 = createDestroyCommand(persistentAdapter1, "command 3");
-
-        context.checking(new Expectations() {
-            {
-                one(mockObjectStore).execute(with(IsisMatchers.listContainingAll(command2)));
-            }
-        });
-        
-        transaction.addCommand(command);
-        transaction.addCommand(command2);
-        transaction.addCommand(command3);
-        transaction.commit();
-    }
-
-
-    @Test
-    public void commit_testNoCommands() throws Exception {
-        context.checking(new Expectations() {
-            {
-                one(mockObjectStore).execute(with(Collections.<PersistenceCommand>emptyList()));
-            }
-        });
-
-        transaction.commit();
-    }
-
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldThrowExceptionIfAttemptToAbortAnAlreadyAbortedTransaction() throws Exception {
-        transaction.abort();
-
-        transaction.abort();
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldThrowExceptionIfAttemptToCommitAnAlreadyAbortedTransaction() throws Exception {
-        transaction.abort();
-
-        transaction.commit();
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldThrowExceptionIfAttemptToAbortAnAlreadyCommitedTransaction() throws Exception {
-        context.checking(new Expectations() {
-            {
-                one(mockObjectStore).execute(with(Collections.<PersistenceCommand>emptyList()));
-            }
-        });
-
-        transaction.commit();
-
-        transaction.abort();
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldThrowExceptionIfAttemptToCommitAnAlreadyCommitedTransaction() throws Exception {
-        context.checking(new Expectations() {
-            {
-                one(mockObjectStore).execute(with(Collections.<PersistenceCommand>emptyList()));
-            }
-        });
-        transaction.commit();
-
-        transaction.commit();
-    }
-}