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/10/01 10:53:35 UTC

[isis] 01/02: ISIS-1976: Improve the service lookup API (streams instead of collections)

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

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

commit dbfc2b56d76d9f32c6c55af9831eea418c190903
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Oct 1 09:55:58 2018 +0200

    ISIS-1976: Improve the service lookup API (streams instead of
    collections)
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1976
---
 .../metamodel/adapter/ObjectAdapterProvider.java   | 17 ++++--
 .../isis/core/metamodel/services/ServiceUtil.java  |  2 +
 .../homepage/HomePageProviderServiceDefault.java   | 25 +++++---
 .../menubars/bootstrap3/MenuBarsServiceBS3.java    | 66 +++++++++++-----------
 .../menubars/bootstrap3/ServiceAndAction.java      |  6 +-
 ...ObjectAdapterContext_ObjectAdapterProvider.java | 24 +++++---
 .../restfulobjects/rendering/ReprRenderer.java     |  1 -
 .../rendering/ReprRendererAbstract.java            |  7 ++-
 .../domainobjects/ActionResultReprRenderer.java    |  6 +-
 .../rendering/domainobjects/ListReprRenderer.java  | 28 +++++----
 .../domainobjects/ObjectActionReprRenderer.java    | 14 ++---
 .../restfulobjects/server/ResourceContext.java     |  8 +--
 .../resources/DomainServiceResourceServerside.java | 23 ++------
 .../resources/DomainServicesListReprRenderer.java  |  2 +-
 .../server/resources/HomePageReprRenderer.java     |  6 +-
 .../server/resources/ResourceAbstract.java         | 12 +---
 .../wicket/model/models/ServiceActionsModel.java   | 11 ++--
 .../serviceactions/ServiceActionUtil.java          | 30 +++++-----
 .../isis/viewer/wicket/ui/pages/home/HomePage.java | 19 +++----
 19 files changed, 159 insertions(+), 148 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 452fd18..4d80ecb 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
@@ -20,7 +20,7 @@ package org.apache.isis.core.metamodel.adapter;
 
 import static org.apache.isis.commons.internal.base._With.mapIfPresentElse;
 
