You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2018/09/08 23:13:45 UTC

[isis] 04/06: ISIS-1976: refactoring OA creation into separated OidProviders

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 05d91d57b2565df02e93e38e6c08f04ef0e56ba2
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sat Sep 8 23:53:39 2018 +0200

    ISIS-1976: refactoring OA creation into separated OidProviders
    
    (intermediate step)
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1976
---
 .../apache/isis/core/commons/ensure/Assert.java    |  10 +-
 .../isis/core/metamodel/adapter/oid/RootOid.java   |  23 +++-
 .../specloader/specimpl/FacetedMethodsBuilder.java |  18 ----
 .../persistence/PersistenceSession5_Decouple.java  |   2 +
 .../runtime/persistence/adapter/PojoAdapter.java   |   2 -
 .../adaptermanager/ObjectAdapterContext.java       |  29 ++----
 .../ObjectAdapterContext_NewIdentifier.java        |   3 +
 ...ObjectAdapterContext_ObjectAdapterProvider.java |  53 +++++++++-
 .../adaptermanager/OidAdapterHashMap.java          |  13 ++-
 .../persistence/adaptermanager/OidProviders.java   | 116 +++++++++++++++++++++
 .../adaptermanager/factories/OidFactory.java       |  48 +++++++++
 .../factories/OidFactory_Builder.java              |  66 ++++++++++++
 .../model/mementos/ObjectAdapterMemento.java       |   5 +
 13 files changed, 340 insertions(+), 48 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/ensure/Assert.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/ensure/Assert.java
index 197be18..77f9acf 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/commons/ensure/Assert.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/ensure/Assert.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.core.commons.ensure;
 
+import java.util.Objects;
+
 public final class Assert {
 
     public static void assertFalse(final String message, final boolean flag) {
@@ -46,5 +48,11 @@ public final class Assert {
             throw new IsisAssertException(message + (target == null ? "" : (": " + target)));
         }
     }
-
+    
+    public static void assertEquals(final String message, Object left, Object right) {
+        if (!Objects.equals(left, right)) {
+            throw new IsisAssertException(message + String.format(": '%s' != '%s' ", ""+left, ""+right));
+        }
+    }
+    
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
index 3136020..2f67f7e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
@@ -204,8 +204,6 @@ public class RootOid implements TypedOid, Serializable {
         return state.isPersistent();
     }
 
-
-
     // -- Version
 
     @Override
@@ -284,7 +282,28 @@ public class RootOid implements TypedOid, Serializable {
         return enString();
     }
 
+    // -- ROOT-ID SUPPORT FOR VALUE
+    
+    public boolean isValue() {
+        return false;
+    }
+    
+    private RootOid() { identifier=null; objectSpecId=null; state=null; };
+    
+    private static final RootOid VALUE_OID = new RootOid() {
+        private static final long serialVersionUID = 1L;
 
+        @Override
+        public boolean isValue() {
+            return true;
+        }
+    };
+    
+    public static RootOid value() {
+        return VALUE_OID;
+    }
+    
+    // --
 
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
index bd24115..4d77fdf 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
@@ -28,7 +28,6 @@ import java.util.List;
 import java.util.Set;
 
 import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -164,14 +163,6 @@ public class FacetedMethodsBuilder {
 
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        super.finalize();
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("finalizing inspector {}", this);
-        }
-    }
-
     // ////////////////////////////////////////////////////////////////////////////
     // Class and stuff immediately derived from class
     // ////////////////////////////////////////////////////////////////////////////
@@ -214,15 +205,6 @@ public class FacetedMethodsBuilder {
 
     }
 
-    // REVIEW: good news - looks like this hacky code is unused and so can be deleted.
-    private static boolean isPrimitiveOrJdkOrJodaOrGuava(final Class<?> cls) {
-        if(cls.isPrimitive()) {
-            return true;
-        }
-        final String className = cls.getName();
-        return className.startsWith("java.") || className.startsWith("javax.") || className.startsWith("org.joda") || className.startsWith("com.google.common");
-    }
-
     // ////////////////////////////////////////////////////////////////////////////
     // introspect associations
     // ////////////////////////////////////////////////////////////////////////////
