details:   https://code.openbravo.com/erp/devel/pi/rev/d126554d216b
changeset: 33426:d126554d216b
user:      Asier Lostalé <asier.lostale <at> openbravo.com>
date:      Tue Feb 13 12:06:02 2018 +0100
summary:   fixed bug 37893, fixed bug 37899: incorrect CU handling in 
concurrency and POS

  Concurrent Users management had two different problems:
   * If a backoffice session was reused in POS closing backoffice browser, a CU
     session was counted and it was not deactivated while POS session was 
active.
     In this situation, the session should be deactivated if CU limit has been
     reached.
   * Code for creating and checking active http sessions in context was not 
thread
     safe, so it was possible to get an error when checking if session was 
active while
     other sessions were created/destroyed in paralell. This has been fixed by
     synchronizing on active session set. Having solved previous issue this 
should
     not create excessive contentention as it will be executed only if: CU 
limit has
     been reached and there are sessions created by mobile modules exclude POS.

details:   https://code.openbravo.com/erp/devel/pi/rev/4f7e83a9ad57
changeset: 33427:4f7e83a9ad57
user:      Asier Lostalé <asier.lostale <at> openbravo.com>
date:      Tue Feb 13 12:08:43 2018 +0100
summary:   related to bug 37893: added test case

  Which ensures sessions can be created and checked concurrently.

diffstat:

 src-test/src/org/openbravo/test/AllAntTaskTests.java      |   2 +
 src-test/src/org/openbravo/test/system/Sessions.java      |  90 +++++++++++++++
 src/org/openbravo/erpCommon/obps/ActivationKey.java       |  12 ++
 src/org/openbravo/erpCommon/security/SessionListener.java |  10 +-
 4 files changed, 110 insertions(+), 4 deletions(-)

diffs (176 lines):

diff -r d6507984d651 -r 4f7e83a9ad57 
src-test/src/org/openbravo/test/AllAntTaskTests.java
--- a/src-test/src/org/openbravo/test/AllAntTaskTests.java      Tue Feb 13 
08:47:07 2018 +0100
+++ b/src-test/src/org/openbravo/test/AllAntTaskTests.java      Tue Feb 13 
12:08:43 2018 +0100
@@ -104,6 +104,7 @@
 import org.openbravo.test.system.ErrorTextParserTest;
 import org.openbravo.test.system.ImportEntrySizeTest;
 import org.openbravo.test.system.Issue29934Test;
+import org.openbravo.test.system.Sessions;
 import org.openbravo.test.system.SystemServiceTest;
 import org.openbravo.test.system.SystemValidatorTest;
 import org.openbravo.test.system.TestInfrastructure;
@@ -194,6 +195,7 @@
     Issue29934Test.class, //
     ImportEntrySizeTest.class, //
     CryptoUtilities.class, //
+    Sessions.class, //
 
     // xml
     ClientExportImportTest.class, //