-import java.util.List;
+import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
@@ -101,7 +101,8 @@ public interface ObjectAdapterProvider {
     
     // -- SERVICE LOOKUP 
     
-    List<ObjectAdapter> getServices();
+    Stream<ObjectAdapter> streamServices();
+    ObjectAdapter lookupService(String serviceId);
     
     
     // -- FOR THOSE THAT IMPLEMENT THROUGH DELEGATION
@@ -150,11 +151,19 @@ public interface ObjectAdapterProvider {
         }
         
         @Programmatic
-        default List<ObjectAdapter> getServices() {
-            return getObjectAdapterProvider().getServices();
+        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/services/ServiceUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServiceUtil.java
index 0f8f0ae..54a8745 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServiceUtil.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServiceUtil.java
@@ -58,6 +58,8 @@ public final class ServiceUtil {
             return fqcnOf(serviceClass);
         }
     }
+    
+    // -- HELPER
 
     private static String serviceTypeOf(final Class<?> serviceClass) {
         final String serviceType;
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/homepage/HomePageProviderServiceDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/homepage/HomePageProviderServiceDefault.java
index 082d03b..f2f0a2e 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/homepage/HomePageProviderServiceDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/homepage/HomePageProviderServiceDefault.java
@@ -18,7 +18,6 @@
  */
 package org.apache.isis.core.runtime.services.homepage;
 
-import java.util.List;
 import java.util.Optional;
 import java.util.stream.Stream;
 
@@ -30,6 +29,7 @@ import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.services.homepage.HomePageProviderService;
+import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.consent.Consent;
@@ -53,8 +53,15 @@ public class HomePageProviderServiceDefault implements HomePageProviderService {
     @Programmatic
     @Override
     public Object homePage() {
-        final List<ObjectAdapter> serviceAdapters = getPersistenceSession().getServices();
-        for (final ObjectAdapter serviceAdapter : serviceAdapters) {
+        return homePage.get();
+    }
+    
+    private final _Lazy<Object> homePage = _Lazy.of(this::lookupHomePage);
+
+    private Object lookupHomePage() {
+        final Stream<ObjectAdapter> serviceAdapters = getPersistenceSession().streamServices();
+        
+        return serviceAdapters.map(serviceAdapter->{
             final ObjectSpecification serviceSpec = serviceAdapter.getSpecification();
             final Stream<ObjectAction> objectActions = serviceSpec.streamObjectActions(Contributed.EXCLUDED);
             
@@ -63,12 +70,12 @@ public class HomePageProviderServiceDefault implements HomePageProviderService {
             .filter(_NullSafe::isPresent)
             .findAny();
             
-            if(homePage.isPresent()) {
-                return homePage.get();
-            }
-            
-        }
-        return null;
+            return homePage;
+        })
+        .filter(Optional::isPresent)
+        .map(Optional::get)
+        .findAny()
+        .orElse(null);
     }
 
     protected Object homePageIfUsable(ObjectAdapter serviceAdapter, ObjectAction objectAction) {
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/menubars/bootstrap3/MenuBarsServiceBS3.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/menubars/bootstrap3/MenuBarsServiceBS3.java
index 942c3b9..7f2962b 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/menubars/bootstrap3/MenuBarsServiceBS3.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/menubars/bootstrap3/MenuBarsServiceBS3.java
@@ -57,6 +57,7 @@ import org.apache.isis.core.metamodel.facets.object.domainservice.DomainServiceF
 import org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFacet;
 import org.apache.isis.core.metamodel.services.grid.GridServiceDefault;
 import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.Contributed;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -179,31 +180,30 @@ public class MenuBarsServiceBS3 implements MenuBarsService {
     private BS3MenuBars deriveMenuBarsFromMetaModelFacets() {
         final BS3MenuBars menuBars = new BS3MenuBars();
 
-        final List<ObjectAdapter> serviceAdapters =
-                isisSessionFactory.getCurrentSession().getPersistenceSession().getServices();
+        final Stream<ObjectAdapter> serviceAdapters =
+                isisSessionFactory.getCurrentSession().getPersistenceSession().streamServices();
 
-        final List<ObjectAdapter> visibleServiceAdapters =
-                _Lists.filter(serviceAdapters,
-                (final ObjectAdapter objectAdapter) -> {
-                        if (objectAdapter == null) {
-                            return false;
-                        }
-                        if (objectAdapter.getSpecification() == null) {
-                            return false;
-                        }
-                        final ObjectSpecification spec = objectAdapter.getSpecification();
-                        if (spec.isHidden()) {
-                            // however, this isn't the same as HiddenObjectFacet, so doesn't filter out
-                            // services that have an imperative hidden() method.
-                            return false;
-                        }
-                        final DomainServiceFacet facet = spec.getFacet(DomainServiceFacet.class);
-                        if (facet == null) {
-                            return true;
-                        }
-                        final NatureOfService natureOfService = facet.getNatureOfService();
-                        return natureOfService == null || natureOfService != NatureOfService.DOMAIN;
-                });
+        final List<ManagedObject> visibleServiceAdapters = serviceAdapters.filter(objectAdapter -> {
+            if (objectAdapter == null) {
+                return false;
+            }
+            if (objectAdapter.getSpecification() == null) {
+                return false;
+            }
+            final ObjectSpecification spec = objectAdapter.getSpecification();
+            if (spec.isHidden()) {
+                // however, this isn't the same as HiddenObjectFacet, so doesn't filter out
+                // services that have an imperative hidden() method.
+                return false;
+            }
+            final DomainServiceFacet facet = spec.getFacet(DomainServiceFacet.class);
+            if (facet == null) {
+                return true;
+            }
+            final NatureOfService natureOfService = facet.getNatureOfService();
+            return natureOfService == null || natureOfService != NatureOfService.DOMAIN;
+        })
+        .collect(Collectors.toList());
 
         append(visibleServiceAdapters, menuBars.getPrimary(), DomainServiceLayout.MenuBar.PRIMARY);
         append(visibleServiceAdapters, menuBars.getSecondary(), DomainServiceLayout.MenuBar.SECONDARY);
@@ -221,14 +221,14 @@ public class MenuBarsServiceBS3 implements MenuBarsService {
 
 
     private void append(
-            final List<ObjectAdapter> serviceAdapters,
+            final List<ManagedObject> serviceAdapters,
             final BS3MenuBar menuBar,
             final DomainServiceLayout.MenuBar menuBarPos) {
 
         List<ServiceAndAction> serviceActions = _Lists.newArrayList();
 
         // cf ServiceActionsModel & ServiceActionUtil#buildMenu in Wicket viewer
-        for (final ObjectAdapter serviceAdapter : _Lists.filter(serviceAdapters, with(menuBarPos))) {
+        for (final ManagedObject serviceAdapter : _Lists.filter(serviceAdapters, with(menuBarPos))) {
             collateServiceActions(serviceAdapter, ActionType.USER, serviceActions);
             collateServiceActions(serviceAdapter, ActionType.PROTOTYPE, serviceActions);
         }
@@ -282,12 +282,12 @@ public class MenuBarsServiceBS3 implements MenuBarsService {
      * straight copy from Wicket UI
      */
     private static Set<String> serviceNamesInOrder(
-            final List<ObjectAdapter> serviceAdapters,
+            final List<ManagedObject> serviceAdapters,
             final List<ServiceAndAction> serviceActions) {
         final Set<String> serviceNameOrder = _Sets.newLinkedHashSet();
 
         // first, order as defined in isis.properties
-        for (ObjectAdapter serviceAdapter : serviceAdapters) {
+        for (ManagedObject serviceAdapter : serviceAdapters) {
             final ObjectSpecification serviceSpec = serviceAdapter.getSpecification();
             String serviceName = serviceSpec.getFacet(NamedFacet.class).value();
             serviceNameOrder.add(serviceName);
@@ -311,12 +311,12 @@ public class MenuBarsServiceBS3 implements MenuBarsService {
         final Map<String, List<ServiceAndAction>> serviceActionsByName = _Maps.newTreeMap();
 
         // map available services
-        ObjectAdapter lastServiceAdapter = null;
+        ManagedObject lastServiceAdapter = null;
 
         for (ServiceAndAction serviceAction : serviceActions) {
             List<ServiceAndAction> serviceActionsForName = serviceActionsByName.get(serviceAction.serviceName);
 
-            final ObjectAdapter serviceAdapter = serviceAction.serviceAdapter;
+            final ManagedObject serviceAdapter = serviceAction.serviceAdapter;
 
             if(serviceActionsForName == null) {
                 serviceActionsForName = _Lists.newArrayList();
@@ -334,7 +334,7 @@ public class MenuBarsServiceBS3 implements MenuBarsService {
 
 
     private void collateServiceActions(
-            final ObjectAdapter serviceAdapter,
+            final ManagedObject serviceAdapter,
             final ActionType actionType,
             final List<ServiceAndAction> serviceActions) {
         final ObjectSpecification serviceSpec = serviceAdapter.getSpecification();
@@ -366,8 +366,8 @@ public class MenuBarsServiceBS3 implements MenuBarsService {
        
     }
 
-    private static Predicate<ObjectAdapter> with(final DomainServiceLayout.MenuBar menuBar) {
-        return (ObjectAdapter input) -> {
+    private static Predicate<ManagedObject> with(final DomainServiceLayout.MenuBar menuBar) {
+        return (ManagedObject input) -> {
                 final DomainServiceLayoutFacet facet =
                         input.getSpecification().getFacet(DomainServiceLayoutFacet.class);
                 return facet != null && facet.getMenuBar() == menuBar;
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/menubars/bootstrap3/ServiceAndAction.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/menubars/bootstrap3/ServiceAndAction.java
index 4524da9..ffe37ea 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/menubars/bootstrap3/ServiceAndAction.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/menubars/bootstrap3/ServiceAndAction.java
@@ -18,19 +18,19 @@
  */
 package org.apache.isis.core.runtime.services.menubars.bootstrap3;
 
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 
 class ServiceAndAction {
     final String serviceName;
-    final ObjectAdapter serviceAdapter;
+    final ManagedObject serviceAdapter;
     final ObjectAction objectAction;
 
     public boolean separator;
 
     ServiceAndAction(
             final String serviceName,
-            final ObjectAdapter serviceAdapter,
+            final ManagedObject serviceAdapter,
             final ObjectAction objectAction) {
         this.serviceName = serviceName;
         this.serviceAdapter = serviceAdapter;
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 50505bf..a982773 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterProvider.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/adaptermanager/ObjectAdapterContext_ObjectAdapterProvider.java
@@ -20,8 +20,10 @@ package org.apache.isis.core.runtime.system.persistence.adaptermanager;
 
 import static org.apache.isis.commons.internal.base._With.requires;
 
-import java.util.List;
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -31,6 +33,7 @@ import org.apache.isis.core.commons.ensure.Assert;
 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.services.ServiceUtil;
 import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -131,21 +134,28 @@ class ObjectAdapterContext_ObjectAdapterProvider implements ObjectAdapterProvide
     // -- SERVICE SUPPORT
     
     @Override
-    public List<ObjectAdapter> getServices() {
-        return serviceAdapters.get();
+    public Stream<ObjectAdapter> streamServices() {
+        return serviceAdapters.get().values().stream();
     }
     
+    @Override
+    public ObjectAdapter lookupService(final String serviceId) {
+        return serviceAdapters.get().get(serviceId);
+    }
+    
+    
     // -- HELPER
     
-    private final _Lazy<List<ObjectAdapter>> serviceAdapters = _Lazy.of(this::initServiceAdapters);
+    private final _Lazy<Map<String, ObjectAdapter>> serviceAdapters = _Lazy.of(this::initServiceAdapters);
     
-    private List<ObjectAdapter> initServiceAdapters() {
+    private Map<String, ObjectAdapter> initServiceAdapters() {
+        
         return servicesInjector.streamRegisteredServiceInstances()
-        .map(this::adapterFor)
+        .map(this::adapterFor) 
         .peek(serviceAdapter->{
             Assert.assertFalse("expected to not be 'transient'", serviceAdapter.getOid().isTransient());
         })
-        .collect(Collectors.toList());
+        .collect(Collectors.toMap(a->ServiceUtil.id(a.getPojo()), v->v, (o,n)->n, LinkedHashMap::new));
     }
     
    
diff --git a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRenderer.java b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRenderer.java
index d0633ad..b1685ad 100644
--- a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRenderer.java
+++ b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRenderer.java
@@ -21,7 +21,6 @@ package org.apache.isis.viewer.restfulobjects.rendering;
 import javax.ws.rs.core.MediaType;
 
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
-import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
 
 public interface ReprRenderer<R extends ReprRenderer<R, T>, T> {
 
diff --git a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRendererAbstract.java b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRendererAbstract.java
index 7438e7b..a07b021 100644
--- a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRendererAbstract.java
+++ b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/ReprRendererAbstract.java
@@ -20,12 +20,13 @@ package org.apache.isis.viewer.restfulobjects.rendering;
 
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Stream;
 
 import javax.ws.rs.core.MediaType;
 
-import org.apache.isis.commons.internal.collections._Lists;
 import com.google.common.collect.Maps;
 
+import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
@@ -223,8 +224,8 @@ public abstract class ReprRendererAbstract<R extends ReprRendererAbstract<R, T>,
         }
     }
 
-    protected List<ObjectAdapter> getServiceAdapters() {
-        return rendererContext.getPersistenceSession().getServices();
+    protected Stream<ObjectAdapter> streamServiceAdapters() {
+        return rendererContext.getPersistenceSession().streamServices();
     }
 
 }
diff --git a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ActionResultReprRenderer.java b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ActionResultReprRenderer.java
index 435c2cb..b34f15f 100644
--- a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ActionResultReprRenderer.java
+++ b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ActionResultReprRenderer.java
@@ -16,8 +16,8 @@
  */
 package org.apache.isis.viewer.restfulobjects.rendering.domainobjects;
 
-import java.util.Collection;
 import java.util.Map;
+import java.util.stream.Stream;
 
 import com.fasterxml.jackson.databind.node.NullNode;
 
@@ -135,8 +135,8 @@ public class ActionResultReprRenderer extends ReprRendererAbstract<ActionResultR
 
         case LIST:
 
-            final Collection<ObjectAdapter> collectionAdapters =
-                CollectionFacet.Utils.toAdapterList(returnedAdapter);
+            final Stream<ObjectAdapter> collectionAdapters =
+                CollectionFacet.Utils.streamAdapters(returnedAdapter);
             
             final ListReprRenderer listReprRenderer =
                     new ListReprRenderer(rendererContext, null, representation).withElementRel(Rel.ELEMENT);
diff --git a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java
index 272743b..83eba8f 100644
--- a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java
+++ b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java
@@ -16,7 +16,9 @@
  */
 package org.apache.isis.viewer.restfulobjects.rendering.domainobjects;
 
-import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -27,10 +29,10 @@ import org.apache.isis.viewer.restfulobjects.rendering.LinkFollowSpecs;
 import org.apache.isis.viewer.restfulobjects.rendering.RendererContext;
 import org.apache.isis.viewer.restfulobjects.rendering.ReprRendererAbstract;
 
-public class ListReprRenderer extends ReprRendererAbstract<ListReprRenderer, Collection<ObjectAdapter>> {
+public class ListReprRenderer extends ReprRendererAbstract<ListReprRenderer, Stream<ObjectAdapter>> {
 
     private ObjectAdapterLinkTo linkTo;
-    private Collection<ObjectAdapter> objectAdapters;
+    private List<ObjectAdapter> objectAdapters;
     private ObjectSpecification elementType;
     private ObjectSpecification returnType;
     private Rel elementRel;
@@ -46,8 +48,12 @@ public class ListReprRenderer extends ReprRendererAbstract<ListReprRenderer, Col
     }
 
     @Override
-    public ListReprRenderer with(final Collection<ObjectAdapter> objectAdapters) {
-        this.objectAdapters = objectAdapters;
+    public ListReprRenderer with(final Stream<ObjectAdapter> objectAdapters) {
+        this.objectAdapters = objectAdapters!=null 
+                ? objectAdapters
+                .filter(adapter->!adapter.getSpecification().isHidden())
+                .collect(Collectors.toList())
+                    : null;
         return this;
     }
 
@@ -90,11 +96,8 @@ public class ListReprRenderer extends ReprRendererAbstract<ListReprRenderer, Col
 
         final JsonRepresentation values = JsonRepresentation.newArray();
 
-        for (final ObjectAdapter adapter : objectAdapters) {
-            final ObjectSpecification specification = adapter.getSpecification();
-            if (specification.isHidden()) {
-                continue;
-            }
+        objectAdapters
+        .forEach(adapter->{
             final JsonRepresentation linkToObject = linkTo.with(adapter).builder(elementRel).build();
             values.arrayAdd(linkToObject);
 
@@ -104,8 +107,9 @@ public class ListReprRenderer extends ReprRendererAbstract<ListReprRenderer, Col
                         );
                 final JsonRepresentation domainObject = renderer.with(adapter).render();
                 linkToObject.mapPut("value", domainObject);
-            }
-        }
+            }            
+        });
+        
         representation.mapPut("value", values);
     }
 
diff --git a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
index 9b21a16..a4b7317 100644
--- a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
+++ b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
@@ -18,6 +18,7 @@ package org.apache.isis.viewer.restfulobjects.rendering.domainobjects;
 
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Stream;
 
 import com.fasterxml.jackson.databind.node.NullNode;
 import org.apache.isis.commons.internal.collections._Lists;
@@ -108,14 +109,11 @@ public class ObjectActionReprRenderer extends AbstractObjectMemberReprRenderer<O
 
     private ObjectAdapter contributingServiceAdapter() {
         final ObjectSpecification serviceType = objectMember.getOnType();
-        final List<ObjectAdapter> serviceAdapters = getServiceAdapters();
-        for (final ObjectAdapter serviceAdapter : serviceAdapters) {
-            if (serviceAdapter.getSpecification() == serviceType) {
-                return serviceAdapter;
-            }
-        }
-        // fail fast
-        throw new IllegalStateException("Unable to locate contributing service");
+        final Stream<ObjectAdapter> serviceAdapters = streamServiceAdapters();
+        return serviceAdapters
+                .filter(serviceAdapter->serviceAdapter.getSpecification() == serviceType)
+                .findFirst()
+                .orElseThrow(()->new IllegalStateException("Unable to locate contributing service")); // fail fast
     }
 
     @Override
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ResourceContext.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ResourceContext.java
index a8e772b..3efb193 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ResourceContext.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/ResourceContext.java
@@ -22,6 +22,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Stream;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -32,10 +33,9 @@ import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.core.UriInfo;
 import javax.ws.rs.ext.Providers;
 
+import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Sets;
-
-import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.config.IsisConfiguration;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -277,8 +277,8 @@ public class ResourceContext implements RendererContext6 {
         return persistenceSession;
     }
 
-    public List<ObjectAdapter> getServiceAdapters() {
-        return persistenceSession.getServices();
+    public Stream<ObjectAdapter> streamServiceAdapters() {
+        return persistenceSession.streamServices();
     }
 
     @Override
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServiceResourceServerside.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServiceResourceServerside.java
index b770685..aa31ea3 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServiceResourceServerside.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServiceResourceServerside.java
@@ -17,7 +17,8 @@
 package org.apache.isis.viewer.restfulobjects.server.resources;
 
 import java.io.InputStream;
-import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
@@ -49,16 +50,10 @@ import org.apache.isis.viewer.restfulobjects.rendering.domainobjects.DomainObjec
 import org.apache.isis.viewer.restfulobjects.rendering.domainobjects.DomainServiceLinkTo;
 import org.apache.isis.viewer.restfulobjects.rendering.service.RepresentationService;
 
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import org.apache.isis.commons.internal.collections._Lists;
-
 @Path("/services")
 public class DomainServiceResourceServerside extends ResourceAbstract implements DomainServiceResource {
 
-    private final static Predicate<ObjectAdapter> NATURE_OF_MENU = new Predicate<ObjectAdapter>() {
-        @Override
-        public boolean apply(final ObjectAdapter input) {
+    private final static Predicate<ObjectAdapter> NATURE_OF_MENU = (final ObjectAdapter input) -> {
             final ObjectSpecification specification = input.getSpecification();
             final DomainServiceFacet facet = specification.getFacet(DomainServiceFacet.class);
             if (facet == null) {
@@ -69,7 +64,6 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
             return  natureOfService == NatureOfService.VIEW ||
                     natureOfService == NatureOfService.VIEW_MENU_ONLY ||
                     natureOfService == NatureOfService.VIEW_REST_ONLY;
-        }
     };
 
     @Override
@@ -79,10 +73,8 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
     public Response services() {
         init(RepresentationType.LIST, Where.STANDALONE_TABLES, RepresentationService.Intent.NOT_APPLICABLE);
 
-        final List<ObjectAdapter> serviceAdapters =
-                _Lists.newArrayList(
-                        Iterables.filter(
-                                getResourceContext().getServiceAdapters(), NATURE_OF_MENU));
+        final Stream<ObjectAdapter> serviceAdapters = getResourceContext().streamServiceAdapters()
+                .filter(NATURE_OF_MENU);
 
         final DomainServicesListReprRenderer renderer = new DomainServicesListReprRenderer(getResourceContext(), null, JsonRepresentation.newMap());
         renderer.usingLinkToBuilder(new DomainServiceLinkTo())
@@ -118,7 +110,6 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
         MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_OBJECT, RestfulMediaType.APPLICATION_JSON_ERROR,
         MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_OBJECT, RestfulMediaType.APPLICATION_XML_ERROR
     })
-    //TODO proprietary @PrettyPrinting
     public Response service(@PathParam("serviceId") final String serviceId) {
         init(RepresentationType.DOMAIN_OBJECT, Where.OBJECT_FORMS, RepresentationService.Intent.ALREADY_PERSISTENT);
 
@@ -159,7 +150,6 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
         MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_OBJECT_ACTION, RestfulMediaType.APPLICATION_JSON_ERROR,
         MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_OBJECT_ACTION, RestfulMediaType.APPLICATION_XML_ERROR
     })
-    //TODO proprietary @PrettyPrinting
     public Response actionPrompt(@PathParam("serviceId") final String serviceId, @PathParam("actionId") final String actionId) {
         init(RepresentationType.OBJECT_ACTION, Where.OBJECT_FORMS, RepresentationService.Intent.ALREADY_PERSISTENT);
 
@@ -195,7 +185,6 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
         MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_ACTION_RESULT, RestfulMediaType.APPLICATION_JSON_ERROR,
         MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_ACTION_RESULT, RestfulMediaType.APPLICATION_XML_ERROR
     })
-    //TODO proprietary @PrettyPrinting
     public Response invokeActionQueryOnly(
             final @PathParam("serviceId") String serviceId,
             final @PathParam("actionId") String actionId,
@@ -224,7 +213,6 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
         MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_ACTION_RESULT, RestfulMediaType.APPLICATION_JSON_ERROR,
         MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_ACTION_RESULT, RestfulMediaType.APPLICATION_XML_ERROR
     })
-    //TODO proprietary @PrettyPrinting
     public Response invokeActionIdempotent(
             final @PathParam("serviceId") String serviceId,
             final @PathParam("actionId") String actionId,
@@ -249,7 +237,6 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
         MediaType.APPLICATION_JSON, RestfulMediaType.APPLICATION_JSON_ACTION_RESULT, RestfulMediaType.APPLICATION_JSON_ERROR,
         MediaType.APPLICATION_XML, RestfulMediaType.APPLICATION_XML_ACTION_RESULT, RestfulMediaType.APPLICATION_XML_ERROR
     })
-    //TODO proprietary @PrettyPrinting
     public Response invokeAction(@PathParam("serviceId") final String serviceId, @PathParam("actionId") final String actionId, final InputStream body) {
         init(RepresentationType.ACTION_RESULT, Where.STANDALONE_TABLES, RepresentationService.Intent.NOT_APPLICABLE, body);
 
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServicesListReprRenderer.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServicesListReprRenderer.java
index 97cade1..7f56432 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServicesListReprRenderer.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainServicesListReprRenderer.java
@@ -49,7 +49,7 @@ public class DomainServicesListReprRenderer extends ListReprRenderer {
         final LinkFollowSpecs linkFollower = getLinkFollowSpecs().follow("links");
         if (linkFollower.matches(link)) {
             final DomainServicesListReprRenderer renderer = new DomainServicesListReprRenderer(getRendererContext(), linkFollower, JsonRepresentation.newMap());
-            renderer.with(getServiceAdapters());
+            renderer.with(streamServiceAdapters());
             link.mapPut("value", renderer.render());
         }
 
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/HomePageReprRenderer.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/HomePageReprRenderer.java
index 099b121..e8fc769 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/HomePageReprRenderer.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/HomePageReprRenderer.java
@@ -19,7 +19,7 @@
 package org.apache.isis.viewer.restfulobjects.server.resources;
 
 import java.util.Collection;
-import java.util.List;
+import java.util.stream.Stream;
 
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -57,7 +57,7 @@ public class HomePageReprRenderer extends ReprRendererAbstract<HomePageReprRende
 
         addLinkToUser(getRendererContext().getAuthenticationSession());
         addLinkToMenuBars();
-        addLinkToServices(getRendererContext().getPersistenceSession().getServices());
+        addLinkToServices(getRendererContext().getPersistenceSession().streamServices());
         addLinkToVersion();
         addLinkToDomainTypes(((ResourceContext)getRendererContext()).getSpecificationLoader().allSpecifications());
 
@@ -90,7 +90,7 @@ public class HomePageReprRenderer extends ReprRendererAbstract<HomePageReprRende
         getLinks().arrayAdd(link);
     }
 
-    private void addLinkToServices(List<ObjectAdapter> serviceAdapters) {
+    private void addLinkToServices(Stream<ObjectAdapter> serviceAdapters) {
 
         final JsonRepresentation link = LinkBuilder.newBuilder(getRendererContext(), Rel.SERVICES.getName(), RepresentationType.LIST, "services").build();
 
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/ResourceAbstract.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/ResourceAbstract.java
index d651be5..39c84a6 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/ResourceAbstract.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/ResourceAbstract.java
@@ -19,7 +19,6 @@
 package org.apache.isis.viewer.restfulobjects.server.resources;
 
 import java.io.InputStream;
-import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -39,7 +38,6 @@ import org.apache.isis.core.commons.url.UrlDecoderUtil;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
-import org.apache.isis.core.metamodel.services.ServiceUtil;
 import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.runtime.authentication.AuthenticationManager;
@@ -153,13 +151,9 @@ public abstract class ResourceAbstract {
     }
 
     protected ObjectAdapter getServiceAdapter(final String serviceId) {
-        final List<ObjectAdapter> serviceAdapters = getPersistenceSession().getServices();
-        for (final ObjectAdapter serviceAdapter : serviceAdapters) {
-            final Object servicePojo = serviceAdapter.getPojo();
-            final String id = ServiceUtil.id(servicePojo);
-            if (serviceId.equals(id)) {
-                return serviceAdapter;
-            }
+        final ObjectAdapter serviceAdapter = getPersistenceSession().lookupService(serviceId);
+        if(serviceAdapter!=null) {
+            return serviceAdapter;
         }
         throw RestfulObjectsApplicationException.createWithMessage(HttpStatusCode.NOT_FOUND, "Could not locate service '%s'", serviceId);
     }
diff --git a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ServiceActionsModel.java b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ServiceActionsModel.java
index d9b6d94..16a5ec4 100644
--- a/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ServiceActionsModel.java
+++ b/core/viewer-wicket-model/src/main/java/org/apache/isis/viewer/wicket/model/models/ServiceActionsModel.java
@@ -21,9 +21,10 @@ package org.apache.isis.viewer.wicket.model.models;
 
 import java.util.List;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.apache.isis.applib.annotation.DomainServiceLayout;
-import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFacet;
 /**
@@ -52,7 +53,9 @@ public class ServiceActionsModel extends ModelAbstract<List<ObjectAdapter>> {
 
     @Override
     protected List<ObjectAdapter> load() {
-        return _Lists.filter(getServiceAdapters(), with(menuBar));
+        return streamServiceAdapters()
+                .filter(with(menuBar))
+                .collect(Collectors.toList());
     }
 
     private static Predicate<ObjectAdapter> with(final DomainServiceLayout.MenuBar menuBar) {
@@ -64,8 +67,8 @@ public class ServiceActionsModel extends ModelAbstract<List<ObjectAdapter>> {
         };
     }
 
-    protected List<ObjectAdapter> getServiceAdapters() {
-        return getPersistenceSession().getServices();
+    protected Stream<ObjectAdapter> streamServiceAdapters() {
+        return getPersistenceSession().streamServices();
     }
 
 
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionUtil.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionUtil.java
index 03fb219..39ff33c 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionUtil.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/serviceactions/ServiceActionUtil.java
@@ -19,11 +19,11 @@
 
 package org.apache.isis.viewer.wicket.ui.components.actionmenu.serviceactions;
 
+import java.util.HashMap;
 import java.util.List;
-
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
@@ -40,7 +40,6 @@ import org.apache.isis.applib.layout.menubars.MenuBars;
 import org.apache.isis.applib.layout.menubars.MenuSection;
 import org.apache.isis.applib.layout.menubars.bootstrap3.BS3Menu;
 import org.apache.isis.applib.layout.menubars.bootstrap3.BS3MenuBar;
-import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Lists;
@@ -49,7 +48,6 @@ import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.runtime.system.SystemConstants;
 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.session.IsisSessionFactoryBuilder;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.model.models.ServiceActionsModel;
@@ -212,11 +210,12 @@ public final class ServiceActionUtil {
 
         // we no longer use ServiceActionsModel#getObject() because the model only holds the services for the
         // menuBar in question, whereas the "Other" menu may reference a service which is defined for some other menubar
-        final List<ObjectAdapter> serviceAdapters = IsisContext.getSessionFactory().getCurrentSession().getPersistenceSession().getServices();
-        final ImmutableMap<ObjectAdapter, String> oidByServiceAdapter = FluentIterable.from(serviceAdapters)
-                .toMap((final ObjectAdapter objectAdapter) -> objectAdapter.getOid().enStringNoVersion());
-        final ImmutableBiMap<String, ObjectAdapter> serviceAdapterByOid = ImmutableBiMap
-                .copyOf(oidByServiceAdapter).inverse();
+        final Stream<ObjectAdapter> serviceAdapters = 
+                IsisContext.getSessionFactory().getCurrentSession().getPersistenceSession().streamServices();
+
+        final Map<String, ObjectAdapter> serviceAdapterBySpecId = 
+                serviceAdapters
+                .collect(Collectors.toMap(a->a.getSpecification().getSpecId().asString(), a->a, (o,n)->n, HashMap::new));
 
         final List<CssMenuItem> menuItems = _Lists.newArrayList();
         for (final BS3Menu menu : menuBar.getMenus()) {
@@ -228,12 +227,11 @@ public final class ServiceActionUtil {
                 boolean firstSection = true;
 
                 for (final ServiceActionLayoutData actionLayoutData : menuSection.getServiceActions()) {
-                    final String objectType = actionLayoutData.getObjectType();
-                    final Bookmark bookmark = new Bookmark(objectType, PersistenceSession.SERVICE_IDENTIFIER);
-                    final String oid = bookmark.toString();
-                    final ObjectAdapter serviceAdapter = serviceAdapterByOid.get(oid);
+                    final String objectTypeLiteral = actionLayoutData.getObjectType();
+                    
+                    final ObjectAdapter serviceAdapter = serviceAdapterBySpecId.get(objectTypeLiteral);
                     if(serviceAdapter == null) {
-                        // service not recognised, presumably the menu layout is out of sync with actual configured modules
+                        // service not recognized, presumably the menu layout is out of sync with actual configured modules
                         continue;
                     }
                     final EntityModel entityModel = new EntityModel(serviceAdapter);
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/home/HomePage.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/home/HomePage.java
index e0f2c70..0174087 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/home/HomePage.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/home/HomePage.java
@@ -19,7 +19,6 @@
 
 package org.apache.isis.viewer.wicket.ui.pages.home;
 
-import java.util.List;
 import java.util.Optional;
 import java.util.stream.Stream;
 
@@ -90,8 +89,8 @@ public class HomePage extends PageAbstract {
     }
 
     private ObjectAndAction lookupHomePageAction() {
-        final List<ObjectAdapter> serviceAdapters = getPersistenceSession().getServices();
-        for (final ObjectAdapter serviceAdapter : serviceAdapters) {
+        final Stream<ObjectAdapter> serviceAdapters = getPersistenceSession().streamServices();
+        return serviceAdapters.map(serviceAdapter->{
             final ObjectSpecification serviceSpec = serviceAdapter.getSpecification();
             final Stream<ObjectAction> objectActions = serviceSpec.streamObjectActions(Contributed.EXCLUDED);
             
@@ -99,13 +98,13 @@ public class HomePage extends PageAbstract {
             .map(objectAction->objectAndActionIfHomePageAndUsable(serviceAdapter, objectAction))
             .filter(_NullSafe::isPresent)
             .findAny();
-            
-            if(homePageAction.isPresent()) {
-                return homePageAction.get();
-            }
-
-        }
-        return null;
+            return homePageAction;
+        })
+        .filter(Optional::isPresent)
+        .map(Optional::get)
+        .findAny()
+        .orElse(null)
+        ;
     }
 
     private ObjectAndAction objectAndActionIfHomePageAndUsable(ObjectAdapter serviceAdapter, ObjectAction objectAction) {