This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch ISIS-1976-rethink-object-adapters
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 8ba3a7cdc4ed556baf1db4e81b25f96bc6739443
Author: Andi Huber <ahu...@apache.org>
AuthorDate: Mon Sep 10 13:24:19 2018 +0200

    ISIS-1976: decouple lifecycle event posting from PersistenceSession
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1976
---
 .../system/persistence/PersistenceSession4.java    |  97 ++-----------
 .../system/persistence/PersistenceSession5.java    | 107 ++------------
 .../system/persistence/PersistenceSession.java     |   3 +-
 .../system/persistence/PersistenceSessionBase.java |   9 --
 .../adaptermanager/ObjectAdapterContext.java       |  32 ++++-
 ...ObjectAdapterContext_LifecycleEventSupport.java |  96 +++++++++++++
 .../ObjectAdapterContext_ObjectCreation.java       | 158 +++++++++++++++++++++
 .../ObjectAdapterContext_ObjectReCreation.java     |  72 ----------
 8 files changed, 298 insertions(+), 276 deletions(-)

diff --git 
a/core/plugins/jdo-datanucleus-4/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession4.java
 
b/core/plugins/jdo-datanucleus-4/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession4.java
index 1acd10d..35230c5 100644
--- 
a/core/plugins/jdo-datanucleus-4/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession4.java
+++ 
b/core/plugins/jdo-datanucleus-4/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession4.java
@@ -441,95 +441,14 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
      */
     @Override
     public ObjectAdapter createTransientInstance(final ObjectSpecification 
objectSpec) {
-        return createInstance(objectSpec, Variant.TRANSIENT, null);
+        return objectAdapterContext.newInstance(objectSpec);
     }
 
     @Override
     public ObjectAdapter createViewModelInstance(final ObjectSpecification 
objectSpec, final String memento) {
-        return createInstance(objectSpec, Variant.VIEW_MODEL, memento);
+        return objectAdapterContext.recreateInstance(objectSpec, memento);
     }
 
-    private ObjectAdapter createInstance(
-            final ObjectSpecification spec,
-            final Variant variant,
-            final String memento) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("creating {} instance of {}", variant, spec);
-        }
-        final Object pojo;
-
-        if(variant == Variant.VIEW_MODEL) {
-            pojo = objectAdapterContext.recreateViewModel(spec, memento);
-        } else {
-            pojo = objectAdapterContext.instantiateAndInjectServices(spec);
-        }
-
-        final ObjectAdapter adapter = adapterFor(pojo);
-        return initializePropertiesAndDoCallback(adapter);
-    }
-
-    private ObjectAdapter initializePropertiesAndDoCallback(final 
ObjectAdapter adapter) {
-
-        // initialize new object
-        final List<ObjectAssociation> fields = 
adapter.getSpecification().getAssociations(Contributed.EXCLUDED);
-        for (ObjectAssociation field : fields) {
-            field.toDefault(adapter);
-        }
-        final Object pojo = adapter.getObject();
-        servicesInjector.injectServicesInto(pojo);
-
-        CallbackFacet.Util.callCallback(adapter, CreatedCallbackFacet.class);
-
-        if (Command.class.isAssignableFrom(pojo.getClass())) {
-
-            // special case... the command object is created while the 
transaction is being started and before
-            // the event bus service is initialized (nb: we initialize 
services *within* a transaction).  To resolve
-            // this catch-22 situation, we simply suppress the posting of this 
event for this domain class.
-
-            // this seems the least unpleasant of the various options 
available:
-            // * we could have put a check in the EventBusService to ignore 
the post if not yet initialized;
-            //   however this might hide other genuine errors
-            // * we could have used the thread-local in JdoStateManagerForIsis 
and the "skip(...)" hook in EventBusServiceJdo
-            //   to have this event be skipped; but that seems like co-opting 
some other design
-            // * we could have the transaction initialize the EventBusService 
as a "special case" before creating the Command;
-            //   but then do we worry about it being re-init'd later by the 
ServicesInitializer?
-
-            // so, doing it this way is this simplest, least obscure.
-
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("Skipping postEvent for creation of Command pojo");
-            }
-
-        } else {
-            postLifecycleEventIfRequired(adapter, 
CreatedLifecycleEventFacet.class);
-        }
-
-        return adapter;
-    }
-
-
-    // -- helper: postEvent
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    void postLifecycleEventIfRequired(
-            final ObjectAdapter adapter,
-            final Class<? extends LifecycleEventFacet> 
lifecycleEventFacetClass) {
-        final LifecycleEventFacet facet = 
adapter.getSpecification().getFacet(lifecycleEventFacetClass);
-        if(facet != null) {
-            final Class<? extends AbstractLifecycleEvent<?>> eventType = 
facet.getEventType();
-            final Object instance = InstanceUtil.createInstance(eventType);
-            final Object pojo = adapter.getObject();
-            postEvent((AbstractLifecycleEvent) instance, pojo);
-        }
-    }
-
-    void postEvent(final AbstractLifecycleEvent<Object> event, final Object 
pojo) {
-        event.setSource(pojo);
-        eventBusService.post(event);
-    }
-
-
-
 
     // -- fixture installation
 
