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 <ahu...@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