diff -r d6507984d651 -r 4f7e83a9ad57 
src-test/src/org/openbravo/test/system/Sessions.java
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/src-test/src/org/openbravo/test/system/Sessions.java      Tue Feb 13 
12:08:43 2018 +0100
@@ -0,0 +1,90 @@
+/*
+ *************************************************************************
+ * The contents of this file are subject to the Openbravo  Public  License
+ * Version  1.1  (the  "License"),  being   the  Mozilla   Public  License
+ * Version 1.1  with a permitted attribution clause; you may not  use this
+ * file except in compliance with the License. You  may  obtain  a copy of
+ * the License at http://www.openbravo.com/legal/license.html 
+ * Software distributed under the License  is  distributed  on  an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific  language  governing  rights  and  limitations
+ * under the License. 
+ * The Original Code is Openbravo ERP. 
+ * The Initial Developer of the Original Code is Openbravo SLU 
+ * All portions are Copyright (C) 2018 Openbravo SLU 
+ * All Rights Reserved. 
+ * Contributor(s):  ______________________________________.
+ ************************************************************************
+ */
+
+package org.openbravo.test.system;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionEvent;
+
+import 
org.jboss.arquillian.container.weld.ee.embedded_1_1.mock.MockHttpSession;
+import org.junit.Test;
+import org.openbravo.erpCommon.security.SessionListener;
+import org.openbravo.erpCommon.utility.SequenceIdData;
+
+/** Test cases covering Session management */
+public class Sessions {
+  private static int NUMBER_OF_THREADS = 4;
+  private static int NUMBER_OF_SESSIONS_PER_THREAD = 1_000;
+
+  /** Covers bug #37893 */
+  @Test
+  public void canCreateAndCheckSessionsInParallel() throws 
InterruptedException, ExecutionException {
+    SessionListener sl = new SessionListener();
+    List<SessionCreatorAndChecker> tasks = new ArrayList<>();
+    for (int i = 0; i < NUMBER_OF_THREADS; i++) {
+      tasks.add(new SessionCreatorAndChecker(sl));
+    }
+
+    ExecutorService es = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
+    List<Future<Void>> executions = es.invokeAll(tasks);
+
+    for (Future<Void> e : executions) {
+      // if assertion failed, this will throw exception
+      e.get();
+    }
+  }
+
+  private class SessionCreatorAndChecker implements Callable<Void> {
+    private SessionListener sl;
+
+    public SessionCreatorAndChecker(SessionListener sl) {
+      this.sl = sl;
+    }
+
+    @Override
+    public Void call() {
+      for (int i = 0; i < NUMBER_OF_SESSIONS_PER_THREAD; i++) {
+        String sessionId = SequenceIdData.getUUID();
+
+        HttpSession s = new MockHttpSession();
+        s.setAttribute("#AD_SESSION_ID", sessionId);
+        sl.sessionCreated(new HttpSessionEvent(s));
+
+        HttpSession sessionFromContext = 
SessionListener.getActiveSession(sessionId);
+
+        // before fix of #37893, sessionFromContext is null in some cases 
because of caught
+        // ConcurrentModificationException
+        assertThat(sessionFromContext, is(s));
+      }
+
+      return null;
+    }
+  }
+}
diff -r d6507984d651 -r 4f7e83a9ad57 
src/org/openbravo/erpCommon/obps/ActivationKey.java
--- a/src/org/openbravo/erpCommon/obps/ActivationKey.java       Tue Feb 13 
08:47:07 2018 +0100
+++ b/src/org/openbravo/erpCommon/obps/ActivationKey.java       Tue Feb 13 
12:08:43 2018 +0100
@@ -40,6 +40,7 @@
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
@@ -252,6 +253,12 @@
       add("OBPOS_POS"); // WebPOS
     }
   };
+
+  private static final List<String> BACKOFFICE_SUCESS_SESSION_TYPES = 
Arrays.asList(//
+      "S", // Standard success session
+      "SUR" // Concurrent users soft limit reached
+  );
+
   public static final Long NO_LIMIT = -1L;
 
   private static ActivationKey instance = new ActivationKey();
@@ -1116,6 +1123,11 @@
    * mobile apps) if activity from them has been recently detected.
    */
   private boolean shouldDeactivateSession(Session expiredSession, Date 
lastValidPingTime) {
+    if 
(BACKOFFICE_SUCESS_SESSION_TYPES.contains(expiredSession.getLoginStatus())) {
+      // backoffice sessions use ping, they can be deactivated even if created 
in a different node
+      return true;
+    }
+
     String sessionId = expiredSession.getId();
     HttpSession session = SessionListener.getActiveSession(sessionId);
     if (session == null) {
diff -r d6507984d651 -r 4f7e83a9ad57 
src/org/openbravo/erpCommon/security/SessionListener.java
--- a/src/org/openbravo/erpCommon/security/SessionListener.java Tue Feb 13 
08:47:07 2018 +0100
+++ b/src/org/openbravo/erpCommon/security/SessionListener.java Tue Feb 13 
12:08:43 2018 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2009-2017 Openbravo SLU 
+ * All portions are Copyright (C) 2009-2018 Openbravo SLU 
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -175,9 +175,11 @@
    */
   public static HttpSession getActiveSession(String sessionId) {
     try {
-      for (HttpSession session : activeHttpSessions) {
-        if (sessionId.equals(session.getAttribute("#AD_SESSION_ID"))) {
-          return session;
+      synchronized (activeHttpSessions) {
+        for (HttpSession session : activeHttpSessions) {
+          if (sessionId.equals(session.getAttribute("#AD_SESSION_ID"))) {
+            return session;
+          }
         }
       }
     } catch (Exception e) {

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Openbravo-commits mailing list
Openbravo-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openbravo-commits

Reply via email to