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

[isis] branch master updated: ISIS-2306: supposed fix to have request scoped IsisSessions for Vaadin

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

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


The following commit(s) were added to refs/heads/master by this push:
     new d30b22e  ISIS-2306: supposed fix to have request scoped IsisSessions for Vaadin
d30b22e is described below

commit d30b22e9ccf340983bf2cc52577504312c34491b
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sun Mar 15 17:06:01 2020 +0100

    ISIS-2306: supposed fix to have request scoped IsisSessions for Vaadin
---
 .../session/IsisSessionFactoryDefault.java         |   6 ++
 .../java/demoapp/vaadin/webapp/DemoAppVaadin.java  |   2 +
 .../vaadin/ui/auth/AuthSessionStoreUtil.java       |  80 ++++++++++++++++
 .../ui/auth/VaadinAuthenticationHandler.java       |  35 +++----
 .../vaadin/ui/components/collection/TableView.java | 102 ++++++++++++++++++++-
 .../ui/components/object/ObjectFormView.java       |  43 +--------
 .../viewer/vaadin/ui/pages/main/MainView.java      |   2 +-
 .../viewer/IsisModuleIncViewerVaadinViewer.java    |   5 +-
 .../viewer/vaadin/viewer/IsisServletForVaadin.java |  84 +++++++++++++++++
 9 files changed, 291 insertions(+), 68 deletions(-)

diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/IsisSessionFactoryDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/IsisSessionFactoryDefault.java
index 730db5b..39803b1 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/IsisSessionFactoryDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/IsisSessionFactoryDefault.java
@@ -245,6 +245,12 @@ public class IsisSessionFactoryDefault implements IsisSessionFactory, IsisSessio
     
     private void closeSessionStackDownToStackSize(int downToStackSize) {
         
+        log.debug("about to close IsisSession stack down to size {} (conversation-id={}, total-sessions-on-stack={}, {})",
+                downToStackSize,
+                conversationId.get(), 
+                isisSessionStack.get().size(),
+                _Probe.currentThreadId());
+        
         val stack = isisSessionStack.get();
         while(stack.size()>downToStackSize) {
             if(stack.size()==1) {       
diff --git a/examples/demo-vaadin/src/main/java/demoapp/vaadin/webapp/DemoAppVaadin.java b/examples/demo-vaadin/src/main/java/demoapp/vaadin/webapp/DemoAppVaadin.java
index c218b67..1e8f994 100644
--- a/examples/demo-vaadin/src/main/java/demoapp/vaadin/webapp/DemoAppVaadin.java
+++ b/examples/demo-vaadin/src/main/java/demoapp/vaadin/webapp/DemoAppVaadin.java
@@ -29,6 +29,7 @@ import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.core.runtimeservices.session.IsisSessionFactoryDefault;
 import org.apache.isis.incubator.viewer.vaadin.ui.auth.VaadinAuthenticationHandler;
 import org.apache.isis.incubator.viewer.vaadin.viewer.IsisModuleIncViewerVaadinViewer;
+import org.apache.isis.incubator.viewer.vaadin.viewer.IsisServletForVaadin;
 
 import demoapp.webapp.DemoApp;
 
@@ -60,6 +61,7 @@ public class DemoAppVaadin extends SpringBootServletInitializer {
         
         IsisPresets.logging(IsisSessionFactoryDefault.class, "debug");
         IsisPresets.logging(VaadinAuthenticationHandler.class, "debug");
+        IsisPresets.logging(IsisServletForVaadin.class, "debug");
         
         SpringApplication.run(new Class[] { DemoAppVaadin.class }, args);
     }
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/AuthSessionStoreUtil.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/AuthSessionStoreUtil.java
new file mode 100644
index 0000000..ee09693
--- /dev/null
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/AuthSessionStoreUtil.java
@@ -0,0 +1,80 @@
+/*
+ *  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.incubator.viewer.vaadin.ui.auth;
+
+import java.util.Optional;
+
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpSession;
+
+import com.vaadin.flow.server.VaadinSession;
+
+import org.apache.isis.core.commons.internal.collections._Lists;
+import org.apache.isis.core.security.authentication.AuthenticationSession;
+import org.apache.isis.core.security.authentication.standard.SimpleSession;
+
+import lombok.NonNull;
+import lombok.experimental.UtilityClass;
+
+/**
+ * 
+ * @since Mar 15, 2020
+ *
+ */
+@UtilityClass
+public class AuthSessionStoreUtil {
+
+    public static void put(
+            @NonNull final HttpSession httpSession, 
+            @Nullable final AuthenticationSession authSession) {
+        httpSession.setAttribute(AuthenticationSession.class.getName(), authSession);
+    }
+    
+    public static Optional<AuthenticationSession> get(
+            @NonNull final HttpSession httpSession) {
+        return Optional.ofNullable(
+                (AuthenticationSession)httpSession
+                .getAttribute(AuthenticationSession.class.getName()));
+    }
+    
+    /** when within a VaadinSession */
+    public static void put(
+            @Nullable final AuthenticationSession authSession) {
+        VaadinSession.getCurrent().getSession()
+        .setAttribute(AuthenticationSession.class.getName(), authSession);
+    }
+    
+    /** when within a VaadinSession */
+    public static Optional<AuthenticationSession> get() {
+        return Optional.ofNullable(
+                (AuthenticationSession)VaadinSession.getCurrent().getSession()
+                .getAttribute(AuthenticationSession.class.getName()));
+    }
+    
+    /** when within a VaadinSession */
+    public static void clear() {
+        put(null);
+    }
+    
+    /** when within a VaadinSession */
+    public static void putSven() {
+        put(new SimpleSession("sven", _Lists.of("isis-module-security-admin")));        
+    }
+
+}
\ No newline at end of file
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/VaadinAuthenticationHandler.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/VaadinAuthenticationHandler.java
index 48fc706..79c9207 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/VaadinAuthenticationHandler.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/auth/VaadinAuthenticationHandler.java
@@ -18,7 +18,6 @@
  */
 package org.apache.isis.incubator.viewer.vaadin.ui.auth;
 
-import java.util.Optional;
 import java.util.concurrent.Callable;
 
 import javax.inject.Inject;
@@ -31,11 +30,8 @@ import com.vaadin.flow.server.VaadinSession;
 
 import org.springframework.stereotype.Component;
 
-import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.runtime.session.IsisSessionFactory;
 import org.apache.isis.core.runtime.session.IsisSessionFactory.ThrowingRunnable;
-import org.apache.isis.core.security.authentication.AuthenticationSession;
-import org.apache.isis.core.security.authentication.standard.SimpleSession;
 import org.apache.isis.incubator.viewer.vaadin.ui.pages.login.VaadinLoginView;
 
 import lombok.val;
@@ -57,7 +53,7 @@ public class VaadinAuthenticationHandler implements VaadinServiceInitListener {
     @Override
     public void serviceInit(ServiceInitEvent event) {
         
-        log.info("service init event {}", event.getSource());
+        log.debug("service init event {}", event.getSource());
         
         event.getSource().addUIInitListener(uiEvent -> {
             uiEvent.getUI().addBeforeEnterListener(this::beforeEnter); 
@@ -71,27 +67,23 @@ public class VaadinAuthenticationHandler implements VaadinServiceInitListener {
      * @return whether login was successful
      */
     public boolean loginToSession(String userName, String secret) {
-        log.info("logging in {}", userName);
+        log.debug("logging in {}", userName);
+        
         // TODO yet does successfully login 'sven' regardless of arguments
-        VaadinSession.getCurrent().setAttribute(
-                AuthenticationSession.class, 
-                new SimpleSession("sven", _Lists.of("isis-module-security-admin")));
+        AuthSessionStoreUtil.putSven();
+        
         return true;
     }
     
     public void logoutFromSession() {
-        currentAuthenticationSession()
+        AuthSessionStoreUtil.get()
         .ifPresent(authSession->{
-            log.info("logging out {}", authSession.getUserName());
-            VaadinSession.getCurrent().setAttribute(AuthenticationSession.class, null);
+            log.debug("logging out {}", authSession.getUserName());
+            AuthSessionStoreUtil.clear();
         });
         VaadinSession.getCurrent().close();
+        isisSessionFactory.closeSessionStack();
     } 
-
-    public static Optional<AuthenticationSession> currentAuthenticationSession() {
-        return Optional.ofNullable(VaadinSession.getCurrent().getAttribute(
-                AuthenticationSession.class));
-    }
     
     /**
      * Executes a piece of code in a new (possibly nested) IsisSession, using the 
@@ -102,7 +94,7 @@ public class VaadinAuthenticationHandler implements VaadinServiceInitListener {
      * 
      */
     public <R> R callAuthenticated(Callable<R> callable) {
-        return currentAuthenticationSession()
+        return AuthSessionStoreUtil.get()
                 .map(authSession->isisSessionFactory.callAuthenticated(authSession, callable))
                 .orElse(null); // TODO redirect to login
     }
@@ -121,20 +113,21 @@ public class VaadinAuthenticationHandler implements VaadinServiceInitListener {
 
     private void beforeEnter(BeforeEnterEvent event) {
         val targetView = event.getNavigationTarget();
-        log.info("Detected a routing event to {}", targetView);
+        log.debug("detected a routing event to {}", targetView);
         
-        val authSession = currentAuthenticationSession().orElse(null);
+        val authSession = AuthSessionStoreUtil.get().orElse(null);
         if(authSession!=null) {
             isisSessionFactory.openSession(authSession);
             return; // access granted
         }
+        // otherwise redirect to login page
         if(!VaadinLoginView.class.equals(targetView)) {
             event.rerouteTo(VaadinLoginView.class);
         }
     }
     
     private void beforeLeave(BeforeLeaveEvent event) {
-        isisSessionFactory.closeSessionStack();
+        //isisSessionFactory.closeSessionStack();
     }
     
 
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/collection/TableView.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/collection/TableView.java
index 8f12661..38dde8e 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/collection/TableView.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/collection/TableView.java
@@ -18,32 +18,126 @@
  */
 package org.apache.isis.incubator.viewer.vaadin.ui.components.collection;
 
+import java.util.Collection;
 import java.util.stream.Collectors;
 
+import javax.annotation.Nullable;
+
 import com.vaadin.flow.component.grid.Grid;
 import com.vaadin.flow.component.orderedlayout.VerticalLayout;
 
+import org.apache.isis.core.commons.internal.base._NullSafe;
 import org.apache.isis.core.metamodel.facets.collections.CollectionFacet;
 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.ObjectAssociation;
 
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
 import lombok.val;
 
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class TableView extends VerticalLayout {
 
     private static final long serialVersionUID = 1L;
-
+    
+    private static final String NULL_LITERAL = "<NULL>";
+    
+    public static TableView empty() {
+        return new TableView();
+    }
+            
     /**
      * Constructs a (page-able) {@link Grid} from given {@code collection}  
-     * @param collection of (wrapped) domain objects
+     * @param collection - of (wrapped) domain objects
      */
-    public TableView(final ManagedObject collection) {
+    public static TableView fromCollection(final ManagedObject collection) {
         val collectionFacet = collection.getSpecification()
                 .getFacet(CollectionFacet.class);
         val objects = collectionFacet.stream(collection)
                 .collect(Collectors.toList());
+        if (_NullSafe.isEmpty(objects)) {
+            return empty();
+        }
+        
+        val elementSpec = objects.iterator().next().getSpecification();
+        return new TableView(elementSpec, objects);
+    }
+    
+    /**
+     * Constructs a (page-able) {@link Grid} from given {@code objectAssociation} and {@code assocObject}   
+     * @param objectAssociation
+     * @param assocObject
+     */
+    public static TableView fromObjectAssociation(
+            @NonNull final ObjectAssociation objectAssociation,
+            @Nullable final ManagedObject assocObject) {
+        
+        val assocObjectSpecification = assocObject.getSpecification();
+        val collectionFacet = assocObjectSpecification.getFacet(CollectionFacet.class);
+
+        val pojo = assocObject.getPojo();
+        if (pojo instanceof Collection) {
+            val objects = collectionFacet.stream(assocObject).collect(Collectors.toList());
+            return new TableView(objectAssociation.getOnType(), objects);
+        }
+        
+        return empty();
+    }
+    
+    
+    /**
+     * 
+     * @param elementSpec - as is common to all given {@code objects} aka elements 
+     * @param objects - (wrapped) domain objects to be rendered by this table
+     */
+    private TableView(
+            @NonNull final ObjectSpecification elementSpec, 
+            @Nullable final Collection<ManagedObject> objects) {
         
+        //            final ComboBox<ManagedObject> listBox = new ComboBox<>();
+        //            listBox.setLabel(label + " #" + objects.size());
+        //            listBox.setItems(objects);
+        //            if (!objects.isEmpty()) {
+        //                listBox.setValue(objects.get(0));
+        //            }
+        //            listBox.setItemLabelGenerator(o -> o.titleString(null));
+
         val objectGrid = new Grid<ManagedObject>();
-        objectGrid.setItems(objects);
         add(objectGrid);
+        
+        if (_NullSafe.isEmpty(objects)) {
+            return;
+        }
+        
+        objectGrid.setItems(objects);
+        
+        elementSpec
+        .streamAssociations(Contributed.INCLUDED)
+        .filter(assoc -> assoc.getFeatureType().isProperty())
+        .forEach(property -> {
+            
+            objectGrid.addColumn(targetObject -> {
+                // TODO call to property.get(...) requires an IsisSession,
+                // not sure if we want to spawn a new session for each such call.
+                // maybe we open an IsisSession earlier, to have this table/grid built 
+                // within a single IsisSession 
+                
+                val propertyValue = property.get(targetObject);
+                return propertyValue == null 
+                        ? NULL_LITERAL
+                        : propertyValue.titleString();
+
+//                return "<" + property.getId() + ">";
+                
+            })
+            .setHeader(property.getName());
+        });
+        objectGrid.setItems(objects);
+        objectGrid.recalculateColumnWidths();
+        objectGrid.setColumnReorderingAllowed(true);
+        
     }
 }
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/object/ObjectFormView.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/object/ObjectFormView.java
index 34bf31e..682cbef 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/object/ObjectFormView.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/object/ObjectFormView.java
@@ -20,12 +20,10 @@ package org.apache.isis.incubator.viewer.vaadin.ui.components.object;
 
 import java.io.ByteArrayInputStream;
 import java.util.Collection;
-import java.util.List;
 import java.util.stream.Collectors;
 
 import com.vaadin.flow.component.Component;
 import com.vaadin.flow.component.formlayout.FormLayout;
-import com.vaadin.flow.component.grid.Grid;
 import com.vaadin.flow.component.html.H1;
 import com.vaadin.flow.component.html.H3;
 import com.vaadin.flow.component.html.Image;
@@ -35,11 +33,11 @@ import com.vaadin.flow.component.textfield.TextField;
 import com.vaadin.flow.server.InputStreamFactory;
 import com.vaadin.flow.server.StreamResource;
 
-import org.apache.isis.core.metamodel.facets.collections.CollectionFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.feature.Contributed;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+import org.apache.isis.incubator.viewer.vaadin.ui.components.collection.TableView;
 
 import lombok.val;
 
@@ -124,48 +122,11 @@ public class ObjectFormView extends VerticalLayout {
             final ObjectAssociation objectAssociation,
             final ManagedObject assocObject
     ) {
-        val assocObjectSpecification = assocObject.getSpecification();
-        val collectionFacet = assocObjectSpecification.getFacet(CollectionFacet.class);
 
         val labelLiteral = "Collection: " + objectAssociation.getName();
         val pojo = assocObject.getPojo();
         if (pojo instanceof Collection) {
-
-            final List<ManagedObject> objects = collectionFacet.stream(assocObject).collect(Collectors.toList());
-
-            //            final ComboBox<ManagedObject> listBox = new ComboBox<>();
-            //            listBox.setLabel(label + " #" + objects.size());
-            //            listBox.setItems(objects);
-            //            if (!objects.isEmpty()) {
-            //                listBox.setValue(objects.get(0));
-            //            }
-            //            listBox.setItemLabelGenerator(o -> o.titleString(null));
-
-            val objectGrid = new Grid<ManagedObject>();
-            if (objects.isEmpty()) {
-                return objectGrid;
-            }
-            val firstObject = objects.get(0);
-            firstObject.getSpecification()
-            .streamAssociations(Contributed.INCLUDED)
-            .filter(assoc -> assoc.getFeatureType().isProperty())
-            .forEach(property -> {
-                objectGrid.addColumn(targetObject -> {
-                    // TODO call to property.get(...) requires an IsisSession,
-                    // not sure if we want to spawn a new session for each such call.
-                    // maybe we open an IsisSession earlier, to have this table/grid built 
-                    // within a single IsisSession 
-                    val propertyValue = property.get(targetObject);
-                    return propertyValue == null 
-                            ? NULL_LITERAL
-                            : propertyValue.titleString();
-                })
-                .setHeader(property.getName());
-            });
-            objectGrid.setItems(objects);
-            objectGrid.recalculateColumnWidths();
-            objectGrid.setColumnReorderingAllowed(true);
-            return objectGrid;
+            return TableView.fromObjectAssociation(objectAssociation, assocObject);
         }
 
         if (pojo == null) {
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/pages/main/MainView.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/pages/main/MainView.java
index 5d172d5..7d0177b 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/pages/main/MainView.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/pages/main/MainView.java
@@ -193,7 +193,7 @@ public class MainView extends VerticalLayout {
                                 );
 
                 if (result.getSpecification().isParentedOrFreeCollection()) {
-                    actionResult.add(new TableView(result));
+                    actionResult.add(TableView.fromCollection(result));
                 } else {
                     actionResult.add(new ObjectFormView(result));
                 }
diff --git a/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisModuleIncViewerVaadinViewer.java b/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisModuleIncViewerVaadinViewer.java
index 8b28086..8890e85 100644
--- a/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisModuleIncViewerVaadinViewer.java
+++ b/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisModuleIncViewerVaadinViewer.java
@@ -41,6 +41,7 @@ import org.springframework.util.ClassUtils;
 import org.springframework.web.context.WebApplicationContext;
 import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 
+import org.apache.isis.core.runtime.session.IsisSessionFactory;
 import org.apache.isis.incubator.viewer.vaadin.ui.IsisModuleIncViewerVaadinUi;
 
 import lombok.val;
@@ -70,6 +71,7 @@ public class IsisModuleIncViewerVaadinViewer {
     
     @Inject private WebApplicationContext context;
     @Inject private VaadinConfigurationProperties configurationProperties;
+    @Inject private IsisSessionFactory isisSessionFactory;
 
     /**
      * Creates a {@link ServletContextInitializer} instance.
@@ -97,7 +99,8 @@ public class IsisModuleIncViewerVaadinViewer {
                     makeContextRelative(urlMapping.replace("*", "")));
         }
         val registration = new ServletRegistrationBean<SpringServlet>(
-                new SpringServlet(context, isRootMapping), urlMapping);
+                new IsisServletForVaadin(isisSessionFactory, context, isRootMapping), 
+                urlMapping);
         registration.setInitParameters(initParameters);
         registration.setAsyncSupported(configurationProperties.isAsyncSupported());
         registration.setName(ClassUtils.getShortNameAsProperty(SpringServlet.class));
diff --git a/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisServletForVaadin.java b/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisServletForVaadin.java
new file mode 100644
index 0000000..d9cbf28
--- /dev/null
+++ b/incubator/viewers/vaadin/viewer/src/main/java/org/apache/isis/incubator/viewer/vaadin/viewer/IsisServletForVaadin.java
@@ -0,0 +1,84 @@
+/*
+ *  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.incubator.viewer.vaadin.viewer;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.vaadin.flow.spring.SpringServlet;
+
+import org.springframework.context.ApplicationContext;
+
+import org.apache.isis.core.runtime.session.IsisSession;
+import org.apache.isis.core.runtime.session.IsisSessionFactory;
+import org.apache.isis.incubator.viewer.vaadin.ui.auth.AuthSessionStoreUtil;
+
+import lombok.NonNull;
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
+/**
+ * An extension of {@link SpringServlet} to support {@link IsisSession} life-cycle management.
+ * @since Mar 14, 2020
+ *
+ */
+@Log4j2
+public class IsisServletForVaadin 
+extends SpringServlet {
+
+    private static final long serialVersionUID = 1L;
+    
+    private final IsisSessionFactory isisSessionFactory;
+
+    public IsisServletForVaadin(
+            @NonNull final IsisSessionFactory isisSessionFactory, 
+            @NonNull final ApplicationContext context, 
+            final boolean forwardingEnforced) {
+        super(context, forwardingEnforced);
+        this.isisSessionFactory = isisSessionFactory;
+    }
+   
+    
+    @Override
+    protected void service(HttpServletRequest request,
+            HttpServletResponse response) throws ServletException, IOException {
+        
+        val authSession = AuthSessionStoreUtil.get(request.getSession(true))
+                .orElse(null);
+        
+        log.debug("new request incoming (authentication={})", authSession);
+        
+        if(authSession!=null) {
+            isisSessionFactory.runAuthenticated(authSession, ()->{
+                super.service(request, response);                
+            });
+        } else {
+            // do not open an IsisSession, instead redirect to login page
+            // this should happen afterwards by means of the VaadinAuthenticationHandler
+            
+            super.service(request, response);    
+        }
+    }
+  
+
+    
+}