@@ -1021,7 +940,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
         changedObjectsServiceInternal.enlistDeleting(adapter);
 
         CallbackFacet.Util.callCallback(adapter, RemovingCallbackFacet.class);
-        postLifecycleEventIfRequired(adapter, 
RemovingLifecycleEventFacet.class);
+        objectAdapterContext.postLifecycleEventIfRequired(adapter, 
RemovingLifecycleEventFacet.class);
     }
 
     @Override
@@ -1083,7 +1002,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
                 adapter = 
objectAdapterContext.addRecreatedPojoToCache(originalOid, pojo);
 
                 CallbackFacet.Util.callCallback(adapter, 
LoadedCallbackFacet.class);
-                postLifecycleEventIfRequired(adapter, 
LoadedLifecycleEventFacet.class);
+                objectAdapterContext.postLifecycleEventIfRequired(adapter, 
LoadedLifecycleEventFacet.class);
             }
         
             newAdapter = adapter;
@@ -1130,7 +1049,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
             // persisting
             // previously this was performed in the 
DataNucleusSimplePersistAlgorithm.
             CallbackFacet.Util.callCallback(adapter, 
PersistingCallbackFacet.class);
-            postLifecycleEventIfRequired(adapter, 
PersistingLifecycleEventFacet.class);
+            objectAdapterContext.postLifecycleEventIfRequired(adapter, 
PersistingLifecycleEventFacet.class);
 
         } else {
             // updating
@@ -1162,7 +1081,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
             objectAdapterContext.remapAsPersistent(adapter, persistentOid, 
this);
 
             CallbackFacet.Util.callCallback(adapter, 
PersistedCallbackFacet.class);
-            postLifecycleEventIfRequired(adapter, 
PersistedLifecycleEventFacet.class);
+            objectAdapterContext.postLifecycleEventIfRequired(adapter, 
PersistedLifecycleEventFacet.class);
 
             changedObjectsServiceInternal.enlistCreated(adapter);
 
@@ -1171,7 +1090,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
             // the callback and transaction.enlist are done in the preDirty 
callback
             // (can't be done here, as the enlist requires to capture the 
'before' values)
             CallbackFacet.Util.callCallback(adapter, 
UpdatedCallbackFacet.class);
-            postLifecycleEventIfRequired(adapter, 
UpdatedLifecycleEventFacet.class);
+            objectAdapterContext.postLifecycleEventIfRequired(adapter, 
UpdatedLifecycleEventFacet.class);
         }
 
         Version versionIfAny = getVersionIfAny(pojo);
@@ -1215,7 +1134,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
         if(!wasAlreadyEnlisted) {
             // prevent an infinite loop... don't call the 'updating()' 
callback on this object if we have already done so
             CallbackFacet.Util.callCallback(adapter, 
UpdatingCallbackFacet.class);
-            postLifecycleEventIfRequired(adapter, 
UpdatingLifecycleEventFacet.class);
+            objectAdapterContext.postLifecycleEventIfRequired(adapter, 
UpdatingLifecycleEventFacet.class);
         }
 
         ensureRootObject(pojo);
diff --git 
a/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession5.java
 
b/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession5.java
index 3441cf0..6255c81 100644
--- 
a/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession5.java
+++ 
b/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession5.java
@@ -21,8 +21,6 @@ package org.apache.isis.core.runtime.system.persistence;
 import static java.util.Objects.requireNonNull;
 import static org.apache.isis.commons.internal.base._Casts.uncheckedCast;
 