diff --git a/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession5_Decouple.java b/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession5_Decouple.java
index 9eb2613..5568f4d 100644
--- a/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession5_Decouple.java
+++ b/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSession5_Decouple.java
@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
 
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.concurrency.ConcurrencyChecking;
@@ -103,6 +104,7 @@ class PersistenceSession5_Decouple  {
 
         final ObjectAdapter serviceAdapter = objectAdapterContext.lookupServiceAdapterFor(rootOid);
         if (serviceAdapter != null) {
+            _Exceptions.unexpectedCodeReach();
             return serviceAdapter;
         }
         
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java
index e709e10..a83c9a8 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java
@@ -19,8 +19,6 @@
 
 package org.apache.isis.core.runtime.persistence.adapter;
 
-import java.util.function.Function;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
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 60329a9..fa273bc 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
@@ -96,14 +96,6 @@ public class ObjectAdapterContext {
             return adapter;
         }
         
-        private void putPojo(Object pojo, ObjectAdapter adapter) {
-            pojoAdapterMap.add(adapter.getObject(), adapter);
-        }
-        
-        private void removePojo(ObjectAdapter adapter) {
-            pojoAdapterMap.remove(adapter);
-        }
-        
         private ObjectAdapter lookupAdapterById(Oid oid) {
             return oidAdapterMap.getAdapter(oid);
         }
@@ -113,22 +105,17 @@ public class ObjectAdapterContext {
                 return; // nothing to do
             }
             final Oid oid = adapter.getOid();
-            if (oid != null) { // eg. value objects don't have an Oid
-                oidAdapterMap.add(oid, adapter);
-            }
-            putPojo(adapter.getObject(), adapter);
+            oidAdapterMap.add(oid, adapter);
+            pojoAdapterMap.add(adapter.getObject(), adapter);
         }
         
         private void removeAdapter(ObjectAdapter adapter) {
-            LOG.debug("removing adapter: {}", adapter);
             if(adapter==null) {
                 return; // nothing to do
             }
             final Oid oid = adapter.getOid();
-            if (oid != null) { // eg. value objects don't have an Oid
-                oidAdapterMap.remove(oid);
-            }
-            removePojo(adapter);
+            oidAdapterMap.remove(oid);
+            pojoAdapterMap.remove(adapter);
         }
         
     }
