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

ahuber pushed a commit to branch 2033-IoC
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/2033-IoC by this push:
     new 188bcf6  ISIS-2033: introduces a new Oid 'UniversalOid'
188bcf6 is described below

commit 188bcf65e2b8c6772d2ecbf73025cac7aef35966
Author: Andi Huber <[email protected]>
AuthorDate: Wed Jan 30 22:57:10 2019 +0100

    ISIS-2033: introduces a new Oid 'UniversalOid'
    
    to access/reference Beans and Entities managed ba external IoC
    containers or PersistenceContexts
    
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-2033
---
 .../applib/services/inject/ServiceInjector.java    |   2 +-
 .../apache/isis/commons/internal/base/_Casts.java  |  60 +++++++++
 .../isis/commons/internal/base/_Strings.java       |  25 ++++
 .../commons/internal/base/_Strings_FastSplit.java  |  48 +++++++
 .../org/apache/isis/commons/internal/cdi/_CDI.java |  43 +++++-
 .../internal/cdi/_CDI_AmbiguousInstance.java       |  58 ++++++++
 .../commons/internal/cdi/_CDI_EmptyInstance.java   |  65 +++++++++
 .../internal/cdi/_CDI_SingletonInstance.java       |  63 +++++++++
 .../org/apache/isis/commons/internal/uri/_URI.java | 146 +++++++++++++++++++++
 .../isis/core/metamodel/adapter/ObjectAdapter.java |   2 +-
 .../metamodel/adapter/ObjectAdapterProvider.java   |  15 ---
 .../isis/core/metamodel/adapter/oid/Oid.java       |   8 ++
 .../isis/core/metamodel/adapter/oid/Oid_Root.java  |  11 ++
 .../core/metamodel/adapter/oid/Oid_Universal.java  | 141 ++++++++++++++++++++
 .../core/metamodel/adapter/oid/UniversalOid.java   |   9 ++
 .../isis/core/metamodel/spec/ManagedObject.java    |  15 ++-
 .../metamodel/specloader/SpecificationLoader.java  |   3 +-
 .../isis/core/plugins/ioc/weld/WeldFactory.java    |   1 -
 .../core/runtime/contextmanger/ContextHandler.java |  28 ++++
 .../core/runtime/contextmanger/ContextManager.java |  12 ++
 .../contextmanger/ManagedObjectResolver.java       |  33 +++++
 .../contextmanger/UniversalContextManager.java     |  73 +++++++++++
 .../runtime/persistence/adapter/PojoAdapter.java   |  22 +++-
 .../adaptermanager/ObjectAdapterContext.java       |  10 +-
 ...ctAdapterContext_ObjectAdapterByIdProvider.java |  47 ++++++-
 ...ObjectAdapterContext_ObjectAdapterProvider.java |  10 +-
 .../ObjectAdapterContext_OidProviders.java         | 109 ++++++++-------
 .../adaptermanager/factories/OidFactory.java       |   5 +-
 .../factories/OidFactory_Builder.java              |  15 ++-
 .../system/session/IsisSessionProducerBean.java    |   5 +-
 .../wicket/viewer/IsisWicketApplication.java       |   2 +-
 .../wicket/ConverterForObjectAdapterMemento.java   |   2 +-
 .../model/mementos/ObjectAdapterMemento.java       |  22 +++-
 .../wicket/model/models/EntityCollectionModel.java |   2 +-
 .../viewer/wicket/model/models/EntityModel.java    |   6 +-
 .../model/models/EntityModelForReference.java      |   2 +-
 .../viewer/wicket/model/models/ValueModel.java     |   2 +-
 .../entityactions/EntityActionLinkFactory.java     |   2 +-
 .../wicket/ui/panels/FormExecutorDefault.java      |  28 +++-
 .../application/manifest/menubars.layout.xml       |  13 ++
 .../modules/spring/SpringDataJPADemoHandler.java   | 100 ++++++++++++++
 41 files changed, 1152 insertions(+), 113 deletions(-)

diff --git 
a/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java
 
b/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java
index 352c5d1..c700f98 100644
--- 
a/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java
+++ 
b/core/applib/src/main/java/org/apache/isis/applib/services/inject/ServiceInjector.java
@@ -45,7 +45,7 @@ public interface ServiceInjector {
     @Deprecated // use ServiceRegistry instead
     <T> T lookupServiceElseFail(final Class<T> serviceClass);
     
-//FIXME [2033]
+//FIXME [2033] remove comments ...
 //    /**
 //     * This is mutable internally, but only ever exposed (in {@link 
#streamRegisteredServices()}).
 //     */
diff --git 
a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Casts.java 
b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Casts.java
index a8365a9..ac56798 100644
--- 
a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Casts.java
+++ 
b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Casts.java
@@ -21,6 +21,7 @@ package org.apache.isis.commons.internal.base;
 
 import static org.apache.isis.commons.internal.base._With.requires;
 
+import java.util.function.BiFunction;
 import java.util.function.Supplier;
 
 import javax.annotation.Nullable;
@@ -63,4 +64,63 @@ public final class _Casts {
 
     }
 
+    /**
+     * Dependent on whether left or right can be cast to {@code cls}, the 
appropriate functional 
+     * interface is chosen to produce the result.
+     * @param left
+     * @param right
+     * @param cls
+     * @param onBothCast
+     * @param onLeftCast
+     * @param onRightCast
+     * @param onNonCast
+     * @return
+     */
+    public static <T, R, U, V> R castThenApply(
+               @Nullable U left, 
+               @Nullable V right,
+               Class<T> cls, 
+               BiFunction<T, T, R> onBothCast,
+               BiFunction<T, V, R> onLeftCast,
+               BiFunction<U, T, R> onRightCast,
+               BiFunction<U, V, R> onNonCast) {
+
+       requires(cls, "cls");
+       
+       T left_casted=null, right_casted=null;
+       boolean left_not_casted=false, right_not_casted=false;
+       
+       if(left==null) {
+               left_casted = null;
+       } else if(cls.isAssignableFrom(left.getClass())) {
+               left_casted = cls.cast(left);
+       } else {
+               left_not_casted = true;
+       }
+       
+       if(right==null) {
+               right_casted = null;
+       } else if(cls.isAssignableFrom(right.getClass())) {
+               right_casted = cls.cast(right);
+       } else {
+               right_not_casted = true;
+       }
+       
+       if(left_not_casted && right_not_casted) {
+               return onNonCast.apply(left, right);
+       }
+
+       if(!left_not_casted && !right_not_casted) {
+               return onBothCast.apply(left_casted, right_casted);
+       }
+       
+       if(left_not_casted) {
+               return onRightCast.apply(left, right_casted);
+       }
+       
+       return onLeftCast.apply(left_casted, right);
+       
+    }
+    
+    
 }
diff --git 
a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java
 
b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java
index 151cfc7..7e6226f 100644
--- 
a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java
+++ 
b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java
@@ -33,6 +33,8 @@ import java.util.Optional;
 import java.util.Scanner;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 import java.util.function.UnaryOperator;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
@@ -365,6 +367,29 @@ public final class _Strings {
         }
         return delimiterPattern.splitAsStream(input);
     }
+    
+
+    public static void splitThenAccept(
+               @Nullable final String input, 
+               final String separator, 
+               final BiConsumer<String, String> onNonEmptySplit,
+               final Consumer<String> onNonEmptyLhs,
+               final Consumer<String> onNonEmptyRhs) {
+       
+       _Strings_FastSplit.splitThenAccept(input, separator, onNonEmptySplit, 
onNonEmptyLhs, onNonEmptyRhs);
+    }
+    
+    public static void splitThenAcceptEmptyAsNull(
+               @Nullable final String input, 
+               final String separator, 
+               final BiConsumer<String, String> onSplit) {
+       
+       _Strings_FastSplit.splitThenAccept(input, separator, onSplit, 
+                       lhs->onSplit.accept(lhs, null), 
+                       rhs->onSplit.accept(null, rhs));
+    }
+    
+    
 
     // -- REPLACEMENT OPERATORS
 
diff --git 
a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings_FastSplit.java
 
b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings_FastSplit.java
new file mode 100644
index 0000000..1eac561
--- /dev/null
+++ 
b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings_FastSplit.java
@@ -0,0 +1,48 @@
+package org.apache.isis.commons.internal.base;
+
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+import javax.annotation.Nullable;
+
+class _Strings_FastSplit {
+
+       public static void splitThenAccept(
+               @Nullable final String input, 
+               final String separator, 
+               BiConsumer<String, String> onNonEmptySplit,
+               Consumer<String> onNonEmptyLhs,
+               Consumer<String> onNonEmptyRhs) {
+       
+        if(_Strings.isEmpty(input)) {
+               // skip
+            return;
+        }
+        
+        // we have a non-empty string
+        
+        final int p = input.indexOf(separator);
+        if(p<1){
+                       if(p==-1) {
+                               // separator not found
+                               onNonEmptyLhs.accept(input);
+                               return;
+                       }
+                       if(p==0) {
+                               // empty lhs in string
+                               if(input.length()>separator.length()) {
+                                       onNonEmptyRhs.accept(input);
+                               }
+                               return;
+                       }
+               }
+        final int q = p + separator.length();
+               if(q==input.length()) {
+                       // empty rhs
+                       onNonEmptyLhs.accept(input.substring(0, p));
+                       return;
+               }
+               onNonEmptySplit.accept(input.substring(0, p), 
input.substring(q));
+    }
+       
+}
diff --git 
a/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI.java 
b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI.java
index 79b5277..0400caf 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI.java
@@ -18,6 +18,10 @@
  */
 package org.apache.isis.commons.internal.cdi;
 
