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/06 16:13:03 UTC

[isis] 16/18: ISIS-1976: lazy initialize OAs for services

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 9eacd3ca14c1d790940f0b61f034a603d672dab0
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Sep 6 13:02:52 2018 +0200

    ISIS-1976: lazy initialize OAs for services
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1976
---
 .../metamodel/adapter/ObjectAdapterProvider.java   |  18 +--
 .../core/metamodel/services/ServicesInjector.java  |   8 ++
 .../system/persistence/PersistenceSession4.java    |  65 +---------
 .../system/persistence/PersistenceSession5.java    |  65 +---------
 .../persistence/PersistenceSession5_Decouple.java  |  16 ++-
 .../system/persistence/PersistenceSession.java     |  14 ++-
 .../adaptermanager/ObjectAdapterContext.java       |  63 +++++++---
 .../ObjectAdapterContext_NewIdentifier.java        | 129 ++++++++++++++++++++
 ...ObjectAdapterContext_ObjectAdapterProvider.java | 132 +++++++++++----------
 .../ObjectAdapterContext_ServiceLookup.java        | 109 +++++++++++++++++
 10 files changed, 402 insertions(+), 217 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapterProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapterProvider.java
index fef5bf7..3b8e0ec 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapterProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapterProvider.java
@@ -37,11 +37,11 @@ public interface ObjectAdapterProvider {
     
     // -- INTERFACE
 
-    /**
-     * @param pojo
-     * @return oid for the given domain object 
-     */
-    Oid oidFor(Object domainObject);
+//    /**
+//     * @param pojo
+//     * @return oid for the given domain object 
+//     */
+//    Oid oidFor(Object domainObject);
     
     /**
      * @return standalone (value) or root adapter
@@ -86,10 +86,10 @@ public interface ObjectAdapterProvider {
         @Programmatic
         ObjectAdapterProvider getObjectAdapterProvider();
         
-        @Programmatic
-        default Oid oidFor(Object domainObject) {
-            return getObjectAdapterProvider().oidFor(domainObject);
-        }
+//        @Programmatic
+//        default Oid oidFor(Object domainObject) {
+//            return getObjectAdapterProvider().oidFor(domainObject);
+//        }
         
         @Programmatic
         default ObjectAdapter adapterFor(Object domainObject) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java
index c345f38..444211e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -213,6 +214,13 @@ public class ServicesInjector implements ApplicationScopedComponent {
         return Collections.unmodifiableList(services);
     }
     
+    /**
+     * @return Stream of all currently registered service instances.
+     */
+    public Stream<Object> streamRegisteredServiceInstances() {
+        return services.stream();
+    }
+    
     // -- INJECT SERVICES INTO
 
     /**
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 d22ef39..e5e0b8c 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
@@ -1175,7 +1175,7 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
             }
             
         } else {
-            originalOid = createPersistentOrViewModelOid(pojo);
+            originalOid = objectAdapterContext.createPersistentOrViewModelOid(pojo);
 
             ObjectAdapter adapter;
             
@@ -1200,70 +1200,13 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
         return objectAdapterContext.lookupAdapterFor(pojo);
     }
 
-    // -- create...Oid (main API)
-    /**
-     * Create a new {@link Oid#isTransient() transient} {@link Oid} for the
-     * supplied pojo, uniquely distinguishable from any other {@link Oid}.
-     */
     @Override
-    public final RootOid createTransientOrViewModelOid(final Object pojo) {
-        return newIdentifier(pojo, Type.TRANSIENT);
-    }
-
-    /**
-     * Return an equivalent {@link RootOid}, but being persistent.
-     *
-     * <p>
-     * It is the responsibility of the implementation to determine the new unique identifier.
-     * For example, the generator may simply assign a new value from a sequence, or a GUID;
-     * or, the generator may use the oid to look up the object and inspect the object in order
-     * to obtain an application-defined value.
-     *
-     * @param pojo - being persisted
-     */
-    @Override
-    public final RootOid createPersistentOrViewModelOid(Object pojo) {
-        return newIdentifier(pojo, Type.PERSISTENT);
-    }
-
-    private RootOid newIdentifier(final Object pojo, final Type type) {
-        final ObjectSpecification spec = objectSpecFor(pojo);
-        if(spec.isService()) {
-            return newRootId(spec, SERVICE_IDENTIFIER, type);
-        }
-
-        final ViewModelFacet recreatableObjectFacet = spec.getFacet(ViewModelFacet.class);
-        final String identifier =
-                recreatableObjectFacet != null
-                ? recreatableObjectFacet.memento(pojo)
-                        : newIdentifierFor(pojo, type);
-
-                return newRootId(spec, identifier, type);
-    }
-
-    private String newIdentifierFor(final Object pojo, final Type type) {
-        return type == Type.TRANSIENT
+    public String identifierFor(final Object pojo, final Oid.State type) {
+        return type == Oid.State.TRANSIENT
                 ? UUID.randomUUID().toString()
                         : JdoObjectIdSerializer.toOidIdentifier(getPersistenceManager().getObjectId(pojo));
     }
 
-    private RootOid newRootId(final ObjectSpecification spec, final String identifier, final Type type) {
-        final Oid.State state =
-                spec.containsDoOpFacet(ViewModelFacet.class)
-                ? Oid.State.VIEWMODEL
-                        : type == Type.TRANSIENT
-                        ? Oid.State.TRANSIENT
-                                : Oid.State.PERSISTENT;
-        final ObjectSpecId objectSpecId = spec.getSpecId();
-        return new RootOid(objectSpecId, identifier, state);
-    }
-
-    private ObjectSpecification objectSpecFor(final Object pojo) {
-        final Class<?> pojoClass = pojo.getClass();
-        return getSpecificationLoader().loadSpecification(pojoClass);
-    }
-
-
 
     /**
      * Called either when an entity is initially persisted, or when an entity is updated; fires the appropriate
@@ -1313,7 +1256,7 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
 
         if (rootOid.isTransient()) {
             // persisting
-            final RootOid persistentOid = createPersistentOrViewModelOid(pojo);
+            final RootOid persistentOid = objectAdapterContext.createPersistentOrViewModelOid(pojo);
 
             objectAdapterContext.remapAsPersistent(adapter, persistentOid, this);
 
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 8fdeef5..e77e5fb 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
@@ -1167,7 +1167,7 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
             }
             
         } else {
-            originalOid = createPersistentOrViewModelOid(pojo);
+            originalOid = objectAdapterContext.createPersistentOrViewModelOid(pojo);
 
             ObjectAdapter adapter;
             
@@ -1192,70 +1192,13 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
         return objectAdapterContext.lookupAdapterFor(pojo);
     }
 
-    // -- create...Oid (main API)
-    /**
-     * Create a new {@link Oid#isTransient() transient} {@link Oid} for the
-     * supplied pojo, uniquely distinguishable from any other {@link Oid}.
-     */
     @Override
-    public final RootOid createTransientOrViewModelOid(final Object pojo) {
-        return newIdentifier(pojo, Type.TRANSIENT);
-    }
-
-    /**
-     * Return an equivalent {@link RootOid}, but being persistent.
-     *
-     * <p>
-     * It is the responsibility of the implementation to determine the new unique identifier.
-     * For example, the generator may simply assign a new value from a sequence, or a GUID;
-     * or, the generator may use the oid to look up the object and inspect the object in order
-     * to obtain an application-defined value.
-     *
-     * @param pojo - being persisted
-     */
-    @Override
-    public final RootOid createPersistentOrViewModelOid(Object pojo) {
-        return newIdentifier(pojo, Type.PERSISTENT);
-    }
-
-    private RootOid newIdentifier(final Object pojo, final Type type) {
-        final ObjectSpecification spec = objectSpecFor(pojo);
-        if(spec.isService()) {
-            return newRootId(spec, SERVICE_IDENTIFIER, type);
-        }
-
-        final ViewModelFacet recreatableObjectFacet = spec.getFacet(ViewModelFacet.class);
-        final String identifier =
-                recreatableObjectFacet != null
-                ? recreatableObjectFacet.memento(pojo)
-                        : newIdentifierFor(pojo, type);
-
-                return newRootId(spec, identifier, type);
-    }
-
-    private String newIdentifierFor(final Object pojo, final Type type) {
-        return type == Type.TRANSIENT
+    public String identifierFor(final Object pojo, final Oid.State type) {
+        return type == Oid.State.TRANSIENT
                 ? UUID.randomUUID().toString()
                         : JdoObjectIdSerializer.toOidIdentifier(getPersistenceManager().getObjectId(pojo));
     }
 
-    private RootOid newRootId(final ObjectSpecification spec, final String identifier, final Type type) {
-        final Oid.State state =
-                spec.containsDoOpFacet(ViewModelFacet.class)
-                ? Oid.State.VIEWMODEL
-                        : type == Type.TRANSIENT
-                        ? Oid.State.TRANSIENT
-                                : Oid.State.PERSISTENT;
-        final ObjectSpecId objectSpecId = spec.getSpecId();
-        return new RootOid(objectSpecId, identifier, state);
-    }
-
-    private ObjectSpecification objectSpecFor(final Object pojo) {
-        final Class<?> pojoClass = pojo.getClass();
-        return getSpecificationLoader().loadSpecification(pojoClass);
-    }
-
-
 
     /**
      * Called either when an entity is initially persisted, or when an entity is updated; fires the appropriate
@@ -1305,7 +1248,7 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
 
         if (rootOid.isTransient()) {
             // persisting
-            final RootOid persistentOid = createPersistentOrViewModelOid(pojo);
+            final RootOid persistentOid = objectAdapterContext.createPersistentOrViewModelOid(pojo);
 
             objectAdapterContext.remapAsPersistent(adapter, persistentOid, this);
 
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 492857b..f5054f0 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
@@ -82,7 +82,13 @@ class PersistenceSession5_Decouple  {
     public ObjectAdapter adapterFor(
             final RootOid rootOid,
             final ConcurrencyChecking concurrencyChecking) {
-
+        
+        //FIXME[ISIS-1976] guard against service lookup
+        final ObjectAdapter serviceAdapter = objectAdapterContext.lookupServiceAdapterFor(rootOid);
+        if (serviceAdapter != null) {
+            return serviceAdapter;
+        }
+        
         // attempt to locate adapter for the Oid
         ObjectAdapter adapter = objectAdapterContext.lookupAdapterFor(rootOid);
         if (adapter == null) {
@@ -98,6 +104,14 @@ class PersistenceSession5_Decouple  {
             } catch(ObjectNotFoundException ex) {
                 throw ex; // just rethrow
             } catch(RuntimeException ex) {
+                
+                System.err.println("------------------------------------------");
+                System.err.println("rootOid: "+rootOid.enString());
+                
+                ex.printStackTrace();
+                System.err.println("------------------------------------------");
+
+                
                 throw new PojoRecreationException(rootOid, ex);
             }
         }
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 1df596c..f0850e5 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
@@ -29,6 +29,7 @@ import org.apache.isis.core.commons.config.IsisConfiguration;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapterProvider;
 import org.apache.isis.core.metamodel.adapter.concurrency.ConcurrencyChecking;
+import org.apache.isis.core.metamodel.adapter.oid.Oid.State;
 import org.apache.isis.core.metamodel.adapter.oid.ParentedCollectionOid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.services.ServicesInjector;
@@ -89,9 +90,6 @@ public interface PersistenceSession extends ObjectAdapterProvider.Delegating, Tr
 
     void close();
 
-    RootOid createTransientOrViewModelOid(Object pojo);
-    RootOid createPersistentOrViewModelOid(Object pojo);
-
     ObjectAdapter createTransientInstance(ObjectSpecification spec);
 
     ObjectAdapter createViewModelInstance(ObjectSpecification spec, String memento);
@@ -108,6 +106,14 @@ public interface PersistenceSession extends ObjectAdapterProvider.Delegating, Tr
     IsisConfiguration getConfiguration();
 
     PersistenceManager getPersistenceManager();
+    
+    /**
+     * @param pojo
+     * @param type
+     * @return String representing an object's id.
+     * @since 2.0.0-M2
+     */
+    String identifierFor(Object pojo, State type);
 
     /**
      * Convenient equivalent to {@code getPersistenceManager()}.
@@ -169,4 +175,6 @@ public interface PersistenceSession extends ObjectAdapterProvider.Delegating, Tr
     boolean isDestroyed(Object pojo);
 
 
+
+
 }
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 a665d20..b204e36 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
@@ -18,7 +18,6 @@
  */
 package org.apache.isis.core.runtime.system.persistence.adaptermanager;
 
-import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
 import java.util.function.Function;
@@ -144,6 +143,8 @@ public class ObjectAdapterContext {
     private final ObjectAdapterContext_ObjectAdapterProvider objectAdapterProviderMixin;
     private final ObjectAdapterContext_AdapterManager adapterManagerMixin;
     private final ObjectAdapterContext_MementoSupport mementoSupportMixin;
+    private final ObjectAdapterContext_ServiceLookup serviceLookupMixin;
+    private final ObjectAdapterContext_NewIdentifier newIdentifierMixin;
     
     private ObjectAdapterContext(
             ServicesInjector servicesInjector, 
@@ -155,6 +156,8 @@ public class ObjectAdapterContext {
         this.objectAdapterProviderMixin = new ObjectAdapterContext_ObjectAdapterProvider(this, persistenceSession);
         this.adapterManagerMixin = new ObjectAdapterContext_AdapterManager(this, persistenceSession);
         this.mementoSupportMixin = new ObjectAdapterContext_MementoSupport(this, persistenceSession);
+        this.serviceLookupMixin = new ObjectAdapterContext_ServiceLookup(this, servicesInjector);
+        this.newIdentifierMixin = new ObjectAdapterContext_NewIdentifier(this, persistenceSession);
         
         this.persistenceSession = persistenceSession;
         this.servicesInjector = servicesInjector;
@@ -166,15 +169,25 @@ public class ObjectAdapterContext {
                 persistenceSession);
     }
 
+    // -- DEBUG
+    
+    private void printContextInfo(String msg) {
+        String id = Integer.toHexString(this.hashCode());
+        String session = ""+persistenceSession;
+        System.out.println("!!!!!!!!!!!!!!!!!!!!!!! "+String.format("%s id=%s session='%s'", 
+                msg, id, session));
+    }
+    
     // -- LIFE-CYCLING
     
     public void open() {
+        printContextInfo("OPEN_");
         cache.open();
-        initServices();
     }
     
     public void close() {
         cache.close();
+        printContextInfo("CLOSE");
     }
     
     // -- CACHING POJO
@@ -220,6 +233,22 @@ public class ObjectAdapterContext {
         consistencyMixin.ensureMapsConsistent(oid);
     }
     
+    // -- NEW IDENTIFIER
+    
+    RootOid createTransientOrViewModelOid(final Object pojo) {
+        return newIdentifierMixin.createTransientOrViewModelOid(pojo);
+    }
+
+    public RootOid createPersistentOrViewModelOid(Object pojo) {
+        return newIdentifierMixin.createPersistentOrViewModelOid(pojo);
+    }
+    
+    // -- SERVICE LOOKUP
+    
+    public ObjectAdapter lookupServiceAdapterFor(RootOid rootOid) {
+        return serviceLookupMixin.serviceAdapterFor(rootOid);
+    }
+    
     // -- FACTORIES
     
     // package private
@@ -331,20 +360,20 @@ public class ObjectAdapterContext {
     
     // ------------------------------------------------------------------------------------------------
     
-    /**
-     * Creates {@link ObjectAdapter adapters} for the service list, ensuring that these are mapped correctly,
-     * and have the same OIDs as in any previous sessions.
-     * 
-     * @deprecated https://issues.apache.org/jira/browse/ISIS-1976
-     */
-    @Deprecated
-    private void initServices() {
-        final List<Object> registeredServices = servicesInjector.getRegisteredServices();
-        for (final Object service : registeredServices) {
-            final ObjectAdapter serviceAdapter = objectAdapterProviderMixin.adapterFor(service);
-            Assert.assertFalse("expected to not be 'transient'", serviceAdapter.getOid().isTransient());
-        }
-    }
+//    /**
+//     * Creates {@link ObjectAdapter adapters} for the service list, ensuring that these are mapped correctly,
+//     * and have the same OIDs as in any previous sessions.
+//     * 
+//     * @deprecated https://issues.apache.org/jira/browse/ISIS-1976
+//     */
+//    @Deprecated
+//    private void initServices() {
+//        final List<Object> registeredServices = servicesInjector.getRegisteredServices();
+//        for (final Object service : registeredServices) {
+//            final ObjectAdapter serviceAdapter = objectAdapterProviderMixin.adapterFor(service);
+//            Assert.assertFalse("expected to not be 'transient'", serviceAdapter.getOid().isTransient());
+//        }
+//    }
     
     public ObjectAdapter disposableAdapterForViewModel(Object viewModelPojo) {
             final ObjectSpecification objectSpecification = 
@@ -479,7 +508,7 @@ public class ObjectAdapterContext {
         return newAdapter;
     }
 
-    
+   
 
 
 }
\ No newline at end of file
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
new file mode 100644
index 0000000..31995e8
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_NewIdentifier.java
@@ -0,0 +1,129 @@
+/*
+ *  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.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+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.ObjectSpecId;
+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: creates RootOids 
+ * </p> 
+ * @since 2.0.0-M2
+ */
+@SuppressWarnings("unused")
+class ObjectAdapterContext_NewIdentifier {
+    
+    
+    private static final Logger LOG = LoggerFactory.getLogger(ObjectAdapterContext_NewIdentifier.class);
+    private final ObjectAdapterContext objectAdapterContext;
+    private final PersistenceSession persistenceSession;
+    private final ServicesInjector servicesInjector;
+    private final SpecificationLoader specificationLoader;
+    
+    
+    ObjectAdapterContext_NewIdentifier(ObjectAdapterContext objectAdapterContext,
+            PersistenceSession persistenceSession) {
+        this.objectAdapterContext = objectAdapterContext;
+        this.persistenceSession = persistenceSession;
+        this.servicesInjector = persistenceSession.getServicesInjector();
+        this.specificationLoader = servicesInjector.getSpecificationLoader();
+    }
+    
+//    RootOid rootOidFor(Object pojo) {
+//        final RootOid rootOid = servicesInjector.isRegisteredServiceInstance(pojo) 
+//                ? createPersistentOrViewModelOid(pojo) 
+//                        : createTransientOrViewModelOid(pojo);
+//        
+//                
+//        return rootOid;
+//    }
+    
+    
+    // -- create...Oid (main API)
+    /**
+     * Create a new {@link Oid#isTransient() transient} {@link Oid} for the
+     * supplied pojo, uniquely distinguishable from any other {@link Oid}.
+     */
+    final RootOid createTransientOrViewModelOid(final Object pojo) {
+        return newIdentifier(pojo, Oid.State.TRANSIENT);
+    }
+
+    /**
+     * Return an equivalent {@link RootOid}, but being persistent.
+     *
+     * <p>
+     * It is the responsibility of the implementation to determine the new unique identifier.
+     * For example, the generator may simply assign a new value from a sequence, or a GUID;
+     * or, the generator may use the oid to look up the object and inspect the object in order
+     * to obtain an application-defined value.
+     *
+     * @param pojo - being persisted
+     */
+    final RootOid createPersistentOrViewModelOid(Object pojo) {
+        return newIdentifier(pojo, Oid.State.PERSISTENT);
+    }
+
+    RootOid newIdentifier(final Object pojo, final Oid.State type) {
+        final ObjectSpecification spec = objectSpecFor(pojo);
+        if(spec.isService()) {
+            return newRootId(spec, PersistenceSession.SERVICE_IDENTIFIER, Oid.State.PERSISTENT); // services are always persistent
+        }
+
+        final ViewModelFacet recreatableObjectFacet = spec.getFacet(ViewModelFacet.class);
+        final String identifier =
+                recreatableObjectFacet != null
+                ? recreatableObjectFacet.memento(pojo)
+                        : persistenceSession.identifierFor(pojo, type);
+
+                return newRootId(spec, identifier, type);
+    }
+    
+    
+    private RootOid newRootId(final ObjectSpecification spec, final String identifier, final Oid.State type) {
+        final Oid.State state =
+                spec.containsDoOpFacet(ViewModelFacet.class)
+                ? Oid.State.VIEWMODEL
+                        : type == Oid.State.TRANSIENT
+                        ? Oid.State.TRANSIENT
+                                : Oid.State.PERSISTENT;
+        final ObjectSpecId objectSpecId = spec.getSpecId();
+        return new RootOid(objectSpecId, identifier, state);
+    }
+    
+    // -- HELPER
+    
+    private ObjectSpecification objectSpecFor(final Object pojo) {
+        final Class<?> pojoClass = pojo.getClass();
+        return specificationLoader.loadSpecification(pojoClass);
+    }
+
+
+    
+}
\ No newline at end of file
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 593ad6c..a8f33ce 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
@@ -20,11 +20,13 @@ package org.apache.isis.core.runtime.system.persistence.adaptermanager;
 
 import java.util.List;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.isis.commons.internal.collections._Lists;
+import org.apache.isis.commons.internal.base._Lazy;
+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;
@@ -47,6 +49,7 @@ import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
  */
 class ObjectAdapterContext_ObjectAdapterProvider implements ObjectAdapterProvider {
     
+    @SuppressWarnings("unused")
     private static final Logger LOG = LoggerFactory.getLogger(ObjectAdapterContext_ObjectAdapterProvider.class);
     private final ObjectAdapterContext objectAdapterContext;
     private final PersistenceSession persistenceSession;
@@ -63,20 +66,19 @@ class ObjectAdapterContext_ObjectAdapterProvider implements ObjectAdapterProvide
         this.isisJdoMetamodelPlugin = IsisJdoMetamodelPlugin.get();
     }
 
-    @Override
-    public Oid oidFor(Object pojo) {
-        if(pojo == null) {
-            return null;
-        }
-        final Oid persistentOrValueOid = persistentOrValueOid(pojo);
-        if(persistentOrValueOid != null) {
-            return persistentOrValueOid;
-        }
-        final RootOid rootOid = servicesInjector.isRegisteredServiceInstance(pojo) 
-                ? persistenceSession.createPersistentOrViewModelOid(pojo) 
-                        : persistenceSession.createTransientOrViewModelOid(pojo);
-        return rootOid;
-    }
+//    @Override
+//    public Oid oidFor(Object pojo) {
+//        if(pojo == null) {
+//            return null;
+//        }
+//        final Oid persistentOrValueOid = persistentOrValueOid(pojo);
+//        if(persistentOrValueOid != null) {
+//            return persistentOrValueOid;
+//        }
+//        final RootOid rootOid = objectAdapterContext.rootOidFor(pojo);
+//        
+//        return rootOid;
+//    }
     
     @Override
     public ObjectAdapter adapterFor(Object pojo) {
@@ -89,16 +91,14 @@ class ObjectAdapterContext_ObjectAdapterProvider implements ObjectAdapterProvide
             return existingOrValueAdapter;
         }
 
-        final RootOid rootOid = servicesInjector.isRegisteredServiceInstance(pojo) 
-                ? persistenceSession.createPersistentOrViewModelOid(pojo) 
-                        : persistenceSession.createTransientOrViewModelOid(pojo);
+        final RootOid rootOid = objectAdapterContext.createTransientOrViewModelOid(pojo);
         
-//        final RootOid rootOid = persistenceSession.createTransientOrViewModelOid(pojo);
         final ObjectAdapter newAdapter = objectAdapterContext.getFactories().createRootAdapter(pojo, rootOid);
 
         return objectAdapterContext.mapAndInjectServices(newAdapter);
     }
-
+    
+    
     @Override
     public ObjectAdapter adapterFor(Object pojo, ObjectAdapter parentAdapter, OneToManyAssociation collection) {
 
@@ -140,66 +140,68 @@ class ObjectAdapterContext_ObjectAdapterProvider implements ObjectAdapterProvide
         if (persistenceSession.getPersistenceManager().getObjectId(pojo) == null) {
             return null;
         }
-        final RootOid oid = persistenceSession.createPersistentOrViewModelOid(pojo);
+        final RootOid oid = objectAdapterContext.createPersistentOrViewModelOid(pojo);
         final ObjectAdapter adapter = objectAdapterContext.addRecreatedPojoToCache(oid, pojo);
         return adapter;
     }
     
+    private List<ObjectAdapter> initServiceAdapters() {
+        return servicesInjector.streamRegisteredServiceInstances()
+        .map(this::adapterFor)
+        .peek(serviceAdapter->{
+            Assert.assertFalse("expected to not be 'transient'", serviceAdapter.getOid().isTransient());
+        })
+        .collect(Collectors.toList());
+    }
+    
+    private _Lazy<List<ObjectAdapter>> serviceAdapters = _Lazy.of(this::initServiceAdapters);
+    
     @Override
     public List<ObjectAdapter> getServices() {
-        final List<Object> services = servicesInjector.getRegisteredServices();
-        final List<ObjectAdapter> serviceAdapters = _Lists.newArrayList();
-        for (final Object servicePojo : services) {
-            ObjectAdapter serviceAdapter = objectAdapterContext.lookupAdapterFor(servicePojo);
-            if(serviceAdapter == null) {
-                throw new IllegalStateException("ObjectAdapter for service " + servicePojo + " does not exist?!?");
-            }
-            serviceAdapters.add(serviceAdapter);
-        }
-        return serviceAdapters;
+        return serviceAdapters.get();
     }
     
     // -- HELPER
     
-    private Oid persistentOrValueOid(Object pojo) {
-        
-        Oid oid;
-
-        // equivalent to  isInstanceOfPersistable = pojo instanceof Persistable;
-        final boolean isInstanceOfPersistable = isisJdoMetamodelPlugin.isPersistenceEnhanced(pojo.getClass());
-        
-        // pojo may have been lazily loaded by object store, but we haven't yet seen it
-        if (isInstanceOfPersistable) {
-            oid = persistentOid(pojo);
-
-            // TODO: could return null if the pojo passed in !dnIsPersistent() || !dnIsDetached()
-            // in which case, we would ought to map as a transient object, rather than fall through and treat as a value?
-        } else {
-            oid = null;
-        }
-
-        if(oid != null) {
-            return oid;
-        }
-        
-        // need to create (and possibly map) the adapter.
-        final ObjectSpecification objSpec = specificationLoader.loadSpecification(pojo.getClass());
-
-        // we create value facets as standalone (so not added to maps)
-        if (objSpec.containsFacet(ValueFacet.class)) {
-            //TODO[ISIS-1976] don't need an adapter, just its oid
-            oid = objectAdapterContext.getFactories().createStandaloneAdapter(pojo).getOid(); 
-            return oid;
-        }
-
-        return null;
-    }
+//    private Oid persistentOrValueOid(Object pojo) {
+//        
+//        Oid oid;
+//
+//        // equivalent to  isInstanceOfPersistable = pojo instanceof Persistable;
+//        final boolean isInstanceOfPersistable = isisJdoMetamodelPlugin.isPersistenceEnhanced(pojo.getClass());
+//        
+//        // pojo may have been lazily loaded by object store, but we haven't yet seen it
+//        if (isInstanceOfPersistable) {
+//            oid = persistentOid(pojo);
+//
+//            // TODO: could return null if the pojo passed in !dnIsPersistent() || !dnIsDetached()
+//            // in which case, we would ought to map as a transient object, rather than fall through and treat as a value?
+//        } else {
+//            oid = null;
+//        }
+//
+//        if(oid != null) {
+//            return oid;
+//        }
+//        
+//        // need to create (and possibly map) the adapter.
+//        final ObjectSpecification objSpec = specificationLoader.loadSpecification(pojo.getClass());
+//
+//        // we create value facets as standalone (so not added to maps)
+//        if (objSpec.containsFacet(ValueFacet.class)) {
+//            //TODO[ISIS-1976] don't need an adapter, just its oid
+//            oid = objectAdapterContext.getFactories().createStandaloneAdapter(pojo).getOid(); 
+//            return oid;
+//        }
+//
+//        return null;
+//    }
     
     protected Oid persistentOid(final Object pojo) {
         if (persistenceSession.getPersistenceManager().getObjectId(pojo) == null) {
             return null;
         }
-        final RootOid oid = persistenceSession.createPersistentOrViewModelOid(pojo);
+        final RootOid oid = objectAdapterContext.createPersistentOrViewModelOid(pojo);
         return oid;
     }
     
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ServiceLookup.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ServiceLookup.java
new file mode 100644
index 0000000..31d3b39
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ServiceLookup.java
@@ -0,0 +1,109 @@
+/*
+ *  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.Map;
+import java.util.Objects;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.commons.internal.context._Context;
+import org.apache.isis.core.commons.ensure.Assert;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.services.ServicesInjector;
+
+/**
+ * package private mixin for ObjectAdapterContext
+ * <p>
+ * Responsibility: provides ObjectAdapters for registered services 
+ * </p> 
+ * @since 2.0.0-M2
+ */
+@SuppressWarnings("unused")
+class ObjectAdapterContext_ServiceLookup {
+    
+    
+    private static final Logger LOG = LoggerFactory.getLogger(ObjectAdapterContext_ServiceLookup.class);
+    private final ObjectAdapterContext objectAdapterContext;
+    private final ServicesInjector servicesInjector;
+    
+    ObjectAdapterContext_ServiceLookup(ObjectAdapterContext objectAdapterContext,
+            ServicesInjector servicesInjector) {
+        this.objectAdapterContext = objectAdapterContext;
+        this.servicesInjector = servicesInjector;
+    }
+
+    ObjectAdapter serviceAdapterFor(RootOid rootOid) {
+        
+        final ServicesByIdResource servicesByIdResource =
+                _Context.computeIfAbsent(ServicesByIdResource.class, cls->initLookupResource());
+        
+        try {
+            final Object serviceInstance = servicesByIdResource.lookupServiceInstance(rootOid);
+            if(serviceInstance==null) {
+                return null;
+            }
+            return objectAdapterContext.getFactories().createRootAdapter(serviceInstance, rootOid);
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+            throw new IllegalStateException("Could not resolve service for id '" + rootOid.enStringNoVersion() + "'");
+        }
+        
+    }
+    
+    // -- HELPER
+    
+    /**
+     *  Application scoped resource to hold a map for looking up services by id.
+     */
+    private static class ServicesByIdResource implements AutoCloseable {
+        private final Map<RootOid, Object> servicesById = _Maps.newHashMap();
+
+        @Override
+        public void close() {
+            servicesById.clear();
+        }
+
+        public Object lookupServiceInstance(RootOid serviceRootOid) {
+            return servicesById.get(serviceRootOid);
+        }
+    }
+    
+    private ServicesByIdResource initLookupResource() {
+        
+        System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! INIT SERVICE ID LOOKUP RESOURCE");
+        
+        final ServicesByIdResource lookupResource = new ServicesByIdResource();
+        
+        servicesInjector.streamRegisteredServiceInstances()
+        .map(objectAdapterContext.getObjectAdapterProvider()::adapterFor)
+        .forEach(serviceAdapter->{
+            Assert.assertFalse("expected to not be 'transient'", serviceAdapter.getOid().isTransient());
+            lookupResource.servicesById.put((RootOid)serviceAdapter.getOid() , serviceAdapter.getObject());
+        });
+        
+        return lookupResource;
+    }
+    
+
+}
\ No newline at end of file