@@ -152,7 +139,7 @@ public class ObjectAdapterContext {
             PersistenceSession persistenceSession) {
         
         this.consistencyMixin = new ObjectAdapterContext_Consistency(this);
-        this.objectAdapterProviderMixin = new ObjectAdapterContext_ObjectAdapterProvider(this, persistenceSession);
+        this.objectAdapterProviderMixin = new ObjectAdapterContext_ObjectAdapterProvider(this, persistenceSession, authenticationSession);
         this.adapterManagerMixin = new ObjectAdapterContext_AdapterManager(this, persistenceSession);
         this.mementoSupportMixin = new ObjectAdapterContext_MementoSupport(this, persistenceSession);
         this.serviceLookupMixin = new ObjectAdapterContext_ServiceLookup(this, servicesInjector);
@@ -460,9 +447,11 @@ public class ObjectAdapterContext {
             final Object collectionPojoActuallyOnPojo = getCollectionPojo(otma, adapterReplacement);
 
             if (collectionPojoActuallyOnPojo != collectionPojoWrappedByAdapter) {
-                cache.removePojo(collectionAdapter);
+                cache.removeAdapter(collectionAdapter);
                 final ObjectAdapter newCollectionAdapter = collectionAdapter.withPojo(collectionPojoActuallyOnPojo);
-                cache.putPojo(collectionPojoActuallyOnPojo, newCollectionAdapter);
+                Assert.assertTrue("expected same", 
+                        Objects.equals(newCollectionAdapter.getObject(), collectionPojoActuallyOnPojo));
+                cache.addAdapter(collectionAdapter);
             }
         }
         
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_NewIdentifier.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_NewIdentifier.java
index 31995e8..5199d79 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_NewIdentifier.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_NewIdentifier.java
@@ -21,6 +21,7 @@ package org.apache.isis.core.runtime.system.persistence.adaptermanager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
@@ -92,7 +93,9 @@ class ObjectAdapterContext_NewIdentifier {
 
     RootOid newIdentifier(final Object pojo, final Oid.State type) {
         final ObjectSpecification spec = objectSpecFor(pojo);
+      //FIXME[ISIS-1976] remove guard 
         if(spec.isService()) {
+            //_Exceptions.throwUnexpectedCodeReach(); 
             return newRootId(spec, PersistenceSession.SERVICE_IDENTIFIER, Oid.State.PERSISTENT); // services are always persistent
         }
 
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterProvider.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterProvider.java
index 75d6e38..776c4db 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterProvider.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterProvider.java
@@ -26,10 +26,13 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.isis.commons.internal.base._Lazy;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.ensure.Assert;
 import org.apache.isis.core.metamodel.IsisJdoMetamodelPlugin;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapterProvider;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
 import org.apache.isis.core.metamodel.services.ServicesInjector;
@@ -37,7 +40,9 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.core.runtime.persistence.adapter.PojoAdapter;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
+import org.apache.isis.core.runtime.system.persistence.adaptermanager.factories.OidFactory;
 
 /**
  * package private mixin for ObjectAdapterContext
@@ -52,17 +57,29 @@ class ObjectAdapterContext_ObjectAdapterProvider implements ObjectAdapterProvide
     private static final Logger LOG = LoggerFactory.getLogger(ObjectAdapterContext_ObjectAdapterProvider.class);
     private final ObjectAdapterContext objectAdapterContext;
     private final PersistenceSession persistenceSession;
+    private final AuthenticationSession authenticationSession;
     private final ServicesInjector servicesInjector;
     private final SpecificationLoader specificationLoader; 
-    private final IsisJdoMetamodelPlugin isisJdoMetamodelPlugin; 
+    private final IsisJdoMetamodelPlugin isisJdoMetamodelPlugin;
+    private final OidFactory oidFactory; 
     
     ObjectAdapterContext_ObjectAdapterProvider(ObjectAdapterContext objectAdapterContext,
-            PersistenceSession persistenceSession) {
+            PersistenceSession persistenceSession, AuthenticationSession authenticationSession) {
         this.objectAdapterContext = objectAdapterContext;
         this.persistenceSession = persistenceSession;
+        this.authenticationSession = authenticationSession;
         this.servicesInjector = persistenceSession.getServicesInjector();
         this.specificationLoader = servicesInjector.getSpecificationLoader();
         this.isisJdoMetamodelPlugin = IsisJdoMetamodelPlugin.get();
+        
+        this.oidFactory = OidFactory.builder(pojo->specificationLoader.loadSpecification(pojo.getClass()))
+                .add(new OidProviders.OidForServices())
+                .add(new OidProviders.OidForValues())
+                .add(new OidProviders.OidForViewModels())
+                .add(new OidProviders.OidForPersistables())
+                .add(new OidProviders.OidForMixins())
+                .add(new OidProviders.OidForStandaloneCollections())
+                .build();
     }
 
 //    @Override
@@ -85,6 +102,25 @@ class ObjectAdapterContext_ObjectAdapterProvider implements ObjectAdapterProvide
         if(pojo == null) {
             return null;
         }
+        
+        final  ObjectAdapter existing = objectAdapterContext.lookupAdapterByPojo(pojo);
+        if (existing != null) {
+            return existing;
+        }
+        
+        final RootOid rootOid2 = oidFactory.oidFor(pojo);
+        
+//        if(rootOid2==null) {
+//            System.err.println("!!! "+pojo);
+//            _Exceptions.throwUnexpectedCodeReach();
+//        }
+//        
+//        if(rootOid2!=null && rootOid2.isValue()) {
+//            return objectAdapterContext.getFactories().createRootAdapter(pojo, null);
+//        }
+        
+        // -- legacy code
+        
         final ObjectAdapter existingOrValueAdapter = existingOrValueAdapter(pojo);
         if(existingOrValueAdapter != null) {
             return existingOrValueAdapter;
@@ -92,6 +128,19 @@ class ObjectAdapterContext_ObjectAdapterProvider implements ObjectAdapterProvide
 
         final RootOid rootOid = objectAdapterContext.createTransientOrViewModelOid(pojo);
         
+      //at this point we know its not a value
+        if(rootOid2==null) {
+            System.err.println("!!! expected "+rootOid);
+            _Exceptions.throwUnexpectedCodeReach();
+        }
+        
+        
+        if(rootOid2!=null && rootOid2.isValue()) {
+            Assert.assertEquals("expected same", rootOid, null);
+        } else if(!rootOid.isTransient()) {
+            Assert.assertEquals("expected same", rootOid, rootOid2);    
+        }
+        
         final ObjectAdapter newAdapter = objectAdapterContext.getFactories().createRootAdapter(pojo, rootOid);
 
         return objectAdapterContext.mapAndInjectServices(newAdapter);
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/OidAdapterHashMap.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/OidAdapterHashMap.java
index da321e1..ea99b7b 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/OidAdapterHashMap.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/OidAdapterHashMap.java
@@ -22,6 +22,8 @@ package org.apache.isis.core.runtime.system.persistence.adaptermanager;
 import java.util.Iterator;
 import java.util.Map;
 
+import javax.annotation.Nullable;
+
 import com.google.common.collect.Maps;
 
 import org.slf4j.Logger;
@@ -62,8 +64,10 @@ class OidAdapterHashMap implements Iterable<Oid>, SessionScopedComponent {
     /**
      * Add an adapter for a given oid
      */
-    public void add(final Oid oid, final ObjectAdapter adapter) {
-
+    public void add(@Nullable final Oid oid, final ObjectAdapter adapter) {
+        if(oid==null) { // eg. value objects don't have an Oid
+            return;
+        }
         adapterByOidMap.put(oid, adapter);
         // log at end so that if toString needs adapters they're in maps.
         if (LOG.isDebugEnabled()) {
@@ -80,7 +84,10 @@ class OidAdapterHashMap implements Iterable<Oid>, SessionScopedComponent {
      *
      * @return <tt>true</tt> if an adapter was removed.
      */
-    public boolean remove(final Oid oid) {
+    public boolean remove(@Nullable final Oid oid) {
+        if(oid==null) { // eg. value objects don't have an Oid
+            return false;
+        }
         LOG.debug("remove oid: {}", oid);
         return adapterByOidMap.remove(oid) != null;
     }
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/OidProviders.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/OidProviders.java
new file mode 100644
index 0000000..e01e83e
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/OidProviders.java
@@ -0,0 +1,116 @@
+package org.apache.isis.core.runtime.system.persistence.adaptermanager;
+
+import org.apache.isis.core.metamodel.IsisJdoMetamodelPlugin;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
+import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
+import org.apache.isis.core.runtime.system.persistence.adaptermanager.factories.OidFactory.OidProvider;
+
+public class OidProviders {
+
+    public static class OidForServices implements OidProvider {
+
+        @Override
+        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+            return spec.isService();
+        }
+
+        @Override
+        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+            final String identifier = PersistenceSession.SERVICE_IDENTIFIER;
+            return new RootOid(spec.getSpecId(), identifier, Oid.State.PERSISTENT);
+        }
+
+    }
+
+    public static class OidForPersistables implements OidProvider {
+
+        private final IsisJdoMetamodelPlugin isisJdoMetamodelPlugin = IsisJdoMetamodelPlugin.get();
+
+        @Override
+        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+            // equivalent to  isInstanceOfPersistable = pojo instanceof Persistable;
+            final boolean isInstanceOfPersistable = isisJdoMetamodelPlugin.isPersistenceEnhanced(pojo.getClass());
+            return isInstanceOfPersistable;
+        }
+
+        @Override
+        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+            final PersistenceSession persistenceSession = IsisContext.getPersistenceSession().get();
+            final Oid.State state = persistenceSession.isTransient(pojo) ? Oid.State.TRANSIENT : Oid.State.PERSISTENT;
+            final String identifier = persistenceSession.identifierFor(pojo, state);
+            return new RootOid(spec.getSpecId(), identifier, state);
+        }
+
+    }
+
+
+    public static class OidForValues implements OidProvider {
+
+        @Override
+        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+            return spec.containsFacet(ValueFacet.class);
+        }
+
+        @Override
+        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+            return RootOid.value();
+        }
+
+    }
+    
+    public static class OidForViewModels implements OidProvider {
+
+        @Override
+        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+            return spec.containsFacet(ViewModelFacet.class);
+        }
+
+        @Override
+        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+            final ViewModelFacet recreatableObjectFacet = spec.getFacet(ViewModelFacet.class);
+            final String identifier = recreatableObjectFacet.memento(pojo);
+            return new RootOid(spec.getSpecId(), identifier, Oid.State.VIEWMODEL);
+        }
+
+    }
+    
+    public static class OidForMixins implements OidProvider {
+
+        @Override
+        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+            return spec.isMixin();
+        }
+
+        @Override
+        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+            final PersistenceSession persistenceSession = IsisContext.getPersistenceSession().get();
+            final String identifier = persistenceSession.identifierFor(pojo, Oid.State.TRANSIENT);
+            return new RootOid(spec.getSpecId(), identifier, Oid.State.TRANSIENT);
+        }
+
+    }
+    
+    public static class OidForStandaloneCollections implements OidProvider {
+
+        @Override
+        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+            return true; //FIXME spec.isParentedOrFreeCollection() && !spec.isParented();
+        }
+
+        @Override
+        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+            final PersistenceSession persistenceSession = IsisContext.getPersistenceSession().get();
+            final String identifier = persistenceSession.identifierFor(pojo, Oid.State.TRANSIENT);
+            return new RootOid(spec.getSpecId(), identifier, Oid.State.TRANSIENT);
+        }
+
+    }
+    
+    
+
+}
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory.java
new file mode 100644
index 0000000..d3646ae
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory.java
@@ -0,0 +1,48 @@
+/*
+ *  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.factories;
+
+import java.util.function.Function;
+
+import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+/**
+ * @since 2.0.0-M2
+ */
+public interface OidFactory {
+    
+    RootOid oidFor(Object pojo);
+    
+    public interface OidProvider {
+        boolean isHandling(Object pojo, ObjectSpecification spec);
+        RootOid oidFor(Object pojo, ObjectSpecification spec);
+    }
+    
+    public interface OidFactoryBuilder {
+        OidFactoryBuilder add(OidProvider handler);
+        OidFactory build();
+    }
+    
+    public static OidFactoryBuilder builder(Function<Object, ObjectSpecification> specProvider) {
+        return new OidFactory_Builder(specProvider);
+    }
+
+}
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory_Builder.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory_Builder.java
new file mode 100644
index 0000000..a7bb938
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/factories/OidFactory_Builder.java
@@ -0,0 +1,66 @@
+/*
+ *  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.factories;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.runtime.system.persistence.adaptermanager.factories.OidFactory.OidFactoryBuilder;
+import org.apache.isis.core.runtime.system.persistence.adaptermanager.factories.OidFactory.OidProvider;
+
+class OidFactory_Builder implements OidFactoryBuilder {
+    
+    private final List<OidProvider> handler = new ArrayList<>();
+    private final Function<Object, ObjectSpecification> specProvider;
+    
+    public OidFactory_Builder(Function<Object, ObjectSpecification> specProvider) {
+        this.specProvider = specProvider;
+    }
+
+    @Override
+    public OidFactoryBuilder add(OidProvider oidProvider) {
+        handler.add(oidProvider);
+        return this;
+    }
+
+    @Override
+    public OidFactory build() {
+        return new OidFactory() {
+            
+            @Override
+            public RootOid oidFor(Object pojo) {
+                
+                final ObjectSpecification spec = specProvider.apply(pojo);
+                
+                return handler.stream()
+                .filter(h->h.isHandling(pojo, spec))
+                .findFirst()
+                .map(h->h.oidFor(pojo, spec))
+                .orElse(null);
+            }
+            
+        };
+    }
+    
+
+}
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
index 243cbac..f422f28 100644
--- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
@@ -432,6 +432,11 @@ public class ObjectAdapterMemento implements Serializable {
         }
 
         final RootOid oid = (RootOid) adapter.getOid();
+        
+        if(oid==null) {
+            System.out.println("!!! "+adapter.getSpecification());
+        }
+        
         if (oid.isTransient()) {
             transientMemento = new Memento(adapter);
             type = Type.TRANSIENT;