+import static org.apache.isis.commons.internal.base._NullSafe.isEmpty;
+import static org.apache.isis.commons.internal.base._NullSafe.stream;
+import static org.apache.isis.commons.internal.base._With.requires;
+
 import java.lang.annotation.Annotation;
 import java.util.Collection;
 import java.util.List;
@@ -28,6 +32,7 @@ import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import javax.annotation.Nullable;
 import javax.enterprise.inject.Any;
 import javax.enterprise.inject.Instance;
 import javax.enterprise.inject.spi.Bean;
@@ -37,14 +42,13 @@ import javax.enterprise.inject.spi.CDIProvider;
 import javax.enterprise.util.AnnotationLiteral;
 import javax.inject.Qualifier;
 
+import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.context._Context;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.commons.internal.functions._Functions.CheckedRunnable;
 import org.apache.isis.core.plugins.ioc.IocPlugin;
 
-import static org.apache.isis.commons.internal.base._NullSafe.isEmpty;
-import static org.apache.isis.commons.internal.base._NullSafe.stream;
-import static org.apache.isis.commons.internal.base._With.requires;
+import lombok.val;
 
 /**
  * <h1>- internal use only -</h1>
@@ -221,6 +225,38 @@ public final class _CDI {
         Set<Bean<?>> beans = beanManager.getBeans(Object.class, 
_CDI.QUALIFIER_ANY);
         return beans.stream();
        }
+    
+    // -- FACTORIES
+    
+       public static class InstanceFactory {
+
+               public static <T> Instance<T> empty() {
+                       return new _CDI_EmptyInstance<>();
+               }
+               
+               public static <T> Instance<T> singleton(@Nullable T pojo) {
+                       if(pojo==null) {
+                               return empty();
+                       }
+                       return _CDI_SingletonInstance.of(pojo);
+               }
+
+               public static <T> Instance<T> ambiguous(@Nullable Collection<T> 
collection) {
+                       val size = _NullSafe.size(collection);
+                       if(size==0) {
+                               return empty();
+                       } 
+                       if(size==1) {
+                               if(collection instanceof List) {
+                                       // just to reduce heap pollution when 
collection is a list
+                                       return 
singleton(((List<T>)collection).get(0));
+                               } 
+                               return singleton(collection.iterator().next());
+                       }
+                       return _CDI_AmbiguousInstance.of(collection);
+               }
+               
+       }
         
     // -- HELPER
     
@@ -246,7 +282,6 @@ public final class _CDI {
             return null;
         }
     }
-
        
 
 
diff --git 
a/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_AmbiguousInstance.java
 
b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_AmbiguousInstance.java
new file mode 100644
index 0000000..1c52594
--- /dev/null
+++ 
b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_AmbiguousInstance.java
@@ -0,0 +1,58 @@
+package org.apache.isis.commons.internal.cdi;
+
+import java.lang.annotation.Annotation;
+import java.util.Iterator;
+
+import javax.enterprise.inject.Instance;
+import javax.enterprise.util.TypeLiteral;
+
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor(staticName="of")
+final class _CDI_AmbiguousInstance<T> implements Instance<T> {
+
+       private final Iterable<T> iterable;
+       
+       @Override
+       public Iterator<T> iterator() {
+               return iterable.iterator();
+       }
+
+       @Override
+       public T get() {
+               throw _Exceptions.notImplemented();
+       }
+
+       @Override
+       public Instance<T> select(Annotation... qualifiers) {
+               throw _Exceptions.notImplemented();
+       }
+
+       @Override
+       public <U extends T> Instance<U> select(Class<U> subtype, Annotation... 
qualifiers) {
+               throw _Exceptions.notImplemented();
+       }
+
+       @Override
+       public <U extends T> Instance<U> select(TypeLiteral<U> subtype, 
Annotation... qualifiers) {
+               throw _Exceptions.notImplemented();
+       }
+
+       @Override
+       public boolean isUnsatisfied() {
+               return false;
+       }
+
+       @Override
+       public boolean isAmbiguous() {
+               return true;
+       }
+
+       @Override
+       public void destroy(T instance) {
+               // ignore
+       }
+
+}
diff --git 
a/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_EmptyInstance.java
 
b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_EmptyInstance.java
new file mode 100644
index 0000000..28d5e8c
--- /dev/null
+++ 
b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_EmptyInstance.java
@@ -0,0 +1,65 @@
+package org.apache.isis.commons.internal.cdi;
+
+import java.lang.annotation.Annotation;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import javax.enterprise.inject.Instance;
+import javax.enterprise.util.TypeLiteral;
+
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+
+final class _CDI_EmptyInstance<T> implements Instance<T> {
+
+       @Override
+       public Iterator<T> iterator() {
+               return new Iterator<T>() {
+
+                       @Override
+                       public boolean hasNext() {
+                               return false;
+                       }
+
+                       @Override
+                       public T next() {
+                               throw new NoSuchElementException();
+                       }
+               };
+       }
+
+       @Override
+       public T get() {
+               throw new NoSuchElementException();
+       }
+
+       @Override
+       public Instance<T> select(Annotation... qualifiers) {
+               throw _Exceptions.notImplemented();
+       }
+
+       @Override
+       public <U extends T> Instance<U> select(Class<U> subtype, Annotation... 
qualifiers) {
+               throw _Exceptions.notImplemented();
+       }
+
+       @Override
+       public <U extends T> Instance<U> select(TypeLiteral<U> subtype, 
Annotation... qualifiers) {
+               throw _Exceptions.notImplemented();
+       }
+
+       @Override
+       public boolean isUnsatisfied() {
+               return true;
+       }
+
+       @Override
+       public boolean isAmbiguous() {
+               return false;
+       }
+
+       @Override
+       public void destroy(T instance) {
+               // ignore
+       }
+
+}
diff --git 
a/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_SingletonInstance.java
 
b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_SingletonInstance.java
new file mode 100644
index 0000000..33cec4c
--- /dev/null
+++ 
b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI_SingletonInstance.java
@@ -0,0 +1,63 @@
+package org.apache.isis.commons.internal.cdi;
+
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.Iterator;
+
+import javax.enterprise.inject.Instance;
+import javax.enterprise.util.TypeLiteral;
+
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor(staticName="of")
+final class _CDI_SingletonInstance<T> implements Instance<T> {
+
+       private final T singleton;
+       private Iterable<T> iterable;
+       
+       @Override
+       public Iterator<T> iterator() {
+               if(iterable==null) {
+                       iterable = Collections.singletonList(singleton);
+               }
+               return iterable.iterator();
+       }
+
+       @Override
+       public T get() {
+               return singleton;
+       }
+
+       @Override
+       public Instance<T> select(Annotation... qualifiers) {
+               throw _Exceptions.notImplemented();
+       }
+
+       @Override
+       public <U extends T> Instance<U> select(Class<U> subtype, Annotation... 
qualifiers) {
+               throw _Exceptions.notImplemented();
+       }
+
+       @Override
+       public <U extends T> Instance<U> select(TypeLiteral<U> subtype, 
Annotation... qualifiers) {
+               throw _Exceptions.notImplemented();
+       }
+
+       @Override
+       public boolean isUnsatisfied() {
+               return false;
+       }
+
+       @Override
+       public boolean isAmbiguous() {
+               return false;
+       }
+
+       @Override
+       public void destroy(T instance) {
+               // ignore
+       }
+
+}
diff --git 
a/core/commons/src/main/java/org/apache/isis/commons/internal/uri/_URI.java 
b/core/commons/src/main/java/org/apache/isis/commons/internal/uri/_URI.java
new file mode 100644
index 0000000..306f33d
--- /dev/null
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/uri/_URI.java
@@ -0,0 +1,146 @@
+package org.apache.isis.commons.internal.uri;
+
+import static 
org.apache.isis.commons.internal.base._Strings.splitThenAcceptEmptyAsNull;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.isis.commons.internal.base._Strings;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.uri._URI.UoidDto.UoidDtoBuilder;
+import org.apache.isis.commons.internal.uri._URI.UriDto.UriDtoBuilder;
+
+import lombok.Builder;
+import lombok.ToString;
+import lombok.val;
+
+/**
+ * @since 2.0.0-M3
+ */
+public final class _URI {
+       
+       // -- URI
+       
+       public static UriDtoBuilder uriBuilder() {
+               return UriDto.builder();
+       }
+       
+       public static UriDtoBuilder uriBuilder(URI template) {
+               val builder = UriDto.builder()
+                               .scheme(template.getScheme())
+                               .authority(template.getAuthority())
+                               .path(template.getPath())
+                               .query(template.getQuery())
+                               .fragment(template.getFragment());
+               return builder;
+       }
+       
+       @Builder @ToString
+       public static class UriDto {
+               private final String scheme;
+               private final String authority;
+               private final String path;
+               private final String query;
+               private final String fragment;
+               
+               public URI toURI() {
+                       try {
+                               return new URI(scheme, authority, path, query, 
fragment);
+                       } catch (URISyntaxException e) {
+                               throw _Exceptions.unrecoverable(e);
+                       }
+               }
+               
+       }
+       
+       // -- UOID
+       
+       private final static String UOID_SCHEME = "uoid";
+
+       public static boolean isUoid(String string) {
+               return string!=null && string.startsWith(UOID_SCHEME + "://");
+       }
+       
+       public static UoidDtoBuilder uoidBuilder() {
+               return UoidDto.builder();
+       }
+       
+       public static UoidDtoBuilder uoidBuilder(URI template) {
+               val builder = UoidDto.builder()
+                               .scheme(template.getScheme())
+                               .path(template.getPath())
+                               .query(template.getQuery())
+                               .fragment(template.getFragment());
+               
+               splitThenAcceptEmptyAsNull(template.getAuthority(), "@", 
+                               (ctxType, rhs)->{ 
+                                       builder.contextType(ctxType!=null ? 
ContextType.valueOf(ctxType) : null);
+                                       
+                                       splitThenAcceptEmptyAsNull(rhs, ":", 
+                                                       (cont, ctxId)->{ 
+                                                               
builder.containerType(cont!=null ? ContainerType.valueOf(cont) : null);
+                                                               
builder.contextId(ctxId);
+                                                       });                     
+                               });
+               
+               
+               
+               return builder;
+                               
+       }
+       
+       public static enum ContainerType {
+               cdi,
+               spring,
+               ;
+       }
+       
+       public static enum ContextType {
+               beans, // InversionOfControlContainer
+               entities, // PersistenceContext
+               ;
+       }
+       
+       @Builder @ToString
+       public static class UoidDto {
+               @Builder.Default private final String scheme = UOID_SCHEME;
+               @Builder.Default private final ContainerType containerType = 
ContainerType.cdi;
+               @Builder.Default private final ContextType contextType = 
ContextType.beans;
+               private final String contextId;
+               private final String path;
+               private final String query;
+               private final String fragment;
+               
+               public URI toURI() {
+                       try {
+                               return new URI(scheme, authority(), path, 
query, fragment);
+                       } catch (URISyntaxException e) {
+                               throw _Exceptions.unrecoverable(e);
+                       }
+               }
+               
+               // -- HELPER
+               
+               private String authority() {
+                       val sb = new StringBuilder();
+                       if(contextType!=null) {
+                               sb.append(contextType.name()).append("@");
+                       }
+                       if(containerType!=null) {
+                               sb.append(containerType.name());
+                       }
+                       if(!_Strings.isEmpty(contextId)) {
+                               sb.append(":").append(contextId);
+                       }
+                       return sb.toString();
+               }
+               
+               
+       }
+
+       //-- HELPER
+
+       private _URI() {}
+
+       
+}
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapter.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapter.java
index 74cc47a..160730a 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapter.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapter.java
@@ -77,7 +77,7 @@ public interface ObjectAdapter extends ManagedObject {
     Oid getOid();
 
     /**
-     * Returns either itself (if this is a root) or the parented collections, 
the
+     * Returns either itself (if this is a root) or for parented collections, 
the
      * adapter corresponding to their {@link ParentedOid#getParentOid() root 
oid}.
      */
     ObjectAdapter getAggregateRoot();
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 4d80ecb..b66baf2 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
@@ -24,7 +24,6 @@ import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
-import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -44,7 +43,6 @@ public interface ObjectAdapterProvider {
      * @param pojo
      * @return oid for the given domain object 
      */
-    @Programmatic
     default @Nullable Oid oidFor(@Nullable Object domainObject) {
         return mapIfPresentElse(adapterFor(domainObject), 
ObjectAdapter::getOid, null);
     }
@@ -109,15 +107,12 @@ public interface ObjectAdapterProvider {
     
     public static interface Delegating extends ObjectAdapterProvider {
         
-        @Programmatic
         ObjectAdapterProvider getObjectAdapterProvider();
         
-        @Programmatic
         default ObjectAdapter adapterFor(Object domainObject) {
             return getObjectAdapterProvider().adapterFor(domainObject);
         }
 
-        @Programmatic
         default ObjectAdapter adapterFor(
                 final Object pojo,
                 final RootOid parentOid,
@@ -125,45 +120,35 @@ public interface ObjectAdapterProvider {
             return getObjectAdapterProvider().adapterFor(pojo, parentOid, 
collection);
         }
 
-        @Programmatic
         default ManagedObject disposableAdapterForViewModel(final Object 
viewModelPojo) {
             return 
getObjectAdapterProvider().disposableAdapterForViewModel(viewModelPojo);
         }
         
-        @Programmatic
         default ObjectSpecification specificationForViewModel(Object 
viewModelPojo) {
             return 
getObjectAdapterProvider().specificationForViewModel(viewModelPojo);
         }
 
-        @Programmatic
         default ObjectAdapter adapterForViewModel(final Object viewModelPojo, 
final String mementoString) {
             return 
getObjectAdapterProvider().adapterForViewModel(viewModelPojo, mementoString);
         }
         
-        @Programmatic
         default ObjectAdapter newTransientInstance(ObjectSpecification 
objectSpec) {
             return getObjectAdapterProvider().newTransientInstance(objectSpec);
         }
         
-        @Programmatic
         default ObjectAdapter recreateViewModelInstance(ObjectSpecification 
objectSpec, final String memento) {
             return 
getObjectAdapterProvider().recreateViewModelInstance(objectSpec, memento);
         }
         
-        @Programmatic
         default Stream<ObjectAdapter> streamServices() {
             return getObjectAdapterProvider().streamServices();
         }
         
-        @Programmatic
         default ObjectAdapter lookupService(String serviceId) {
             return getObjectAdapterProvider().lookupService(serviceId);
         }
         
     }
-
-
-    
     
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java
index 9ddeb17..c12947e 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.core.metamodel.adapter.oid;
 
+import java.net.URI;
+
 import org.apache.isis.applib.annotation.Value;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.core.commons.encoding.Encodable;
@@ -110,6 +112,12 @@ public interface Oid extends Encodable {
             return Oid_Value.INSTANCE;
         }
         
+        public static UniversalOid universal(URI uri) {
+            return Oid_Universal.of(uri);
+        }
+        
+        // -- LEGACY
+        
         public static RootOid ofBookmark(final Bookmark bookmark) {
             return Oid_Root.of(ObjectSpecId.of(bookmark.getObjectType()), 
                     bookmark.getIdentifier(), Oid_State.from(bookmark), 
Version.empty());
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
index 98f1d67..57cfddc 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
@@ -25,6 +25,7 @@ import java.io.IOException;
 import java.util.Objects;
 
 import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.commons.encoding.DataInputExtended;
 import org.apache.isis.core.commons.encoding.DataOutputExtended;
 import org.apache.isis.core.commons.url.UrlDecoderUtil;
@@ -32,6 +33,8 @@ import org.apache.isis.core.metamodel.adapter.version.Version;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.schema.common.v1.OidDto;
 
+import lombok.val;
+
 final class Oid_Root implements RootOid {
 
     // -- fields
@@ -69,6 +72,14 @@ final class Oid_Root implements RootOid {
         this.state = state;
         this.version = version;
         this.hashCode = calculateHash();
+        
+        
+        val debug = this.toString(); 
+        if(debug.contains("/spring/")) {
+               _Exceptions.throwUnexpectedCodeReach();
+        }
+        
+        
     }
 
     // -- Encodeable
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Universal.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Universal.java
new file mode 100644
index 0000000..4f33110
--- /dev/null
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Universal.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.core.metamodel.adapter.oid;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.commons.internal.base._Strings;
+import org.apache.isis.commons.internal.debug._Probe;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.uri._URI;
+import org.apache.isis.core.commons.encoding.DataOutputExtended;
+import org.apache.isis.core.metamodel.adapter.version.Version;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.schema.common.v1.OidDto;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import lombok.val;
+
+@RequiredArgsConstructor(staticName="of")
+final class Oid_Universal implements UniversalOid {
+
+    private final static long serialVersionUID = 1L;
+       private final static _Probe probe = 
_Probe.unlimited().label("Oid_Universal");
+    
+       private final URI universalId;
+       @Getter @Setter private Version version;
+       
+       @Override
+       public ObjectSpecId getObjectSpecId() {
+               
+               val path = universalId().getPath();
+               
+               val firstPathEntry = _Strings.splitThenStream(path, "/")
+               .filter(_Strings::isNotEmpty)
+               .findFirst()
+               .orElse(null);
+               
+               return ObjectSpecId.of(firstPathEntry);
+       }
+
+       @Override
+       public String getIdentifier() {
+               return universalId().getQuery();
+       }
+
+       @Override
+       public Bookmark asBookmark() {
+               
+               //TODO [2033] bad place to do this here, change API ?
+               //probe.println("NOT IMPLEMENTED: 'asBookmark()'");
+               
+               final String objectType = getObjectSpecId().asString(); 
+                               //asBookmarkObjectState().getCode() + 
rootOid.getObjectSpecId().asString();
+        final String identifier = universalId().getQuery();
+                       //rootOid.getIdentifier();
+        
+        return new Bookmark(objectType, identifier);
+
+       }
+
+       @Override
+       public OidDto asOidDto() {
+               _Exceptions.throwNotImplemented();
+               
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       public String enString() {
+               if(version==null) {
+                       return enStringNoVersion();
+               }
+               return _URI.uriBuilder(universalId)
+                               .fragment(version.enString())
+                               .build()
+                               .toURI()
+                               .toString();
+       }
+
+       @Override
+       public String enStringNoVersion() {
+               return universalId.toString();
+       }
+
+       @Override
+       public boolean isTransient() {
+               return false;
+       }
+
+       @Override
+       public boolean isViewModel() {
+               return false;
+       }
+
+       @Override
+       public boolean isPersistent() {
+               return true;
+       }
+
+       @Override
+       public Oid copy() {
+               return of(universalId());
+       }
+
+       @Override
+       public void encode(DataOutputExtended outputStream) throws IOException {
+               _Exceptions.throwNotImplemented();
+               
+               // TODO Auto-generated method stub
+               
+       }
+
+       @Override
+       public URI universalId() {
+               return universalId;
+       }
+
+
+}
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/UniversalOid.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/UniversalOid.java
new file mode 100644
index 0000000..5773b37
--- /dev/null
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/UniversalOid.java
@@ -0,0 +1,9 @@
+package org.apache.isis.core.metamodel.adapter.oid;
+
+import java.net.URI;
+
+public interface UniversalOid extends RootOid {
+
+       URI universalId();
+       
+}
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
index 1409ff9..46bc043 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
@@ -25,8 +25,13 @@ import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import 
org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
 
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Value;
+
 /**
- * Represents an instance of some element of the meta-model managed by the 
framework.
+ * Represents an instance of some element of the meta-model managed by the 
framework, 
+ * that is IoC-container provided beans or persistence-stack provided 
entities.  
  *
  */
 public interface ManagedObject {
@@ -42,6 +47,14 @@ public interface ManagedObject {
      */
     Object getPojo();
     
+    // -- SIMPLE
+    
+    @Value @RequiredArgsConstructor(staticName="of") 
+    public final static class SimpleManagedObject implements ManagedObject {
+        @Getter private final ObjectSpecification specification;
+        @Getter private final Object pojo;
+    }
+    
     // -- TITLE
     
     public default String titleString() {
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
index 2e607ed..5cf33b2 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
@@ -66,7 +66,6 @@ import 
org.apache.isis.core.metamodel.specloader.validator.ValidationFailures;
 import org.apache.isis.core.runtime.threadpool.ThreadPoolExecutionMode;
 import org.apache.isis.core.runtime.threadpool.ThreadPoolSupport;
 import org.apache.isis.progmodels.dflt.ProgrammingModelFacetsJava5;
-import org.apache.isis.schema.metamodel.v1.MetamodelDto;
 import org.apache.isis.schema.utils.CommonDtoUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -216,7 +215,7 @@ public class SpecificationLoader {
 
         LOG.info("init() - done");
         
-        //FIXME [2033] remove
+        //FIXME [2033] remove debug code ...
         {
                streamServiceClasses()
                .forEach(service->probe.println("using service %s", service));
diff --git 
a/core/plugins/ioc-weld/src/main/java/org/apache/isis/core/plugins/ioc/weld/WeldFactory.java
 
b/core/plugins/ioc-weld/src/main/java/org/apache/isis/core/plugins/ioc/weld/WeldFactory.java
index 4627805..c322b75 100644
--- 
a/core/plugins/ioc-weld/src/main/java/org/apache/isis/core/plugins/ioc/weld/WeldFactory.java
+++ 
b/core/plugins/ioc-weld/src/main/java/org/apache/isis/core/plugins/ioc/weld/WeldFactory.java
@@ -62,7 +62,6 @@ public class WeldFactory {
                            
"org.apache.isis.core.wrapper.WrapperFactoryDefault",
                            
"org.apache.isis.viewer.wicket.viewer.IsisWicketModule",
                            
"org.apache.isis.applib.services.jdosupport.IsisJdoSupportDN5",
-                           
"org.apache.isis.core.runtime.services.ServiceInstantiator",
                            
                            "org.apache.wicket.cdi.AutoConversation",
                            
"org.apache.isis.viewer.restfulobjects.rendering.RendererContext"
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextHandler.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextHandler.java
new file mode 100644
index 0000000..477c988
--- /dev/null
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextHandler.java
@@ -0,0 +1,28 @@
+package org.apache.isis.core.runtime.contextmanger;
+
+import java.net.URI;
+
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+/**
+ * @since 2.0.0-M3
+ */
+public interface ContextHandler extends ManagedObjectResolver {
+
+       /**
+        * To support chain-of-responsibility pattern.
+        * @param objectSpec
+        * @return whether this manager sees itself responsible to manage 
objects represented by given objectSpec
+        */
+       boolean recognizes(ObjectSpecification objectSpec);
+       
+       /**
+        * To support chain-of-responsibility pattern.
+        * @param uri
+        * @return whether this manager sees itself responsible to manage 
objects represented by given uri
+        */
+       boolean recognizes(URI uri);
+       
+
+       
+}
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextManager.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextManager.java
new file mode 100644
index 0000000..69fe5ba
--- /dev/null
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ContextManager.java
@@ -0,0 +1,12 @@
+package org.apache.isis.core.runtime.contextmanger;
+
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+/**
+ * @since 2.0.0-M3
+ */
+public interface ContextManager extends ManagedObjectResolver {
+
+       ManagedObjectResolver resolverFor(ObjectSpecification spec);
+       
+}
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ManagedObjectResolver.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ManagedObjectResolver.java
new file mode 100644
index 0000000..08ce300
--- /dev/null
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/ManagedObjectResolver.java
@@ -0,0 +1,33 @@
+package org.apache.isis.core.runtime.contextmanger;
+
+import java.net.URI;
+
+import javax.enterprise.inject.Instance;
+
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+
+/**
+ * @since 2.0.0-M3
+ */
+public interface ManagedObjectResolver {
+
+       /**
+        * Returns object identifier, which holds sufficient information for 
the framework to 
+        * retrieve a reference to given managedObject later.
+        * 
+        * @param managedObject
+        * @return identifier 
+        */
+       URI identifierOf(ManagedObject managedObject);
+       
+       
+       /**
+        * Retrieve a reference to the ManagedObject as identified by the 
identifier. 
+        * @param spec 
+        * @param identifier
+        * @return
+        */
+       Instance<ManagedObject> resolve(ObjectSpecId spec, URI identifier);
+       
+}
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/UniversalContextManager.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/UniversalContextManager.java
new file mode 100644
index 0000000..7ef59ad
--- /dev/null
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/contextmanger/UniversalContextManager.java
@@ -0,0 +1,73 @@
+package org.apache.isis.core.runtime.contextmanger;
+
+import static org.apache.isis.commons.internal.base._With.requires;
+
+import java.net.URI;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+import lombok.val;
+
+@Singleton
+public class UniversalContextManager implements ContextManager {
+
+       @Inject Instance<ContextHandler> contextHandlers;
+       
+       @Override
+       public URI identifierOf(ManagedObject managedObject) {
+               
+               requires(managedObject, "managedObject");
+               
+               val resolver = resolverFor(managedObject.getSpecification());
+               if(resolver==null) {
+                       val msg = String.format(
+                                       "Could not find a ContextHandler that 
recognizes managedObject of type %s.", managedObject);
+                       throw _Exceptions.unrecoverable(msg); 
+               }
+               
+               val uri = resolver.identifierOf(managedObject);
+               
+               return uri;
+               
+       }
+
+       @Override
+       public Instance<ManagedObject> resolve(ObjectSpecId spec, URI 
identifier) {
+               
+               requires(identifier, "identifier");
+               
+               val instance = contextHandlers.stream()
+               .filter(handler->handler.recognizes(identifier))
+               .findFirst()
+               .map(handler->handler.resolve(spec, identifier))
+               .orElseThrow(()->{
+                       val msg = String.format(
+                                       "Could not find a ContextHandler that 
recognizes identifier URI %s.", identifier);
+                       return _Exceptions.unrecoverable(msg);
+               }); 
+               
+               return instance;
+       }
+
+       @Override
+       public ManagedObjectResolver resolverFor(ObjectSpecification objSpec) {
+               
+               requires(objSpec, "objSpec");
+               
+               return contextHandlers.stream()
+               .filter(handler->handler.recognizes(objSpec))
+               .findFirst()
+               .orElse(null);
+       }
+
+
+       
+       
+}
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 d74b22a..104b406 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
@@ -21,10 +21,8 @@ package org.apache.isis.core.runtime.persistence.adapter;
 
 import static org.apache.isis.commons.internal.base._With.requires;
 
-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.exceptions.IsisException;
 import org.apache.isis.core.commons.util.ToString;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -32,12 +30,15 @@ import 
org.apache.isis.core.metamodel.adapter.concurrency.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.ParentedOid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.adapter.oid.UniversalOid;
 import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
 import org.apache.isis.core.metamodel.adapter.version.Version;
 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;
 import org.apache.isis.core.security.authentication.AuthenticationSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public final class PojoAdapter implements ObjectAdapter {
 
@@ -113,6 +114,11 @@ public final class PojoAdapter implements ObjectAdapter {
     
     @Override
     public boolean isTransient() {
+       
+       if(oid instanceof UniversalOid) {
+               return oid.isTransient(); //FIXME [2033] this is a quick-hack
+       }
+       
         if(getSpecification().isService() || getSpecification().isViewModel()) 
{
             // services and view models are treated as persistent objects
             return false;
@@ -122,6 +128,11 @@ public final class PojoAdapter implements ObjectAdapter {
 
     @Override
     public boolean representsPersistent() {
+       
+       if(oid instanceof UniversalOid) {
+               return oid.isPersistent(); //FIXME [2033] this is a quick-hack
+       }
+       
         if(getSpecification().isService() || getSpecification().isViewModel()) 
{
             // services and view models are treated as persistent objects
             return true;
@@ -131,6 +142,11 @@ public final class PojoAdapter implements ObjectAdapter {
 
     @Override
     public boolean isDestroyed() {
+       
+       if(oid instanceof UniversalOid) {
+               return false; //FIXME [2033] this is a quick-hack
+       }
+       
         if(getSpecification().isService() || getSpecification().isViewModel()) 
{
             // services and view models are treated as persistent objects
             return false;
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 6d78ee1..134931c 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
@@ -40,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.contextmanger.ContextManager;
 import org.apache.isis.core.runtime.memento.Data;
+import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.security.authentication.AuthenticationSession;
 
@@ -76,6 +78,7 @@ final public class ObjectAdapterContext {
     final ObjectAdapterContext_ObjectCreation objectCreationMixin;
     private final ObjectAdapterContext_LifecycleEventSupport 
lifecycleEventMixin;
     private final ServiceInjector servicesInjector;
+    final ContextManager contextManager;
 
     private ObjectAdapterContext(
             ServiceInjector servicesInjector, 
@@ -89,7 +92,10 @@ final public class ObjectAdapterContext {
         this.mementoSupportMixin = new 
ObjectAdapterContext_MementoSupport(this, persistenceSession);
         this.serviceLookupMixin = new ObjectAdapterContext_ServiceLookup(this, 
servicesInjector);
         this.newIdentifierMixin = new ObjectAdapterContext_NewIdentifier(this, 
metaModelContext, persistenceSession);
-        this.objectAdapterByIdProviderMixin = new 
ObjectAdapterContext_ObjectAdapterByIdProvider(this, metaModelContext, 
persistenceSession, authenticationSession);
+        
+        this.contextManager = 
IsisContext.getServiceRegistry().lookupServiceElseFail(ContextManager.class);
+        
+        this.objectAdapterByIdProviderMixin = new 
ObjectAdapterContext_ObjectAdapterByIdProvider(this, contextManager, 
metaModelContext, persistenceSession, authenticationSession);
         this.dependencyInjectionMixin = new 
ObjectAdapterContext_DependencyInjection(this, persistenceSession);
         this.objectCreationMixin = new 
ObjectAdapterContext_ObjectCreation(this, metaModelContext, persistenceSession);
         this.lifecycleEventMixin = new 
ObjectAdapterContext_LifecycleEventSupport(this, metaModelContext, 
persistenceSession);
@@ -102,6 +108,8 @@ final public class ObjectAdapterContext {
                 authenticationSession, 
                 specificationLoader, 
                 persistenceSession);
+        
+        
     }
 
     // -- DEBUG
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterByIdProvider.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterByIdProvider.java
index 5add0ce..9606686 100644
--- 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterByIdProvider.java
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterByIdProvider.java
@@ -20,13 +20,12 @@ package 
org.apache.isis.core.runtime.system.persistence.adaptermanager;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Stream;
 
-import org.slf4j.Logger;
-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.ensure.Ensure;
 import org.apache.isis.core.metamodel.MetaModelContext;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -34,15 +33,21 @@ import 
org.apache.isis.core.metamodel.adapter.ObjectAdapterByIdProvider;
 import org.apache.isis.core.metamodel.adapter.concurrency.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.adapter.oid.UniversalOid;
 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.object.viewmodel.ViewModelFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.core.runtime.contextmanger.ContextManager;
 import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
 import org.apache.isis.core.runtime.persistence.PojoRecreationException;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.security.authentication.AuthenticationSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import lombok.val;
 
 /**
  * package private mixin for ObjectAdapterContext
@@ -59,18 +64,23 @@ class ObjectAdapterContext_ObjectAdapterByIdProvider 
implements ObjectAdapterByI
     private final PersistenceSession persistenceSession;
     private final SpecificationLoader specificationLoader;
     private final AuthenticationSession authenticationSession;
+    private final ContextManager contextManager;
     private final boolean concurrencyCheckingGloballyEnabled;
     
     ObjectAdapterContext_ObjectAdapterByIdProvider(
             ObjectAdapterContext objectAdapterContext,
+            ContextManager contextManager,
             MetaModelContext metaModelContext,
             PersistenceSession persistenceSession,
             AuthenticationSession authenticationSession) {
         
+       Objects.requireNonNull(contextManager);
+       
         this.objectAdapterContext = objectAdapterContext;
         this.persistenceSession = persistenceSession;
         this.specificationLoader = metaModelContext.getSpecificationLoader();
         this.authenticationSession = authenticationSession;
+        this.contextManager = contextManager;
         
         this.concurrencyCheckingGloballyEnabled = 
                 
!ConcurrencyChecking.isGloballyDisabled(persistenceSession.getConfiguration());
@@ -108,7 +118,7 @@ class ObjectAdapterContext_ObjectAdapterByIdProvider 
implements ObjectAdapterByI
             final RootOid rootOid,
             final ConcurrencyChecking concurrencyChecking) {
                 
-        /* FIXME[ISIS-1976] SPI for adapterFor(RootOid)
+        /* FIXME [ISIS-1976] SPI for adapterFor(RootOid)
          * https://github.com/apache/isis/pull/121#discussion_r215889748
          * 
          * Eventually I'm hoping that this code will simplify and then become 
pluggable.
@@ -125,8 +135,33 @@ class ObjectAdapterContext_ObjectAdapterByIdProvider 
implements ObjectAdapterByI
          * into some other datastore. So really my "PersistenceProvider" is a
          * generalization of that concept).
          */
-        
-        //FIXME[ISIS-1976] remove guard
+       
+       if(rootOid instanceof UniversalOid) {
+               
+               Objects.requireNonNull(rootOid);
+               
+               val universalOid = (UniversalOid) rootOid;
+               val spec = universalOid.getObjectSpecId();
+               val instance = contextManager.resolve(spec, 
universalOid.universalId());
+               
+               if(instance.isResolvable()) {
+                       val managedObject = instance.get();
+                       return 
objectAdapterContext.getFactories().createRootAdapter(managedObject.getPojo(), 
rootOid); 
+               } else if(instance.isAmbiguous()) {
+                       
+                       //FIXME [2033] handle ambiguity
+                       throw _Exceptions.notImplemented();
+                       
+               } else {
+                       
+                       //FIXME [2033] handle no such element
+                       throw _Exceptions.notImplemented();
+               }
+               
+               
+       }
+       
+        //FIXME [ISIS-1976] remove guard
         final ObjectAdapter serviceAdapter = 
objectAdapterContext.lookupServiceAdapterFor(rootOid);
         if (serviceAdapter != null) {
             //throw _Exceptions.unexpectedCodeReach();
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 90ea7d7..b829ddb 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
@@ -35,6 +35,7 @@ import org.apache.isis.core.metamodel.MetaModelContext;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapterProvider;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.adapter.oid.UniversalOid;
 import org.apache.isis.core.metamodel.services.ServiceUtil;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -72,8 +73,8 @@ class ObjectAdapterContext_ObjectAdapterProvider implements 
ObjectAdapterProvide
         
         this.oidFactory = 
OidFactory.builder(pojo->specificationLoader.loadSpecification(pojo.getClass()))
                 .add(new 
ObjectAdapterContext_OidProviders.GuardAgainstRootOid())
+                .add(new 
ObjectAdapterContext_OidProviders.OidForManagedContexts())
                 .add(new ObjectAdapterContext_OidProviders.OidForServices())
-                .add(new 
ObjectAdapterContext_OidProviders.OidForManagedBeans())
                 .add(new ObjectAdapterContext_OidProviders.OidForValues())
                 .add(new ObjectAdapterContext_OidProviders.OidForViewModels())
                 .add(new ObjectAdapterContext_OidProviders.OidForPersistent())
@@ -88,10 +89,13 @@ class ObjectAdapterContext_ObjectAdapterProvider implements 
ObjectAdapterProvide
             return null;
         }
         
-        //FIXME [2033] the pojo might be a managed object (eg. by Spring or 
CDI), this is new 
-        
         final RootOid rootOid = oidFactory.oidFor(pojo);
         final ObjectAdapter newAdapter = 
objectAdapterContext.getFactories().createRootAdapter(pojo, rootOid);
+        
+        // the pojo might be a managed object (eg. by Spring or CDI), this is 
new
+        if(rootOid instanceof UniversalOid) {
+               return newAdapter; // skip service injection
+        }
         return objectAdapterContext.injectServices(newAdapter);
     }
     
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_OidProviders.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_OidProviders.java
index 4421f59..699b4d6 100644
--- 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_OidProviders.java
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_OidProviders.java
@@ -18,19 +18,19 @@
  */
 package org.apache.isis.core.runtime.system.persistence.adaptermanager;
 
-import java.lang.reflect.InvocationTargetException;
+import java.util.Objects;
 import java.util.UUID;
 
-import javax.persistence.Entity;
-
-import org.apache.isis.commons.internal._Constants;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.base._Lazy;
+import org.apache.isis.commons.internal.base._Tuples;
 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.metamodel.spec.ManagedObject;
+import org.apache.isis.core.runtime.contextmanger.ContextManager;
+import org.apache.isis.core.runtime.contextmanger.ManagedObjectResolver;
 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;
@@ -43,31 +43,30 @@ class ObjectAdapterContext_OidProviders {
     static class GuardAgainstRootOid implements OidProvider {
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
-            return pojo instanceof RootOid;
+        public boolean isHandling(ManagedObject managedObject) {
+            return managedObject.getPojo() instanceof RootOid;
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
             throw new IllegalArgumentException("Cannot create a RootOid for 
pojo, "
                     + "when pojo is instance of RootOid. You might want to ask 
"
                     + "ObjectAdapterByIdProvider for an ObjectAdapter 
instead.");
         }
-
     }
     
     
     static class OidForServices implements OidProvider {
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
-            return spec.isService();
+        public boolean isHandling(ManagedObject managedObject) {
+            return managedObject.getSpecification().isService();
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
             final String identifier = PersistenceSession.SERVICE_IDENTIFIER;
-            return Oid.Factory.persistentOf(spec.getSpecId(), identifier);
+            return 
Oid.Factory.persistentOf(managedObject.getSpecification().getSpecId(), 
identifier);
         }
 
     }
@@ -77,14 +76,18 @@ class ObjectAdapterContext_OidProviders {
         private final IsisJdoMetamodelPlugin isisJdoMetamodelPlugin = 
IsisJdoMetamodelPlugin.get();
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+        public boolean isHandling(ManagedObject managedObject) {
             // equivalent to 'isInstanceOfPersistable = pojo instanceof 
Persistable'
-            final boolean isInstanceOfPersistable = 
isisJdoMetamodelPlugin.isPersistenceEnhanced(pojo.getClass());
+            final boolean isInstanceOfPersistable = isisJdoMetamodelPlugin
+                       
.isPersistenceEnhanced(managedObject.getPojo().getClass());
             return isInstanceOfPersistable;
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
+               val pojo = managedObject.getPojo();
+               val spec = managedObject.getSpecification();
+               
             final PersistenceSession persistenceSession = 
IsisContext.getPersistenceSession().get();
             final boolean isRecognized = persistenceSession.isRecognized(pojo);
             if(isRecognized) {
@@ -98,38 +101,40 @@ class ObjectAdapterContext_OidProviders {
         
     }
 
-    static class OidForManagedBeans implements OidProvider {
+    static class OidForManagedContexts implements OidProvider {
 
-        //FIXME [2033] this is just a PoC for 'Customer'
+       final _Lazy<ContextManager> contextManager = _Lazy.of(()->
+               
IsisContext.getServiceRegistry().lookupServiceElseFail(ContextManager.class));
+       
+       private _Tuples.Tuple2<Object, ManagedObjectResolver> latestLookup; // 
acts as a cache
        
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
-               return pojo.getClass().isAnnotationPresent(Entity.class);
+        public boolean isHandling(ManagedObject managedObject) {
+               val pojo = managedObject.getPojo();
+               val spec = managedObject.getSpecification();
+               
+               val managedObjectResolver = 
contextManager.get().resolverFor(spec);
+               
+               if(managedObjectResolver!=null) {
+                       // likely to be reused below, just an optimization
+                       latestLookup = _Tuples.pair(pojo, 
managedObjectResolver);
+                       return true;
+               }
+               return false;
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
-               try {
-                               return oidForCustomer(pojo, spec);
-                       } catch (NoSuchMethodException | SecurityException | 
IllegalAccessException | IllegalArgumentException
-                                       | InvocationTargetException e) {
-                               throw _Exceptions.unrecoverable(e);
-                       }
-        }
-        
-        private RootOid oidForCustomer(Object pojo, ObjectSpecification spec) 
-                       throws NoSuchMethodException, SecurityException, 
IllegalAccessException, 
-                       IllegalArgumentException, InvocationTargetException {
-               
-               val idGetter = pojo.getClass().getMethod("getId", 
_Constants.emptyClasses);
-               Long id = (Long)idGetter.invoke(pojo, _Constants.emptyObjects);
-               if(id!=null && id>0) {
-                       final String identifier = "" + id;
-                       return Oid.Factory.persistentOf(spec.getSpecId(), 
identifier);  
-               } else {
-                final String identifier = UUID.randomUUID().toString();
-                return Oid.Factory.transientOf(spec.getSpecId(), identifier);  
  
-            }
+        public RootOid oidFor(ManagedObject managedObject) {
+               val pojo = managedObject.getPojo();
+               val spec = managedObject.getSpecification();
+
+               val managedObjectResolver =     (latestLookup!=null && 
+                               Objects.equals(pojo, latestLookup.get_1()))
+                               ? latestLookup.get_2() // use cache
+                                               : 
contextManager.get().resolverFor(spec);
+                               
+               val objectIdUri = 
managedObjectResolver.identifierOf(managedObject);
+               return Oid.Factory.universal(objectIdUri);
         }
         
     }
@@ -137,12 +142,13 @@ class ObjectAdapterContext_OidProviders {
     static class OidForValues implements OidProvider {
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+        public boolean isHandling(ManagedObject managedObject) {
+               val spec = managedObject.getSpecification();
             return spec.containsFacet(ValueFacet.class);
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
             return Oid.Factory.value();
         }
 
@@ -151,12 +157,16 @@ class ObjectAdapterContext_OidProviders {
     static class OidForViewModels implements OidProvider {
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+        public boolean isHandling(ManagedObject managedObject) {
+               val spec = managedObject.getSpecification();
             return spec.containsFacet(ViewModelFacet.class);
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
+               val pojo = managedObject.getPojo();
+               val spec = managedObject.getSpecification();
+               
             final ViewModelFacet recreatableObjectFacet = 
spec.getFacet(ViewModelFacet.class);
             final String identifier = recreatableObjectFacet.memento(pojo);
             return Oid.Factory.viewmodelOf(spec.getSpecId(), identifier);
@@ -167,12 +177,13 @@ class ObjectAdapterContext_OidProviders {
     static class OidForOthers implements OidProvider {
 
         @Override
-        public boolean isHandling(Object pojo, ObjectSpecification spec) {
+        public boolean isHandling(ManagedObject managedObject) {
             return true; // try to handle anything
         }
 
         @Override
-        public RootOid oidFor(Object pojo, ObjectSpecification spec) {
+        public RootOid oidFor(ManagedObject managedObject) {
+               val spec = managedObject.getSpecification();
             final String identifier = UUID.randomUUID().toString();
             return Oid.Factory.transientOf(spec.getSpecId(), identifier);
         }
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
index d3646ae..3b34eb7 100644
--- 
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
@@ -22,6 +22,7 @@ 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.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 /**
@@ -32,8 +33,8 @@ public interface OidFactory {
     RootOid oidFor(Object pojo);
     
     public interface OidProvider {
-        boolean isHandling(Object pojo, ObjectSpecification spec);
-        RootOid oidFor(Object pojo, ObjectSpecification spec);
+        boolean isHandling(ManagedObject managedObject);
+        RootOid oidFor(ManagedObject managedObject);
     }
     
     public interface OidFactoryBuilder {
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
index 4f4e46a..fab1201 100644
--- 
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
@@ -19,16 +19,20 @@
 
 package 
org.apache.isis.core.runtime.system.persistence.adaptermanager.factories;
 
+import static java.util.Objects.requireNonNull;
+
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 import java.util.function.Function;
 
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+import org.apache.isis.core.metamodel.spec.ManagedObject.SimpleManagedObject;
 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;
 
+import lombok.val;
+
 class OidFactory_Builder implements OidFactoryBuilder {
     
     private final List<OidProvider> handler = new ArrayList<>();
@@ -49,14 +53,15 @@ class OidFactory_Builder implements OidFactoryBuilder {
         return pojo -> {
 
             final ObjectSpecification spec = specProvider.apply(pojo);
-
+            val managedObject = SimpleManagedObject.of(spec, pojo);
+            
             final RootOid rootOid = handler.stream()
-            .filter(h->h.isHandling(pojo, spec))
+            .filter(h->h.isHandling(managedObject))
             .findFirst()
-            .map(h->h.oidFor(pojo, spec))
+            .map(h->h.oidFor(managedObject))
             .orElse(null);
 
-            Objects.requireNonNull(rootOid, () -> "Could not create an Oid for 
pojo: "+pojo);
+            requireNonNull(rootOid, () -> "Could not create an Oid for pojo: 
"+pojo);
 
             return rootOid;
         };
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionProducerBean.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionProducerBean.java
index 5cba4d2..e5c6171 100644
--- 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionProducerBean.java
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionProducerBean.java
@@ -29,14 +29,15 @@ import 
org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import 
org.apache.isis.core.runtime.system.persistence.PersistenceSessionFactory;
 
 /**
- * @deprecated TODO [2033] 
+ * @deprecated TODO [2033] convert ...
  * Currently `IsisSessionFactory` and those singletons that depend on it 
  * (`SpecificationLoader` and `PersistenceSessionFactory`) are not life-cycle 
  * managed by CDI, instead we provide Producer Methods for these.
  * 
  * Consequently the framework is responsible for their life-cycles. 
  * 
- * We want to have CDI also manage these, which can be achieved by finally 
removing the `IsisSessionProducerBean` singleton.
+ * We want to have CDI also manage these, which can be achieved by finally 
+ * removing the `IsisSessionProducerBean` singleton.
  *
  */
 @Singleton
diff --git 
a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
 
b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
index 0b4ba2b..f38350a 100644
--- 
a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
+++ 
b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/IsisWicketApplication.java
@@ -253,7 +253,7 @@ implements ComponentFactoryRegistryAccessor, 
PageClassRegistryAccessor, WicketVi
             new CdiConfiguration(beanManager).configure(this);
 
 
-//            // FIXME [2033]
+//            // FIXME [2033] remove comments ...
 //            // create IsisSessionFactory
 //            //
 //            final Injector injector = Guice.createInjector(
diff --git 
a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/ConverterForObjectAdapterMemento.java
 
b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/ConverterForObjectAdapterMemento.java
index 6b62d8d..f944f15 100644
--- 
a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/ConverterForObjectAdapterMemento.java
+++ 
b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/ConverterForObjectAdapterMemento.java
@@ -56,7 +56,7 @@ public class ConverterForObjectAdapterMemento implements 
IConverter<ObjectAdapte
         final RootOid oid = RootOid.deStringEncoded(value);
         
         final ObjectAdapter adapter = getPersistenceSession().adapterFor(oid);
-        return ObjectAdapterMemento.createOrNull(adapter);
+        return ObjectAdapterMemento.mementoOf(adapter);
     }
 
     /**
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 66c315b..1ed2992 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
@@ -20,14 +20,18 @@
 package org.apache.isis.viewer.wicket.model.mementos;
 
 import java.io.Serializable;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.function.Function;
 
+import javax.annotation.Nullable;
+
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.hint.HintStore;
 import org.apache.isis.commons.internal.collections._Lists;
+import org.apache.isis.commons.internal.uri._URI;
 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;
@@ -44,6 +48,8 @@ import org.apache.isis.core.runtime.memento.Memento;
 import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 
+import lombok.val;
+
 public class ObjectAdapterMemento implements Serializable {
 
     private static final long serialVersionUID = 1L;
@@ -51,7 +57,7 @@ public class ObjectAdapterMemento implements Serializable {
     /**
      * Factory method
      */
-    public static ObjectAdapterMemento createOrNull(final ObjectAdapter 
adapter) {
+    public static ObjectAdapterMemento mementoOf(@Nullable final ObjectAdapter 
adapter) {
         if (adapter == null) {
             return null;
         }
@@ -226,6 +232,14 @@ public class ObjectAdapterMemento implements Serializable {
                     final ObjectAdapterMemento oam,
                     ConcurrencyChecking concurrencyChecking,
                     final PersistenceSession persistenceSession, final 
SpecificationLoader specificationLoader) {
+               
+               if(_URI.isUoid(oam.persistentOidStr)) {
+                       val uri = URI.create(oam.persistentOidStr);
+                       val oid = Oid.Factory.universal(uri);
+                       val objAdapter = persistenceSession.adapterFor(oid, 
concurrencyChecking);
+                       return objAdapter;
+               }
+               
                 RootOid oid = 
Oid.unmarshaller().unmarshal(oam.persistentOidStr, RootOid.class);
                 try {
                     final ObjectAdapter adapter = 
persistenceSession.adapterFor(oid, concurrencyChecking);
@@ -573,11 +587,11 @@ public class ObjectAdapterMemento implements Serializable 
{
         }
 
         public static Function<Object, ObjectAdapterMemento> fromPojo(final 
ObjectAdapterProvider adapterProvider) {
-            return pojo->ObjectAdapterMemento.createOrNull( 
adapterProvider.adapterFor(pojo) );
+            return pojo->ObjectAdapterMemento.mementoOf( 
adapterProvider.adapterFor(pojo) );
                 }
 
         public static Function<ObjectAdapter, ObjectAdapterMemento> 
fromAdapter() {
-            return ObjectAdapterMemento::createOrNull;
+            return ObjectAdapterMemento::mementoOf;
         }
 
         public static Function<ObjectAdapterMemento, ObjectAdapter> 
fromMemento(
@@ -596,7 +610,7 @@ public class ObjectAdapterMemento implements Serializable {
         }
 
         public static Function<ObjectAdapter, ObjectAdapterMemento> 
toMemento() {
-            return ObjectAdapterMemento::createOrNull;
+            return ObjectAdapterMemento::mementoOf;
         }
 
 
diff --git 
a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
 
b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
index f913940..8c7ddb9 100644
--- 
a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
+++ 
b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
@@ -488,7 +488,7 @@ UiHintContainer {
 
 
     public void toggleSelectionOn(ObjectAdapter selectedAdapter) {
-        ObjectAdapterMemento selectedAsMemento = 
ObjectAdapterMemento.createOrNull(selectedAdapter);
+        ObjectAdapterMemento selectedAsMemento = 
ObjectAdapterMemento.mementoOf(selectedAdapter);
 
         // try to remove; if couldn't, then mustn't have been in there, in 
which case add.
         boolean removed = toggledMementosList.remove(selectedAsMemento);
diff --git 
a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
 
b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
index 4235404..8e27759 100644
--- 
a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
+++ 
b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
@@ -177,7 +177,7 @@ public class EntityModel extends 
BookmarkableModel<ObjectAdapter> implements Obj
     }
 
     public EntityModel(final ObjectAdapter adapter) {
-        this(ObjectAdapterMemento.createOrNull(adapter));
+        this(ObjectAdapterMemento.mementoOf(adapter));
         setObject(adapter);
     }
 
@@ -356,7 +356,7 @@ public class EntityModel extends 
BookmarkableModel<ObjectAdapter> implements Obj
     @Override
     public void setObject(final ObjectAdapter adapter) {
         super.setObject(adapter);
-        adapterMemento = ObjectAdapterMemento.createOrNull(adapter);
+        adapterMemento = ObjectAdapterMemento.mementoOf(adapter);
     }
 
     public void setObjectMemento(
@@ -532,7 +532,7 @@ public class EntityModel extends 
BookmarkableModel<ObjectAdapter> implements Obj
                 return pending;
             }
             final ObjectAdapter adapter = entityModel.getObject();
-            return ObjectAdapterMemento.createOrNull(adapter);
+            return ObjectAdapterMemento.mementoOf(adapter);
         }
 
         @Override
diff --git 
a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModelForReference.java
 
b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModelForReference.java
index 6110b73..f4610ab 100644
--- 
a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModelForReference.java
+++ 
b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModelForReference.java
@@ -91,7 +91,7 @@ public class EntityModelForReference implements 
ObjectAdapterModel {
     @Override
     public PageParameters getPageParameters() {
         PageParameters pageParameters = createPageParameters(getObject());
-        ObjectAdapterMemento oam = 
ObjectAdapterMemento.createOrNull(getObject());
+        ObjectAdapterMemento oam = ObjectAdapterMemento.mementoOf(getObject());
         HintPageParameterSerializer.hintStoreToPageParameters(pageParameters, 
oam);
         return pageParameters;
     }
diff --git 
a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ValueModel.java
 
b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ValueModel.java
index 2f4698e..ca05d5e 100644
--- 
a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ValueModel.java
+++ 
b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ValueModel.java
@@ -34,7 +34,7 @@ public class ValueModel extends ModelAbstract<ObjectAdapter> {
     private final ObjectAdapterMemento adapterMemento;
 
     public ValueModel(final ObjectAdapter adapter) {
-        adapterMemento = ObjectAdapterMemento.createOrNull(adapter);
+        adapterMemento = ObjectAdapterMemento.mementoOf(adapter);
     }
 
     @Override
diff --git 
a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
 
b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
index 2a33d13..cdd7423 100644
--- 
a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
+++ 
b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
@@ -48,7 +48,7 @@ public final class EntityActionLinkFactory extends 
ActionLinkFactoryAbstract {
 
         final ObjectAdapter objectAdapter = 
this.targetEntityModel.load(ConcurrencyChecking.NO_CHECK);
 
-        final Boolean persistent = objectAdapter.representsPersistent();
+        final boolean persistent = objectAdapter.representsPersistent();
         if (!persistent) {
             throw new IllegalArgumentException(String.format(
                     "Object '%s' is not persistent.", 
objectAdapter.titleString(null)));
diff --git 
a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
 
b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
index 49d3eef..59ee34b 100644
--- 
a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
+++ 
b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
@@ -19,6 +19,7 @@ package org.apache.isis.viewer.wicket.ui.panels;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Callable;
+import java.util.function.BiFunction;
 import java.util.stream.Stream;
 
 import org.apache.isis.applib.RecoverableException;
@@ -30,9 +31,12 @@ import 
org.apache.isis.applib.services.exceprecog.ExceptionRecognizerComposite;
 import org.apache.isis.applib.services.hint.HintStore;
 import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
+import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.concurrency.ConcurrencyChecking;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.adapter.oid.UniversalOid;
 import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
 import org.apache.isis.core.metamodel.facets.actions.redirect.RedirectFacet;
 import 
org.apache.isis.core.metamodel.facets.properties.renderunchanged.UnchangingFacet;
@@ -68,6 +72,8 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Throwables;
 
+import lombok.val;
+
 public final class FormExecutorDefault<M extends 
BookmarkableModel<ObjectAdapter> & ParentEntityModelProvider>
 implements FormExecutor {
 
@@ -279,10 +285,24 @@ implements FormExecutor {
             final ObjectAdapter targetAdapter,
             final ObjectAdapter resultAdapter) {
 
-        final ObjectAdapterMemento targetOam = 
ObjectAdapterMemento.createOrNull(targetAdapter);
-        final ObjectAdapterMemento resultOam = 
ObjectAdapterMemento.createOrNull(resultAdapter);
-
-        return differs(targetOam, resultOam);
+       val left = targetAdapter.getOid();
+       val right = resultAdapter.getOid();
+       
+       val differs = _Casts.castThenApply(left, right, UniversalOid.class,
+                       (l, r)-> !Objects.equals(l, r), // onBothCast
+                       (l, r) -> true, // onLeftCast
+                       (l, r) -> true, // onRightCast
+                       (l, r) -> { // onNonCast
+                               
+                               // legacy behavior, for non UniversalOid
+                               
+                       final ObjectAdapterMemento targetOam = 
ObjectAdapterMemento.mementoOf(targetAdapter);
+                       final ObjectAdapterMemento resultOam = 
ObjectAdapterMemento.mementoOf(resultAdapter);
+               
+                       return differs(targetOam, resultOam);                   
+                       });
+               
+               return differs;
     }
 
     private static boolean differs(
diff --git 
a/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/menubars.layout.xml
 
b/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/menubars.layout.xml
index d286f2d..9846d45 100644
--- 
a/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/menubars.layout.xml
+++ 
b/example/application/simpleapp/application/src/main/java/domainapp/application/manifest/menubars.layout.xml
@@ -33,6 +33,19 @@
                 </mb3:serviceAction>
             </mb3:section>
         </mb3:menu>
+        
+        </mb3:menu>
+                       <mb3:named>Spring</mb3:named>
+            <mb3:section>
+                <mb3:serviceAction objectType="simple.CustomerMenu" 
id="createCustomer">
+                    <cpt:named>Create Customer</cpt:named>
+                </mb3:serviceAction>
+                <mb3:serviceAction objectType="simple.CustomerMenu" 
id="findByLastName">
+                    <cpt:named>Find By Last Name</cpt:named>
+                </mb3:serviceAction>
+            </mb3:section>
+        </mb3:menu>
+        
         <mb3:menu unreferencedActions="true">
             <mb3:named>Other</mb3:named>
         </mb3:menu>
diff --git 
a/example/application/simpleapp/module-spring/src/main/java/domainapp/modules/spring/SpringDataJPADemoHandler.java
 
b/example/application/simpleapp/module-spring/src/main/java/domainapp/modules/spring/SpringDataJPADemoHandler.java
new file mode 100644
index 0000000..f2a0cdd
--- /dev/null
+++ 
b/example/application/simpleapp/module-spring/src/main/java/domainapp/modules/spring/SpringDataJPADemoHandler.java
@@ -0,0 +1,100 @@
+package domainapp.modules.spring;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.util.UUID;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.persistence.Entity;
+import javax.persistence.EntityManager;
+
+import org.apache.isis.commons.internal._Constants;
+import org.apache.isis.commons.internal.cdi._CDI;
+import org.apache.isis.commons.internal.debug._Probe;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.uri._URI;
+import org.apache.isis.commons.internal.uri._URI.ContainerType;
+import org.apache.isis.commons.internal.uri._URI.ContextType;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObject.SimpleManagedObject;
+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.contextmanger.ContextHandler;
+import org.springframework.context.ApplicationContext;
+
+import domainapp.modules.spring.dom.customer.Customer;
+import lombok.val;
+
+@Singleton
+public class SpringDataJPADemoHandler implements ContextHandler {
+       
+       private final static _Probe probe = 
_Probe.unlimited().label("SpringDataJPADemoHandler");
+       
+       @Inject ApplicationContext springContext;
+       @Inject SpecificationLoader specLoader;
+
+       @Override
+       public URI identifierOf(ManagedObject managedObject) {
+       try {
+                       return identifierForCustomer(managedObject.getPojo(), 
managedObject.getSpecification());
+               } catch (NoSuchMethodException | SecurityException | 
IllegalAccessException | IllegalArgumentException
+                               | InvocationTargetException e) {
+                       throw _Exceptions.unrecoverable(e);
+               }
+       }
+
+       @Override
+       public Instance<ManagedObject> resolve(ObjectSpecId specId, URI 
identifier) {
+               
+               // FIXME [2033] this is just a PoC
+               
+               long id = Long.parseLong(identifier.getQuery());
+               
+               val em = springContext.getBean(EntityManager.class);
+               
+               val customer = em.find(Customer.class, id);
+               val spec = specLoader.lookupBySpecId(specId);
+               
+               val managedObject = SimpleManagedObject.of(spec, customer);
+               
+               return _CDI.InstanceFactory.singleton(managedObject);
+       }
+
+       @Override
+       public boolean recognizes(URI uri) {
+               return uri.toString().startsWith("uoid://entities@spring");
+       }
+
+       @Override
+       public boolean recognizes(ObjectSpecification objSpec) {
+               // FIXME [2033] this is just a PoC
+               return 
objSpec.getCorrespondingClass().isAnnotationPresent(Entity.class);
+       }
+       
+       // -- HELPER
+       
+       private URI identifierForCustomer(Object pojo, ObjectSpecification 
spec) 
+               throws NoSuchMethodException, SecurityException, 
IllegalAccessException, 
+               IllegalArgumentException, InvocationTargetException {
+       
+       val idGetter = pojo.getClass().getMethod("getId", 
_Constants.emptyClasses);
+       final Long id = (Long)idGetter.invoke(pojo, _Constants.emptyObjects);
+       final String identifier = (id!=null && id>0) 
+                       ? "" + id
+                                       : UUID.randomUUID().toString();
+               
+               return _URI.uoidBuilder()
+                               .containerType(ContainerType.spring)
+                               .contextType(ContextType.entities)
+                               .contextId(null)
+                               .path("/"+spec.getSpecId().asString()+"/")
+                               .query(identifier)
+                               .build()
+                               .toURI();
+    }
+       
+
+}

Reply via email to