-import java.lang.reflect.Array;
-import java.lang.reflect.Modifier;
 import java.sql.Timestamp;
 import java.text.MessageFormat;
 import java.util.ArrayList;
@@ -48,7 +46,6 @@ import org.datanucleus.identity.DatastoreIdImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.isis.applib.events.lifecycle.AbstractLifecycleEvent;
 import org.apache.isis.applib.query.Query;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
@@ -58,7 +55,6 @@ import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.ensure.Assert;
 import org.apache.isis.core.commons.exceptions.IsisException;
-import org.apache.isis.core.commons.factory.InstanceUtil;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapterByIdProvider;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapterProvider;
@@ -70,9 +66,6 @@ import 
org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
 import org.apache.isis.core.metamodel.adapter.version.Version;
 import 
org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacetUtils;
 import org.apache.isis.core.metamodel.facets.object.callbacks.CallbackFacet;
-import 
org.apache.isis.core.metamodel.facets.object.callbacks.CreatedCallbackFacet;
-import 
org.apache.isis.core.metamodel.facets.object.callbacks.CreatedLifecycleEventFacet;
-import 
org.apache.isis.core.metamodel.facets.object.callbacks.LifecycleEventFacet;
 import 
org.apache.isis.core.metamodel.facets.object.callbacks.LoadedCallbackFacet;
 import 
org.apache.isis.core.metamodel.facets.object.callbacks.LoadedLifecycleEventFacet;
 import 
org.apache.isis.core.metamodel.facets.object.callbacks.PersistedCallbackFacet;
@@ -91,8 +84,6 @@ import 
org.apache.isis.core.metamodel.services.container.query.QueryCardinality;
 import org.apache.isis.core.metamodel.spec.FreeStandingList;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.spec.feature.Contributed;
-import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 import org.apache.isis.core.runtime.persistence.FixturesInstalledFlag;
 import org.apache.isis.core.runtime.persistence.NotPersistableException;
 import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
@@ -439,96 +430,14 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
      */
     @Override
     public ObjectAdapter createTransientInstance(final ObjectSpecification 
objectSpec) {
-        return createInstance(objectSpec, Variant.TRANSIENT, null);
+        return objectAdapterContext.newInstance(objectSpec);
     }
 
     @Override
     public ObjectAdapter createViewModelInstance(final ObjectSpecification 
objectSpec, final String memento) {
-        return createInstance(objectSpec, Variant.VIEW_MODEL, memento);
+        return objectAdapterContext.recreateInstance(objectSpec, memento);
     }
 
-    private ObjectAdapter createInstance(
-            final ObjectSpecification spec,
-            final Variant variant,
-            final String memento) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("creating {} instance of {}", variant, spec);
-        }
-        final Object pojo;
-
-        if(variant == Variant.VIEW_MODEL) {
-            pojo = objectAdapterContext.recreateViewModel(spec, memento);
-        } else {
-            pojo = objectAdapterContext.instantiateAndInjectServices(spec);
-
-        }
-
-        final ObjectAdapter adapter = adapterFor(pojo);
-        return initializePropertiesAndDoCallback(adapter);
-    }
-
-    private ObjectAdapter initializePropertiesAndDoCallback(final 
ObjectAdapter adapter) {
-
-        // initialize new object
-        final List<ObjectAssociation> fields = 
adapter.getSpecification().getAssociations(Contributed.EXCLUDED);
-        for (ObjectAssociation field : fields) {
-            field.toDefault(adapter);
-        }
-        final Object pojo = adapter.getObject();
-        servicesInjector.injectServicesInto(pojo);
-
-        CallbackFacet.Util.callCallback(adapter, CreatedCallbackFacet.class);
-
-        if (Command.class.isAssignableFrom(pojo.getClass())) {
-
-            // special case... the command object is created while the 
transaction is being started and before
-            // the event bus service is initialized (nb: we initialize 
services *within* a transaction).  To resolve
-            // this catch-22 situation, we simply suppress the posting of this 
event for this domain class.
-
-            // this seems the least unpleasant of the various options 
available:
-            // * we could have put a check in the EventBusService to ignore 
the post if not yet initialized;
-            //   however this might hide other genuine errors
-            // * we could have used the thread-local in JdoStateManagerForIsis 
and the "skip(...)" hook in EventBusServiceJdo
-            //   to have this event be skipped; but that seems like co-opting 
some other design
-            // * we could have the transaction initialize the EventBusService 
as a "special case" before creating the Command;
-            //   but then do we worry about it being re-init'd later by the 
ServicesInitializer?
-
-            // so, doing it this way is this simplest, least obscure.
-
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("Skipping postEvent for creation of Command pojo");
-            }
-
-        } else {
-            postLifecycleEventIfRequired(adapter, 
CreatedLifecycleEventFacet.class);
-        }
-
-        return adapter;
-    }
-
-
-    // -- helper: postEvent
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    void postLifecycleEventIfRequired(
-            final ObjectAdapter adapter,
-            final Class<? extends LifecycleEventFacet> 
lifecycleEventFacetClass) {
-        final LifecycleEventFacet facet = 
adapter.getSpecification().getFacet(lifecycleEventFacetClass);
-        if(facet != null) {
-            final Class<? extends AbstractLifecycleEvent<?>> eventType = 
facet.getEventType();
-            final Object instance = InstanceUtil.createInstance(eventType);
-            final Object pojo = adapter.getObject();
-            postEvent((AbstractLifecycleEvent) instance, pojo);
-        }
-    }
-
-    void postEvent(final AbstractLifecycleEvent<Object> event, final Object 
pojo) {
-        event.setSource(pojo);
-        eventBusService.post(event);
-    }
-
-
-
 
     // -- fixture installation
 
