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

[isis] 03/03: ISIS-1976: improve the ObjectAdapterProvider interface (API)

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

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

commit 5a8b180a8337a1d9072f94623af1afa7888ce085
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Sep 5 20:41:07 2018 +0200

    ISIS-1976: improve the ObjectAdapterProvider interface (API)
    
    also prepare for removal of the OA by pojo lookup map
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1976
---
 .../metamodel/adapter/ObjectAdapterProvider.java   | 28 ++++++++--
 ...ObjectFacetDeclarativeInitializingAbstract.java |  3 +-
 .../adaptermanager/ObjectAdapterContext.java       | 64 ++++++++++++++--------
 .../ObjectAdapterContext_AdapterManager.java       | 30 ++++++++++
 ...ObjectAdapterContext_ObjectAdapterProvider.java | 11 +++-
 5 files changed, 103 insertions(+), 33 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapterProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/ObjectAdapterProvider.java
index e799f5d..fef5bf7 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
@@ -25,6 +25,7 @@ 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.ObjectSpecId;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 
 /**
@@ -56,12 +57,19 @@ public interface ObjectAdapterProvider {
             OneToManyAssociation collection);
 
     /**
-     * @param viewModelPojo
-     * @return an ObjectAdapter 'bypassing mapping', that holds the ObjectSpecification
-     * FIXME[ISIS-1976] Note: whether or not 'bypassing mapping' should not be exposed by the API.
-     * So this further needs refactoring. 
+     * Returns an ObjectAdapter that holds the ObjectSpecification used for 
+     * interrogating the domain object's metadata. 
+     * <p>
+     * Does _not_ perform dependency injection on the domain object. Also bypasses 
+     * caching (if any), that is each call to this method creates a new unique instance.
+     * </p>
+     * 
+     * @param viewModelPojo domain object
+     * @return  
      */
