From 242eb443aab3a1b6cb0c04193a920ee0fda9d9c4 Mon Sep 17 00:00:00 2001
From: ribeaudc <ribeaudc>
Date: Thu, 30 Oct 2008 11:47:02 +0000
Subject: [PATCH] [LMS-621] add: - 'LoginController'. fix: - Some problems in
 the login process.

SVN: 8826
---
 .../web/client/application/AppController.java | 15 +---
 .../web/client/application/AppEvents.java     |  2 +-
 .../client/web/client/application/Client.java | 26 ++++---
 .../client/application/LoginController.java   | 56 +++++++++++++++
 .../web/client/application/LoginView.java     | 32 +++++----
 .../application/SessionContextCallback.java   | 11 ++-
 .../web/client/application/ui/LoginPage.java  |  8 ++-
 .../client/application/ui/LoginWidget.java    | 28 ++++----
 .../ui/sample_browser/SampleBrowserGrid.java  | 69 ++++++++++++-------
 .../util/UserFailureExceptionTranslator.java  |  2 +-
 .../openbis/plugin/AbstractClientService.java | 17 ++++-
 .../testframework/AbstractGWTTestCase.java    | 11 +--
 12 files changed, 190 insertions(+), 87 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/LoginController.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AppController.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AppController.java
index f87ba322712..2c1c3ea4edd 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AppController.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AppController.java
@@ -26,18 +26,14 @@ import com.extjs.gxt.ui.client.mvc.Controller;
  */
 public class AppController extends Controller
 {
-
     private AppView appView;
 
-    private LoginView loginView;
-
     private final GenericViewContext viewContext;
 
     public AppController(final GenericViewContext viewContext)
     {
         this.viewContext = viewContext;
         registerEventTypes(AppEvents.INIT);
-        registerEventTypes(AppEvents.USER_NOT_LOGGED_IN);
         registerEventTypes(AppEvents.NAVI_EVENT);
     }
 
@@ -46,15 +42,14 @@ public class AppController extends Controller
     {
         switch (event.type)
         {
-            case AppEvents.USER_NOT_LOGGED_IN:
-                onLogin(event);
-                break;
             case AppEvents.INIT:
                 onInit(event);
                 break;
             case AppEvents.NAVI_EVENT:
                 onLeftMenuSelectionChanged(event);
                 break;
+            default:
+                throw new IllegalArgumentException("Unknow event '" + event + "'.");
         }
     }
 
@@ -67,12 +62,6 @@ public class AppController extends Controller
     public void initialize()
     {
         appView = new AppView(this, viewContext);
-        loginView = new LoginView(this, viewContext);
-    }
-
-    private void onLogin(final AppEvent<?> event)
-    {
-        forwardToView(loginView, event);
     }
 
     private void onInit(final AppEvent<?> event)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AppEvents.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AppEvents.java
index c7397f71abd..fa19c227063 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AppEvents.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AppEvents.java
@@ -43,7 +43,7 @@ public class AppEvents
 
     public final static int INIT = STARTING_VALUE + 20;
 
-    public final static int USER_NOT_LOGGED_IN = STARTING_VALUE + 30;
+    public final static int LOGIN = STARTING_VALUE + 30;
 
     protected static final int NAVI_EVENT = STARTING_VALUE + 40;
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Client.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Client.java
index 0e9b12c7637..66e7f4cb375 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Client.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Client.java
@@ -21,6 +21,7 @@ import com.google.gwt.core.client.EntryPoint;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.rpc.ServiceDefTarget;
 
+import ch.systemsx.cisd.openbis.generic.client.web.client.IClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.IGenericClientService;
 import ch.systemsx.cisd.openbis.generic.client.web.client.IGenericClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.DictonaryBasedMessageProvider;
@@ -28,19 +29,21 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IMess
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ApplicationInfo;
 
 /**
+ * The {@link EntryPoint} implementation.
+ * 
  * @author Franz-Josef Elmer
  * @author Izabela Adamczyk
  */
-public class Client implements EntryPoint
+public final class Client implements EntryPoint
 {
-    private GenericViewContext viewContext;
+    private IViewContext<IGenericClientServiceAsync> viewContext;
 
-    public final GenericViewContext tryToGetViewContext()
+    public final IViewContext<IGenericClientServiceAsync> tryToGetViewContext()
     {
         return viewContext;
     }
 
-    private GenericViewContext createViewContext()
+    private final IViewContext<IGenericClientServiceAsync> createViewContext()
     {
         final IGenericClientServiceAsync service = GWT.create(IGenericClientService.class);
         final ServiceDefTarget endpoint = (ServiceDefTarget) service;
@@ -67,16 +70,21 @@ public class Client implements EntryPoint
         if (viewContext == null)
         {
             viewContext = createViewContext();
+            final Dispatcher dispatcher = Dispatcher.get();
+            dispatcher.addController(new LoginController(viewContext));
+            dispatcher.addController(new AppController((GenericViewContext) viewContext));
         }
 
-        Dispatcher dispatcher = Dispatcher.get();
-        dispatcher.addController(new AppController(viewContext));
-
-        final IGenericClientServiceAsync service = viewContext.getService();
+        final IClientServiceAsync service = viewContext.getService();
         service.getApplicationInfo(new AbstractAsyncCallback<ApplicationInfo>(viewContext)
             {
+
+                //
+                // AbstractAsyncCallback
+                //
+
                 @Override
-                public void process(final ApplicationInfo info)
+                public final void process(final ApplicationInfo info)
                 {
                     viewContext.getModel().setApplicationInfo(info);
                     service.tryToGetCurrentSessionContext(new SessionContextCallback(
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/LoginController.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/LoginController.java
new file mode 100644
index 00000000000..eadb04ea576
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/LoginController.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed 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 ch.systemsx.cisd.openbis.generic.client.web.client.application;
+
+import com.extjs.gxt.ui.client.mvc.AppEvent;
+import com.extjs.gxt.ui.client.mvc.Controller;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.IGenericClientServiceAsync;
+
+/**
+ * The {@link Controller} extension for logging events.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class LoginController extends Controller
+{
+    private final LoginView loginView;
+
+    LoginController(final IViewContext<IGenericClientServiceAsync> viewContext)
+    {
+        registerEventTypes(AppEvents.LOGIN);
+        loginView = new LoginView(this, viewContext);
+    }
+
+    //
+    // Controller
+    //
+
+    @Override
+    public final void handleEvent(final AppEvent<?> event)
+    {
+        final int type = event.type;
+        switch (type)
+        {
+            case AppEvents.LOGIN:
+                forwardToView(loginView, event);
+                break;
+            default:
+                throw new IllegalArgumentException("Unknow event '" + event + "'.");
+        }
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/LoginView.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/LoginView.java
index 4d9263c4565..85ba19a4c70 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/LoginView.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/LoginView.java
@@ -21,10 +21,11 @@ import com.extjs.gxt.ui.client.mvc.Controller;
 import com.extjs.gxt.ui.client.mvc.View;
 import com.google.gwt.user.client.ui.RootPanel;
 
+import ch.systemsx.cisd.openbis.generic.client.web.client.IGenericClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.LoginPage;
 
 /**
- * Responsible for creating login page and displaying it.
+ * The {@link View} extension for logging.
  * 
  * @author Izabela Adamczyk
  */
@@ -32,35 +33,40 @@ public class LoginView extends View
 {
     private LoginPage loginPage;
 
-    private final GenericViewContext viewContext;
+    private final IViewContext<IGenericClientServiceAsync> viewContext;
 
-    public LoginView(final Controller controller, final GenericViewContext viewContext2)
+    public LoginView(final Controller controller,
+            final IViewContext<IGenericClientServiceAsync> viewContext)
     {
         super(controller);
-        viewContext = viewContext2;
+        this.viewContext = viewContext;
     }
 
+    private void initUI()
+    {
+        RootPanel.get().clear();
+        RootPanel.get().add(loginPage);
+    }
+
+    //
+    // View
+    //
+
     @Override
-    protected void initialize()
+    protected final void initialize()
     {
         loginPage = new LoginPage(viewContext);
     }
 
     @Override
-    protected void handleEvent(final AppEvent<?> event)
+    protected final void handleEvent(final AppEvent<?> event)
     {
         switch (event.type)
         {
-            case AppEvents.USER_NOT_LOGGED_IN:
+            case AppEvents.LOGIN:
                 initUI();
                 break;
         }
     }
 
-    private void initUI()
-    {
-        RootPanel.get().clear();
-        RootPanel.get().add(loginPage);
-    }
-
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/SessionContextCallback.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/SessionContextCallback.java
index 11cb9e2ad2a..05adc3b59cb 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/SessionContextCallback.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/SessionContextCallback.java
@@ -34,16 +34,21 @@ public final class SessionContextCallback extends AbstractAsyncCallback<SessionC
         super(viewContext);
     }
 
+    //
+    // AbstractAsyncCallback
+    //
+
     @Override
-    public void process(final SessionContext sessionContext)
+    public final void process(final SessionContext sessionContext)
     {
+        final Dispatcher dispatcher = Dispatcher.get();
         if (sessionContext == null)
         {
-            Dispatcher.get().dispatch(AppEvents.USER_NOT_LOGGED_IN);
+            dispatcher.dispatch(AppEvents.LOGIN);
         } else
         {
             viewContext.getModel().setSessionContext(sessionContext);
-            Dispatcher.get().dispatch(AppEvents.INIT);
+            dispatcher.dispatch(AppEvents.INIT);
         }
     }
 }
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/LoginPage.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/LoginPage.java
index 5849764aace..86760800db1 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/LoginPage.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/LoginPage.java
@@ -25,7 +25,8 @@ import com.extjs.gxt.ui.client.widget.Text;
 import com.extjs.gxt.ui.client.widget.VerticalPanel;
 import com.extjs.gxt.ui.client.widget.layout.CenterLayout;
 
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.IGenericClientServiceAsync;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 
 /**
  * The login page.
@@ -35,7 +36,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericVie
 public class LoginPage extends LayoutContainer
 {
 
-    public LoginPage(final GenericViewContext viewContext)
+    public LoginPage(final IViewContext<IGenericClientServiceAsync> viewContext)
     {
         setStyleName("login-page");
         setLayout(new CenterLayout());
@@ -48,7 +49,8 @@ public class LoginPage extends LayoutContainer
         headerPanel.setSpacing(10);
         headerPanel.add(viewContext.getImageBundle().getLogo().createImage());
 
-        final Text welcomeLabel = new Text(viewContext.getMessage("welcome", new Date()));
+        final Text welcomeLabel =
+                new Text(viewContext.getMessageProvider().getMessage("welcome", new Date()));
         welcomeLabel.setStyleName("login-welcome-text");
 
         headerPanel.add(welcomeLabel);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/LoginWidget.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/LoginWidget.java
index 4804d7c8e88..c3b5b49ae2e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/LoginWidget.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/LoginWidget.java
@@ -29,9 +29,10 @@ import com.extjs.gxt.ui.client.widget.form.Field;
 import com.extjs.gxt.ui.client.widget.form.FormPanel;
 import com.extjs.gxt.ui.client.widget.form.TextField;
 
+import ch.systemsx.cisd.openbis.generic.client.web.client.IGenericClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericConstants;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.GWTUtils;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IMessageProvider;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.SessionContext;
@@ -62,10 +63,10 @@ public class LoginWidget extends VerticalPanel
 
     private final FormPanel formPanel;
 
-    public LoginWidget(final GenericViewContext viewContext)
+    public LoginWidget(final IViewContext<IGenericClientServiceAsync> viewContext)
     {
         setSpacing(10);
-        add(new Text(viewContext.getMessage(PREFIX + "invitation")));
+        add(new Text(viewContext.getMessageProvider().getMessage(PREFIX + "invitation")));
         formPanel = createFormPanel();
         userField = createUserField(viewContext);
         formPanel.add(userField);
@@ -88,10 +89,11 @@ public class LoginWidget extends VerticalPanel
         return formPanel;
     }
 
-    private final TextField<String> createUserField(final GenericViewContext viewContext)
+    private final TextField<String> createUserField(
+            final IViewContext<IGenericClientServiceAsync> viewContext)
     {
         final TextField<String> field = new TextField<String>();
-        field.setFieldLabel(viewContext.getMessage(PREFIX + "userLabel"));
+        field.setFieldLabel(viewContext.getMessageProvider().getMessage(PREFIX + "userLabel"));
         field.setSelectOnFocus(true);
         field.setAllowBlank(false);
         field.setValidateOnBlur(true);
@@ -102,7 +104,7 @@ public class LoginWidget extends VerticalPanel
     }
 
     private final void addEnterKeyListener(final Field<String> field,
-            final GenericViewContext viewContext)
+            final IViewContext<IGenericClientServiceAsync> viewContext)
     {
         field.addKeyListener(new EnterKeyListener()
             {
@@ -115,21 +117,23 @@ public class LoginWidget extends VerticalPanel
             });
     }
 
-    private final TextField<String> createPasswordField(final GenericViewContext viewContext)
+    private final TextField<String> createPasswordField(
+            final IViewContext<IGenericClientServiceAsync> viewContext)
     {
         final TextField<String> field = new TextField<String>();
         field.setPassword(true);
         field.setAllowBlank(false);
-        field.setFieldLabel(viewContext.getMessage(PREFIX + "passwordLabel"));
+        field.setFieldLabel(viewContext.getMessageProvider().getMessage(PREFIX + "passwordLabel"));
         field.setId(PASSWORD_FIELD_ID);
         field.setValidateOnBlur(true);
         addEnterKeyListener(field, viewContext);
         return field;
     }
 
-    private final Button createButton(final GenericViewContext viewContext)
+    private final Button createButton(final IViewContext<IGenericClientServiceAsync> viewContext)
     {
-        final Button b = new Button(viewContext.getMessage(PREFIX + "buttonLabel"));
+        final Button b =
+                new Button(viewContext.getMessageProvider().getMessage(PREFIX + "buttonLabel"));
         b.setId(BUTTON_ID);
         b.addSelectionListener(new SelectionListener<ComponentEvent>()
             {
@@ -147,7 +151,7 @@ public class LoginWidget extends VerticalPanel
         return b;
     }
 
-    private final void doLogin(final GenericViewContext viewContext)
+    private final void doLogin(final IViewContext<IGenericClientServiceAsync> viewContext)
     {
         if (GWTUtils.isTesting() || formPanel.isValid())
         {
@@ -164,7 +168,7 @@ public class LoginWidget extends VerticalPanel
 
     public static final class LoginCallback extends AbstractAsyncCallback<SessionContext>
     {
-        private LoginCallback(final GenericViewContext viewContext)
+        private LoginCallback(final IViewContext<IGenericClientServiceAsync> viewContext)
         {
             super(viewContext);
         }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample_browser/SampleBrowserGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample_browser/SampleBrowserGrid.java
index 7b6c5aa1cb3..f0d77cf12e9 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample_browser/SampleBrowserGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/sample_browser/SampleBrowserGrid.java
@@ -89,8 +89,9 @@ public final class SampleBrowserGrid extends LayoutContainer
 
     private final PagingLoader<?> loader;
 
-    public SampleBrowserGrid(final GenericViewContext viewContext, CommonColumns commonColumns,
-            ParentColumns parentColumns, PropertyColumns propertyColumns)
+    public SampleBrowserGrid(final GenericViewContext viewContext,
+            final CommonColumns commonColumns, final ParentColumns parentColumns,
+            final PropertyColumns propertyColumns)
     {
         this.viewContext = viewContext;
         this.commonColumns = commonColumns;
@@ -134,7 +135,7 @@ public final class SampleBrowserGrid extends LayoutContainer
 
         if (propertyColumns.isDirty())
         {
-            List<Sample> currentSamples = extractSamplesFromModel(previousModelsOrNull);
+            final List<Sample> currentSamples = extractSamplesFromModel(previousModelsOrNull);
             if (currentSamples.size() > 0)
             {
                 viewContext.getService().listSamplesProperties(newConfiguration.getCriterias(),
@@ -149,20 +150,20 @@ public final class SampleBrowserGrid extends LayoutContainer
 
     private List<Sample> extractSamplesFromModel(final List<SampleModel> modelList)
     {
-        List<Sample> samples = new ArrayList<Sample>();
-        for (SampleModel model : modelList)
+        final List<Sample> samples = new ArrayList<Sample>();
+        for (final SampleModel model : modelList)
         {
             samples.add((Sample) model.get(ModelDataPropertyNames.OBJECT));
         }
         return samples;
     }
 
-    protected void removeUnnecessarySamples(List<SampleModel> models)
+    protected void removeUnnecessarySamples(final List<SampleModel> models)
     {
-        Iterator<SampleModel> iterator = models.iterator();
+        final Iterator<SampleModel> iterator = models.iterator();
         while (iterator.hasNext())
         {
-            SampleModel next = iterator.next();
+            final SampleModel next = iterator.next();
             final Boolean isGroupLevelSample =
                     (Boolean) next.get(ModelDataPropertyNames.IS_GROUP_SAMPLE);
             final boolean isInstanceLevelSample = isGroupLevelSample == false;
@@ -301,7 +302,7 @@ public final class SampleBrowserGrid extends LayoutContainer
         {
             for (final Sample sample : samples)
             {
-                long sampleId = sample.getId();
+                final long sampleId = sample.getId();
                 List<SampleProperty> props = sample.getProperties();
                 if (props == null)
                 {
@@ -328,8 +329,12 @@ public final class SampleBrowserGrid extends LayoutContainer
             this.delegate = delegate;
         }
 
+        //
+        // AbstractAsyncCallback
+        //
+
         @Override
-        protected void finishOnFailure(final Throwable caught)
+        protected final void finishOnFailure(final Throwable caught)
         {
             delegate.onFailure(caught);
         }
@@ -350,8 +355,12 @@ public final class SampleBrowserGrid extends LayoutContainer
             {
                 private List<SampleModel> samples = null;
 
+                //
+                // RpcProxy
+                //
+
                 @Override
-                public void load(final PagingLoadConfig loadConfig,
+                public final void load(final PagingLoadConfig loadConfig,
                         final AsyncCallback<PagingLoadResult<SampleModel>> callback)
                 {
                     loadSamples(samples, createPageCallbackDelegator(loadConfig, callback));
@@ -361,21 +370,28 @@ public final class SampleBrowserGrid extends LayoutContainer
                         final PagingLoadConfig loadConfig,
                         final AsyncCallback<PagingLoadResult<SampleModel>> callback)
                 {
-                    return new AsyncCallback<List<SampleModel>>()
+                    return new AbstractAsyncCallback<List<SampleModel>>(viewContext)
                         {
-                            public void onFailure(Throwable caught)
-                            {
-                                callback.onFailure(caught);
-                            }
 
-                            public void onSuccess(List<SampleModel> result)
+                            //
+                            // AbstractAsyncCallback
+                            //
+
+                            @Override
+                            protected final void process(final List<SampleModel> result)
                             {
                                 samples = result;
                                 sort(samples, loadConfig);
-                                PagingLoadResult<SampleModel> pagingLoadResult =
+                                final PagingLoadResult<SampleModel> pagingLoadResult =
                                         getSublist(samples, loadConfig);
                                 callback.onSuccess(pagingLoadResult);
                             }
+
+                            @Override
+                            protected final void finishOnFailure(final Throwable caught)
+                            {
+                                // callback.onFailure(caught);
+                            }
                         };
                 }
             };
@@ -383,14 +399,14 @@ public final class SampleBrowserGrid extends LayoutContainer
 
     private PagingLoader<?> createSampleLoader()
     {
-        RpcProxy<PagingLoadConfig, PagingLoadResult<SampleModel>> proxy = createSampleProxy();
-        BasePagingLoader<PagingLoadConfig, PagingLoadResult<SampleModel>> pagingLoader =
+        final RpcProxy<PagingLoadConfig, PagingLoadResult<SampleModel>> proxy = createSampleProxy();
+        final BasePagingLoader<PagingLoadConfig, PagingLoadResult<SampleModel>> pagingLoader =
                 new BasePagingLoader<PagingLoadConfig, PagingLoadResult<SampleModel>>(proxy);
         pagingLoader.setRemoteSort(true);
         return pagingLoader;
     }
 
-    private static void sort(List<SampleModel> samples, final PagingLoadConfig config)
+    private static void sort(final List<SampleModel> samples, final PagingLoadConfig config)
     {
         if (config.getSortInfo().getSortField() != null)
         {
@@ -400,7 +416,7 @@ public final class SampleBrowserGrid extends LayoutContainer
                 Collections.sort(samples, config.getSortInfo().getSortDir().comparator(
                         new Comparator<SampleModel>()
                             {
-                                public int compare(SampleModel p1, SampleModel p2)
+                                public int compare(final SampleModel p1, final SampleModel p2)
                                 {
                                     return p1.get(sortField, "").compareTo(p2.get(sortField, ""));
                                 }
@@ -409,10 +425,11 @@ public final class SampleBrowserGrid extends LayoutContainer
         }
     }
 
-    private static <T> PagingLoadResult<T> getSublist(List<T> samples, final PagingLoadConfig config)
+    private static <T> PagingLoadResult<T> getSublist(final List<T> samples,
+            final PagingLoadConfig config)
     {
-        ArrayList<T> sublist = new ArrayList<T>();
-        int start = config.getOffset();
+        final ArrayList<T> sublist = new ArrayList<T>();
+        final int start = config.getOffset();
         int limit = samples.size();
         if (config.getLimit() > 0)
         {
@@ -427,7 +444,7 @@ public final class SampleBrowserGrid extends LayoutContainer
 
     private void updateLoadedPropertyColumns()
     {
-        for (LoadableColumnConfig cc : propertyColumns.getColumns())
+        for (final LoadableColumnConfig cc : propertyColumns.getColumns())
         {
             if (cc.isDirty())
             {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/util/UserFailureExceptionTranslator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/util/UserFailureExceptionTranslator.java
index 3389825cafc..e560338d1f4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/util/UserFailureExceptionTranslator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/util/UserFailureExceptionTranslator.java
@@ -50,7 +50,7 @@ public class UserFailureExceptionTranslator
             ch.systemsx.cisd.common.exceptions.UserFailureException exception)
     {
         final String className =
-                WEB_CLIENT_EXCEPTIONS_PACKAGE + exception.getClass().getSimpleName();
+                WEB_CLIENT_EXCEPTIONS_PACKAGE + "." + exception.getClass().getSimpleName();
         String message = exception.getMessage();
         try
         {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/AbstractClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/AbstractClientService.java
index 82ab44c290f..35ab2e9daba 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/AbstractClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/AbstractClientService.java
@@ -155,13 +155,28 @@ public abstract class AbstractClientService implements IClientService
             }
             final HttpSession httpSession = creatHttpSession();
             // Expiration time of httpSession is 10 seconds less than of session
-            httpSession.setMaxInactiveInterval(session.getSessionExpirationTime() / 1000 - 10);
+            final int sessionExpirationTimeInMillis = session.getSessionExpirationTime();
+            final int sessionExpirationTimeInSeconds = sessionExpirationTimeInMillis / 1000;
+            if (sessionExpirationTimeInMillis < 0)
+            {
+                httpSession.setMaxInactiveInterval(-1);
+            } else if (sessionExpirationTimeInMillis < 1000 || sessionExpirationTimeInSeconds < 10)
+            {
+                httpSession.setMaxInactiveInterval(0);
+            } else
+            {
+                httpSession.setMaxInactiveInterval(sessionExpirationTimeInSeconds - 10);
+            }
             httpSession.setAttribute(SessionConstants.OPENBIS_SESSION_ATTRIBUTE_KEY, session);
             httpSession.setAttribute(SessionConstants.OPENBIS_SERVER_ATTRIBUTE_KEY, getServer());
             return createSessionContext(session);
         } catch (final ch.systemsx.cisd.common.exceptions.UserFailureException e)
         {
             throw UserFailureExceptionTranslator.translate(e);
+        } catch (final IllegalStateException e)
+        {
+            operationLog.error("Session already invalidated.", e);
+            return null;
         }
     }
 
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractGWTTestCase.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractGWTTestCase.java
index feed5d2bae3..4e0d767a2c6 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractGWTTestCase.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractGWTTestCase.java
@@ -19,9 +19,10 @@ package ch.systemsx.cisd.openbis.generic.client.web.client.testframework;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
+import ch.systemsx.cisd.openbis.generic.client.web.client.IGenericClientServiceAsync;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.Client;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.GWTUtils;
 
 /**
@@ -53,7 +54,7 @@ public abstract class AbstractGWTTestCase extends GWTTestCase
      * Delays test termination until the specified timeout (in milliseconds). Wrapper of
      * {@link #delayTestFinish(int)}. Will be used in {@link RemoteConsole}.
      */
-    void delayTestTermination(int timeoutMillis)
+    void delayTestTermination(final int timeoutMillis)
     {
         delayTestFinish(timeoutMillis);
     }
@@ -77,16 +78,16 @@ public abstract class AbstractGWTTestCase extends GWTTestCase
     {
         remoteConsole.cancelTimer();
         AbstractAsyncCallback.setAllCallbackObjectsSilent();
-        GenericViewContext viewContext = client.tryToGetViewContext();
+        final IViewContext<IGenericClientServiceAsync> viewContext = client.tryToGetViewContext();
         if (viewContext != null)
         {
             viewContext.getService().logout(new AsyncCallback<Void>()
                 {
-                    public void onSuccess(Void result)
+                    public void onSuccess(final Void result)
                     {
                     }
 
-                    public void onFailure(Throwable caught)
+                    public void onFailure(final Throwable caught)
                     {
                         System.out.println("LOGOUT FAILED: " + caught);
                     }
-- 
GitLab