@@ -1017,7 +926,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
         changedObjectsServiceInternal.enlistDeleting(adapter);
 
         CallbackFacet.Util.callCallback(adapter, RemovingCallbackFacet.class);
-        postLifecycleEventIfRequired(adapter, 
RemovingLifecycleEventFacet.class);
+        objectAdapterContext.postLifecycleEventIfRequired(adapter, 
RemovingLifecycleEventFacet.class);
     }
 
     @Override
@@ -1079,7 +988,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
                 adapter = 
objectAdapterContext.addRecreatedPojoToCache(originalOid, pojo);
 
                 CallbackFacet.Util.callCallback(adapter, 
LoadedCallbackFacet.class);
-                postLifecycleEventIfRequired(adapter, 
LoadedLifecycleEventFacet.class);
+                objectAdapterContext.postLifecycleEventIfRequired(adapter, 
LoadedLifecycleEventFacet.class);
             }
         
             newAdapter = adapter;
@@ -1126,7 +1035,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
             // persisting
             // previously this was performed in the 
DataNucleusSimplePersistAlgorithm.
             CallbackFacet.Util.callCallback(adapter, 
PersistingCallbackFacet.class);
-            postLifecycleEventIfRequired(adapter, 
PersistingLifecycleEventFacet.class);
+            objectAdapterContext.postLifecycleEventIfRequired(adapter, 
PersistingLifecycleEventFacet.class);
 
         } else {
             // updating
@@ -1158,7 +1067,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
             objectAdapterContext.remapAsPersistent(adapter, persistentOid, 
this);
 
             CallbackFacet.Util.callCallback(adapter, 
PersistedCallbackFacet.class);
-            postLifecycleEventIfRequired(adapter, 
PersistedLifecycleEventFacet.class);
+            objectAdapterContext.postLifecycleEventIfRequired(adapter, 
PersistedLifecycleEventFacet.class);
 
             changedObjectsServiceInternal.enlistCreated(adapter);
 
@@ -1167,7 +1076,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
             // the callback and transaction.enlist are done in the preDirty 
callback
             // (can't be done here, as the enlist requires to capture the 
'before' values)
             CallbackFacet.Util.callCallback(adapter, 
UpdatedCallbackFacet.class);
-            postLifecycleEventIfRequired(adapter, 
UpdatedLifecycleEventFacet.class);
+            objectAdapterContext.postLifecycleEventIfRequired(adapter, 
UpdatedLifecycleEventFacet.class);
         }
 
         Version versionIfAny = getVersionIfAny(pojo);