-    ObjectAdapter specificationForViewModel(final Object viewModelPojo);
+    ObjectAdapter disposableAdapterForViewModel(Object viewModelPojo);
+    
+    ObjectSpecification specificationForViewModel(Object viewModelPojo);
 
     ObjectAdapter adapterForViewModel(
             final Object viewModelPojo, 
@@ -97,7 +105,12 @@ public interface ObjectAdapterProvider {
         }
 
         @Programmatic
-        default ObjectAdapter specificationForViewModel(final Object viewModelPojo) {
+        default ObjectAdapter disposableAdapterForViewModel(final Object viewModelPojo) {
+            return getObjectAdapterProvider().disposableAdapterForViewModel(viewModelPojo);
+        }
+        
+        @Programmatic
+        default ObjectSpecification specificationForViewModel(Object viewModelPojo) {
             return getObjectAdapterProvider().specificationForViewModel(viewModelPojo);
         }
 
@@ -116,6 +129,9 @@ public interface ObjectAdapterProvider {
     }
 
 
+   
+
+
     
     
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java
index 2b47acd..97cc65e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java
@@ -21,6 +21,7 @@ package org.apache.isis.core.metamodel.facets.object.recreatable;
 
 import java.util.List;
 import java.util.Set;
+import java.util.UUID;
 
 import org.apache.isis.applib.services.urlencoding.UrlEncodingService;
 import org.apache.isis.commons.internal.memento._Mementos;
@@ -97,7 +98,7 @@ extends RecreatableObjectFacetAbstract {
 
         final _Mementos.Memento memento = _Mementos.create(codec, serializer);
 
-        final ObjectAdapter ownerAdapter = adapterProvider.specificationForViewModel(viewModelPojo);
+        final ObjectAdapter ownerAdapter = adapterProvider.disposableAdapterForViewModel(viewModelPojo);
         final ObjectSpecification spec = ownerAdapter.getSpecification();
         
         final List<OneToOneAssociation> properties = spec.getProperties(Contributed.EXCLUDED);
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 a9535a6..5ebfe1f 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
@@ -19,13 +19,16 @@
 package org.apache.isis.core.runtime.system.persistence.adaptermanager;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.UUID;
 import java.util.function.Function;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.isis.commons.internal.functions._Predicates;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.ensure.Ensure;
 import org.apache.isis.core.commons.ensure.IsisAssertException;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapterProvider;
@@ -66,6 +69,7 @@ public class ObjectAdapterContext {
     
     private final PojoAdapterHashMap pojoAdapterMap = new PojoAdapterHashMap();
     private final OidAdapterHashMap oidAdapterMap = new OidAdapterHashMap();
+    private final OidAdapterHashMap oidAdapterMap2 = new OidAdapterHashMap();
     private final PersistenceSession persistenceSession; 
     private final ServicesInjector servicesInjector;
     private final SpecificationLoader specificationLoader;
@@ -100,6 +104,7 @@ public class ObjectAdapterContext {
     public void open() {
         oidAdapterMap.open();
         pojoAdapterMap.open();
+        oidAdapterMap2.open();
         initServices();
     }
     
@@ -107,6 +112,7 @@ public class ObjectAdapterContext {
         
         try {
             oidAdapterMap.close();
+            oidAdapterMap2.close();
         } catch(final Throwable ex) {
             // ignore
             LOG.error("close: oidAdapterMap#close() failed; continuing to avoid memory leakage");
@@ -120,22 +126,45 @@ public class ObjectAdapterContext {
         }
     }
     
-    // -- CACHING
+    // -- CACHING DEPR.
 
     @Deprecated // don't expose caching
     protected ObjectAdapter lookupAdapterByPojo(Object pojo) {
-        return pojoAdapterMap.getAdapter(pojo);
+        final ObjectAdapter adapter = pojoAdapterMap.getAdapter(pojo);
+        if(adapter!=null) {
+            Oid y = adapter.getOid();
+            Objects.requireNonNull(y);
+            
+            Oid x = objectAdapterProviderMixin.oidFor(pojo);
+            Objects.requireNonNull(x);
+            
+            //FIXME[ISIS-1976] oids must match
+            //Ensure.ensureThatArg(x, _Predicates.equalTo(y), ()->String.format("x: %s\ny: %s", ""+x, ""+y));
+        }
+        return adapter;
     }
     
     private void putPojo(Object pojo, ObjectAdapter adapter) {
+        
+        Oid x = objectAdapterProviderMixin.oidFor(pojo);
+        Oid y = adapter.getOid();
+        Objects.requireNonNull(y);
+        
+        //FIXME[ISIS-1976] oids must match
+        //Ensure.ensureThatArg(x, _Predicates.equalTo(y), ()->String.format("x: %s\ny: %s", ""+x, ""+y));
+        
+        oidAdapterMap2.add(adapter.getOid(), adapter);
         pojoAdapterMap.add(adapter.getObject(), adapter);
     }
     
     private void removePojo(ObjectAdapter adapter) {
+        Oid y = adapter.getOid();
+        Objects.requireNonNull(y);
+        oidAdapterMap2.remove(y);
         pojoAdapterMap.remove(adapter);
     }
     
-    // --
+    // -- CACHING
     
     @Deprecated // don't expose caching
     public boolean containsAdapterForPojo(Object pojo) {
@@ -315,28 +344,15 @@ public class ObjectAdapterContext {
         oidAdapterMap.add(adapter.getOid(), adapter);
     }
     
-    public ObjectAdapter specificationForViewModel(Object viewModelPojo) {
-        //FIXME[ISIS-1976]
-        // this is horrible, but there's a catch-22 here...
-        // we need an adapter in order to query the state of the object via the metamodel, on the other hand
-        // we can't create an adapter without the identifier, which is what we're trying to derive
-        // so... we create a temporary transient adapter, use it to wrap this adapter and interrogate this pojo,
-        // then throw away that adapter (remove from the adapter map)
-        final boolean[] createdTemporaryAdapter = {false};
-        final ObjectAdapter viewModelAdapter = adapterForViewModel(
-                viewModelPojo, 
-                (ObjectSpecId objectSpecId)->{
-                    createdTemporaryAdapter[0] = true;
-                    return RootOid.create(objectSpecId, UUID.randomUUID().toString()); });
-    
-        //final ObjectSpecification spec = viewModelAdapter.getSpecification();
-        
-        if(createdTemporaryAdapter[0]) {
-            adapterManagerMixin.removeAdapterFromCache(viewModelAdapter);
-        }
-        return viewModelAdapter;
+    public ObjectAdapter disposableAdapterForViewModel(Object viewModelPojo) {
+            final ObjectSpecification objectSpecification = 
+                    specificationLoader.loadSpecification(viewModelPojo.getClass());
+            final ObjectSpecId objectSpecId = objectSpecification.getSpecId();
+            final RootOid newRootOid = RootOid.create(objectSpecId, UUID.randomUUID().toString());
+            final ObjectAdapter createdAdapter = adapterManagerMixin.createRootOrAggregatedAdapter(newRootOid, viewModelPojo);
+            return createdAdapter;
     }
-
+    
     public ObjectAdapter adapterForViewModel(Object viewModelPojo, Function<ObjectSpecId, RootOid> rootOidFactory) {
         ObjectAdapter viewModelAdapter = adapterManagerMixin.lookupAdapterFor(viewModelPojo);
         if(viewModelAdapter == null) {
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_AdapterManager.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_AdapterManager.java
index f88f5f8..e60d247 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_AdapterManager.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_AdapterManager.java
@@ -178,6 +178,36 @@ class ObjectAdapterContext_AdapterManager {
         return adapter;
     }
     
+    ObjectAdapter injectServices(final ObjectAdapter adapter) {
+        // since the whole point of this method is to map an adapter that's just been created.
+        // so we *don't* call ensureMapsConsistent(adapter);
+
+        Assert.assertNotNull(adapter);
+        final Object pojo = adapter.getObject();
+
+        if (LOG.isDebugEnabled()) {
+            // don't interact with the underlying object because may be a ghost
+            // and would trigger a resolve
+            // don't call toString() on adapter because calls hashCode on
+            // underlying object, may also trigger a resolve.
+            LOG.debug("adding identity for adapter with oid={}", adapter.getOid());
+        }
+
+        // value adapters are not mapped (but all others - root and aggregated adapters - are)
+        if (adapter.isValue()) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("not mapping value adapter");
+            }
+            servicesInjector.injectServicesInto(pojo);
+            return adapter;
+        }
+
+        // must inject after mapping, otherwise infinite loop
+        servicesInjector.injectServicesInto(pojo);
+
+        return adapter;
+    }
+    
     ObjectAdapter createRootOrAggregatedAdapter(final Oid oid, final Object pojo) {
         final ObjectAdapter createdAdapter;
         if(oid instanceof RootOid) {
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 ba820e3..77545ab 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
@@ -116,8 +116,15 @@ class ObjectAdapterContext_ObjectAdapterProvider implements ObjectAdapterProvide
     }
 
     @Override
-    public ObjectAdapter specificationForViewModel(Object viewModelPojo) {
-        return objectAdapterContext.specificationForViewModel(viewModelPojo);
+    public ObjectSpecification specificationForViewModel(Object viewModelPojo) {
+        final ObjectSpecification objectSpecification = 
+                specificationLoader.loadSpecification(viewModelPojo.getClass());
+        return objectSpecification;
+    }
+    
+    @Override
+    public ObjectAdapter disposableAdapterForViewModel(Object viewModelPojo) {
+        return objectAdapterContext.disposableAdapterForViewModel(viewModelPojo);
     }
 
     @Override