@@ -1211,7 +1120,7 @@ implements 
IsisLifecycleListener.PersistenceSessionLifecycleManagement {
         if(!wasAlreadyEnlisted) {
             // prevent an infinite loop... don't call the 'updating()' 
callback on this object if we have already done so
             CallbackFacet.Util.callCallback(adapter, 
UpdatingCallbackFacet.class);
-            postLifecycleEventIfRequired(adapter, 
UpdatingLifecycleEventFacet.class);
+            objectAdapterContext.postLifecycleEventIfRequired(adapter, 
UpdatingLifecycleEventFacet.class);
         }
 
         ensureRootObject(pojo);
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
index 8f3967f..af0a2e8 100644
--- 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession.java
@@ -53,6 +53,7 @@ extends
     void open();
     void close();
     boolean flush();
+    void resolve(Object parent);
     
     IsisConfiguration getConfiguration();
     IsisTransactionManager getTransactionManager();
@@ -166,6 +167,6 @@ extends
 
     Object lookup(Bookmark bookmark, FieldResetPolicy fieldResetPolicy);
 
-    void resolve(Object parent);
+    
 
 }
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionBase.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionBase.java
index f597cc5..21f1e31 100644
--- 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionBase.java
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionBase.java
@@ -28,7 +28,6 @@ import org.slf4j.LoggerFactory;
 import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.command.CommandContext;
 import org.apache.isis.applib.services.command.spi.CommandService;
-import org.apache.isis.applib.services.eventbus.EventBusService;
 import org.apache.isis.applib.services.factory.FactoryService;
 import org.apache.isis.applib.services.iactn.InteractionContext;
 import org.apache.isis.applib.services.metrics.MetricsService;
@@ -67,7 +66,6 @@ abstract class PersistenceSessionBase implements 
PersistenceSession {
     protected final CommandService commandService;
 
     protected final InteractionContext interactionContext;
-    protected final EventBusService eventBusService ;
     protected final ChangedObjectsServiceInternal 
changedObjectsServiceInternal;
     protected final FactoryService factoryService;
     protected final MetricsService metricsService;
@@ -122,7 +120,6 @@ abstract class PersistenceSessionBase implements 
PersistenceSession {
         this.commandContext = lookupService(CommandContext.class);
         this.commandService = lookupService(CommandService.class);
         this.interactionContext = lookupService(InteractionContext.class);
-        this.eventBusService = lookupService(EventBusService.class);
         this.changedObjectsServiceInternal = 
lookupService(ChangedObjectsServiceInternal.class);
         this.metricsService = lookupService(MetricsService.class);
         this.factoryService = lookupService(FactoryService.class);
@@ -184,11 +181,6 @@ abstract class PersistenceSessionBase implements 
PersistenceSession {
         PERSISTENT
     }
 
-    protected enum Variant {
-        TRANSIENT,
-        VIEW_MODEL
-    }
-
     protected enum State {
         NOT_INITIALIZED, OPEN, CLOSED
     }
@@ -264,5 +256,4 @@ abstract class PersistenceSessionBase implements 
PersistenceSession {
         return new ToString(this).toString();
     }
 
-
 }
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext.java
index efff6cc..d4ac548 100644
--- 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext.java
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext.java
@@ -22,6 +22,8 @@ import java.util.Objects;
 import java.util.UUID;
 import java.util.function.Function;
 
+import javax.annotation.Nullable;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,7 +38,7 @@ import 
org.apache.isis.core.metamodel.adapter.oid.ParentedCollectionOid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.adapter.version.Version;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
-import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
+import 
org.apache.isis.core.metamodel.facets.object.callbacks.LifecycleEventFacet;
 import 
org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
 import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
@@ -135,7 +137,8 @@ public class ObjectAdapterContext {
     private final ObjectAdapterContext_NewIdentifier newIdentifierMixin;
     private final ObjectAdapterContext_ObjectAdapterByIdProvider 
objectAdapterByIdProviderMixin;
     private final ObjectAdapterContext_DependencyInjection 
dependencyInjectionMixin;
-    private final ObjectAdapterContext_ObjectReCreation objectReCreationMixin;
+    private final ObjectAdapterContext_ObjectCreation objectReCreationMixin;
+    private final ObjectAdapterContext_LifecycleEventSupport 
lifecycleEventMixin;
     
     private ObjectAdapterContext(
             ServicesInjector servicesInjector, 
@@ -151,7 +154,8 @@ public class ObjectAdapterContext {
         this.newIdentifierMixin = new ObjectAdapterContext_NewIdentifier(this, 
persistenceSession);
         this.objectAdapterByIdProviderMixin = new 
ObjectAdapterContext_ObjectAdapterByIdProvider(this, persistenceSession, 
authenticationSession);
         this.dependencyInjectionMixin = new 
ObjectAdapterContext_DependencyInjection(this, persistenceSession);
-        this.objectReCreationMixin = new 
ObjectAdapterContext_ObjectReCreation(this, persistenceSession);
+        this.objectReCreationMixin = new 
ObjectAdapterContext_ObjectCreation(this, persistenceSession);
+        this.lifecycleEventMixin = new 
ObjectAdapterContext_LifecycleEventSupport(this, persistenceSession);
         
         this.persistenceSession = persistenceSession;
         this.servicesInjector = servicesInjector;
@@ -347,10 +351,22 @@ public class ObjectAdapterContext {
         return mementoSupportMixin;
     }
     
-    // -- OBJECT RECREATION SUPPORT
+    // -- DOMAIN OBJECT CREATION SUPPORT
+    
+    public ObjectAdapter newInstance(ObjectSpecification objectSpec) {
+        return objectReCreationMixin.newInstance(objectSpec);
+    }
+    
+    public ObjectAdapter recreateInstance(ObjectSpecification objectSpec, 
@Nullable final String memento) {
+        return objectReCreationMixin.recreateInstance(objectSpec, memento);
+    }
+    
+    // -- LIFECYCLE EVENT SUPPORT
     
-    public Object recreateViewModel(final ObjectSpecification spec, final 
String memento) {
-        return objectReCreationMixin.recreateViewModel(spec, memento);
+    public void postLifecycleEventIfRequired(
+            final ObjectAdapter adapter,
+            final Class<? extends LifecycleEventFacet> 
lifecycleEventFacetClass) {
+        lifecycleEventMixin.postLifecycleEventIfRequired(adapter, 
lifecycleEventFacetClass);
     }
     
     // 
------------------------------------------------------------------------------------------------
@@ -493,4 +509,8 @@ public class ObjectAdapterContext {
 
 
 
+
+
+
+
 }
\ No newline at end of file
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_LifecycleEventSupport.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_LifecycleEventSupport.java
new file mode 100644
index 0000000..217ca05
--- /dev/null
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_LifecycleEventSupport.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.runtime.system.persistence.adaptermanager;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.events.lifecycle.AbstractLifecycleEvent;
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.eventbus.EventBusService;
+import org.apache.isis.core.commons.factory.InstanceUtil;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.object.callbacks.CallbackFacet;
+import 
org.apache.isis.core.metamodel.facets.object.callbacks.CreatedCallbackFacet;
+import 
org.apache.isis.core.metamodel.facets.object.callbacks.CreatedLifecycleEventFacet;
+import 
org.apache.isis.core.metamodel.facets.object.callbacks.LifecycleEventFacet;
+import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
+import org.apache.isis.core.metamodel.services.ServicesInjector;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.Contributed;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
+
+/**
+ * package private mixin for ObjectAdapterContext
+ * <p>
+ * Responsibility: provides life-cycle event post support
+ * </p> 
+ * @since 2.0.0-M2
+ */
+@SuppressWarnings("unused")
+class ObjectAdapterContext_LifecycleEventSupport {
+    
+    
+    private static final Logger LOG = 
LoggerFactory.getLogger(ObjectAdapterContext_LifecycleEventSupport.class);
+    private final ObjectAdapterContext objectAdapterContext;
+    private final PersistenceSession persistenceSession;
+    private final ServicesInjector servicesInjector;
+    private final SpecificationLoader specificationLoader;
+    private final EventBusService eventBusService; 
+    
+    
+    ObjectAdapterContext_LifecycleEventSupport(ObjectAdapterContext 
objectAdapterContext,
+            PersistenceSession persistenceSession) {
+        this.objectAdapterContext = objectAdapterContext;
+        this.persistenceSession = persistenceSession;
+        this.servicesInjector = persistenceSession.getServicesInjector();
+        this.specificationLoader = servicesInjector.getSpecificationLoader();
+        this.eventBusService = 
servicesInjector.lookupService(EventBusService.class);
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    void postLifecycleEventIfRequired(
+            final ObjectAdapter adapter,
+            final Class<? extends LifecycleEventFacet> 
lifecycleEventFacetClass) {
+        final LifecycleEventFacet facet = 
adapter.getSpecification().getFacet(lifecycleEventFacetClass);
+        if(facet != null) {
+            final Class<? extends AbstractLifecycleEvent<?>> eventType = 
facet.getEventType();
+            final Object instance = InstanceUtil.createInstance(eventType);
+            final Object pojo = adapter.getObject();
+            postEvent((AbstractLifecycleEvent) instance, pojo);
+        }
+    }
+    
+    //  -- HELPER
+    
+    private void postEvent(final AbstractLifecycleEvent<Object> event, final 
Object pojo) {
+        if(eventBusService!=null) {
+            event.setSource(pojo);
+            eventBusService.post(event);
+        }
+    }
+
+    
+}
\ No newline at end of file
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectCreation.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectCreation.java
new file mode 100644
index 0000000..b50a42e
--- /dev/null
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectCreation.java
@@ -0,0 +1,158 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.runtime.system.persistence.adaptermanager;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.events.lifecycle.AbstractLifecycleEvent;
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.eventbus.EventBusService;
+import org.apache.isis.core.commons.factory.InstanceUtil;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.facets.object.callbacks.CallbackFacet;
+import 
org.apache.isis.core.metamodel.facets.object.callbacks.CreatedCallbackFacet;
+import 
org.apache.isis.core.metamodel.facets.object.callbacks.CreatedLifecycleEventFacet;
+import 
org.apache.isis.core.metamodel.facets.object.callbacks.LifecycleEventFacet;
+import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
+import org.apache.isis.core.metamodel.services.ServicesInjector;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.Contributed;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
+
+/**
+ * package private mixin for ObjectAdapterContext
+ * <p>
+ * Responsibility: re-creates domain object instances  
+ * </p> 
+ * @since 2.0.0-M2
+ */
+@SuppressWarnings("unused")
+class ObjectAdapterContext_ObjectCreation {
+    
+    
+    private static final Logger LOG = 
LoggerFactory.getLogger(ObjectAdapterContext_ObjectCreation.class);
+    private final ObjectAdapterContext objectAdapterContext;
+    private final PersistenceSession persistenceSession;
+    private final ServicesInjector servicesInjector;
+    private final SpecificationLoader specificationLoader;
+    
+    ObjectAdapterContext_ObjectCreation(ObjectAdapterContext 
objectAdapterContext,
+            PersistenceSession persistenceSession) {
+        this.objectAdapterContext = objectAdapterContext;
+        this.persistenceSession = persistenceSession;
+        this.servicesInjector = persistenceSession.getServicesInjector();
+        this.specificationLoader = servicesInjector.getSpecificationLoader();
+    }
+    
+    public ObjectAdapter newInstance(ObjectSpecification objectSpec) {
+        return newInstance(objectSpec, Variant.TRANSIENT, null);
+    }
+
+    public ObjectAdapter recreateInstance(ObjectSpecification objectSpec, 
@Nullable String memento) {
+        return newInstance(objectSpec, Variant.VIEW_MODEL, memento);
+    }
+    
+    //  -- HELPER
+    
+    private enum Variant {
+        TRANSIENT,
+        VIEW_MODEL
+    }
+    
+    private ObjectAdapter newInstance(ObjectSpecification spec, Variant 
variant, String memento) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("creating {} instance of {}", variant, spec);
+        }
+        final Object pojo;
+
+        if(variant == Variant.VIEW_MODEL) {
+            pojo = recreateViewModel(spec, memento);
+        } else {
+            pojo = objectAdapterContext.instantiateAndInjectServices(spec);
+
+        }
+
+        final ObjectAdapter adapter = 
objectAdapterContext.getObjectAdapterProvider().adapterFor(pojo);
+        return initializePropertiesAndDoCallback(adapter);
+    }
+    
+    private Object recreateViewModel(final ObjectSpecification spec, final 
String memento) {
+        final ViewModelFacet facet = spec.getFacet(ViewModelFacet.class);
+        if(facet == null) {
+            throw new IllegalArgumentException("spec does not have 
ViewModelFacet; spec is " + spec.getFullIdentifier());
+        }
+
+        final Object viewModelPojo;
+        if(facet.getRecreationMechanism().isInitializes()) {
+            viewModelPojo = 
objectAdapterContext.instantiateAndInjectServices(spec);
+            facet.initialize(viewModelPojo, memento);
+        } else {
+            viewModelPojo = facet.instantiate(spec.getCorrespondingClass(), 
memento);
+        }
+        return viewModelPojo;
+    }
+    
+    private ObjectAdapter initializePropertiesAndDoCallback(final 
ObjectAdapter adapter) {
+
+        // initialize new object
+        final List<ObjectAssociation> fields = 
adapter.getSpecification().getAssociations(Contributed.EXCLUDED);
+        for (ObjectAssociation field : fields) {
+            field.toDefault(adapter);
+        }
+        final Object pojo = adapter.getObject();
+        servicesInjector.injectServicesInto(pojo);
+
+        CallbackFacet.Util.callCallback(adapter, CreatedCallbackFacet.class);
+
+        if (Command.class.isAssignableFrom(pojo.getClass())) {
+
+            // special case... the command object is created while the 
transaction is being started and before
+            // the event bus service is initialized (nb: we initialize 
services *within* a transaction).  To resolve
+            // this catch-22 situation, we simply suppress the posting of this 
event for this domain class.
+
+            // this seems the least unpleasant of the various options 
available:
+            // * we could have put a check in the EventBusService to ignore 
the post if not yet initialized;
+            //   however this might hide other genuine errors
+            // * we could have used the thread-local in JdoStateManagerForIsis 
and the "skip(...)" hook in EventBusServiceJdo
+            //   to have this event be skipped; but that seems like co-opting 
some other design
+            // * we could have the transaction initialize the EventBusService 
as a "special case" before creating the Command;
+            //   but then do we worry about it being re-init'd later by the 
ServicesInitializer?
+
+            // so, doing it this way is this simplest, least obscure.
+
+            if(LOG.isDebugEnabled()) {
+                LOG.debug("Skipping postEvent for creation of Command pojo");
+            }
+
+        } else {
+            objectAdapterContext.postLifecycleEventIfRequired(adapter, 
CreatedLifecycleEventFacet.class);
+        }
+
+        return adapter;
+    }
+
+    
+}
\ No newline at end of file
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectReCreation.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectReCreation.java
deleted file mode 100644
index cb276ac..0000000
--- 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectReCreation.java
+++ /dev/null
@@ -1,72 +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.system.persistence.adaptermanager;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
-import org.apache.isis.core.metamodel.services.ServicesInjector;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
-import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
-
-/**
- * package private mixin for ObjectAdapterContext
- * <p>
- * Responsibility: re-creates domain object instances  
- * </p> 
- * @since 2.0.0-M2
- */
-@SuppressWarnings("unused")
-class ObjectAdapterContext_ObjectReCreation {
-    
-    
-    private static final Logger LOG = 
LoggerFactory.getLogger(ObjectAdapterContext_ObjectReCreation.class);
-    private final ObjectAdapterContext objectAdapterContext;
-    private final PersistenceSession persistenceSession;
-    private final ServicesInjector servicesInjector;
-    private final SpecificationLoader specificationLoader;
-    
-    
-    ObjectAdapterContext_ObjectReCreation(ObjectAdapterContext 
objectAdapterContext,
-            PersistenceSession persistenceSession) {
-        this.objectAdapterContext = objectAdapterContext;
-        this.persistenceSession = persistenceSession;
-        this.servicesInjector = persistenceSession.getServicesInjector();
-        this.specificationLoader = servicesInjector.getSpecificationLoader();
-    }
-
-    Object recreateViewModel(final ObjectSpecification spec, final String 
memento) {
-        final ViewModelFacet facet = spec.getFacet(ViewModelFacet.class);
-        if(facet == null) {
-            throw new IllegalArgumentException("spec does not have 
ViewModelFacet; spec is " + spec.getFullIdentifier());
-        }
-
-        final Object viewModelPojo;
-        if(facet.getRecreationMechanism().isInitializes()) {
-            viewModelPojo = 
objectAdapterContext.instantiateAndInjectServices(spec);
-            facet.initialize(viewModelPojo, memento);
-        } else {
-            viewModelPojo = facet.instantiate(spec.getCorrespondingClass(), 
memento);
-        }
-        return viewModelPojo;
-    }
-    
-}
\ No newline at end of file

Reply via email to