fixed bug 35060: Observers are executed twice on commitAndClose
authorAsier Lostalé <asier.lostale@openbravo.com>
Fri, 27 Jan 2017 11:02:07 +0100
changeset 31439 e159a9846352
parent 31438 9f835f99b47d
child 31440 768cb3ce28e1
fixed bug 35060: Observers are executed twice on commitAndClose

DAL observes got executed twice on commitAndClose because session.isDirty check
was causing them to be called.

Now, session dirtiness shouldn't be checked using directly session.isDirty method
but through the new OBDal.isSessionDirty, which allows OBInterceptor to know if
session is being checked so that it can prevent observes execution.
src/org/openbravo/dal/core/OBInterceptor.java
src/org/openbravo/dal/core/SessionHandler.java
src/org/openbravo/dal/service/OBDal.java
--- a/src/org/openbravo/dal/core/OBInterceptor.java	Thu Jan 26 14:31:05 2017 +0100
+++ b/src/org/openbravo/dal/core/OBInterceptor.java	Fri Jan 27 11:02:07 2017 +0100
@@ -163,6 +163,11 @@
   @Override
   public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
       Object[] previousState, String[] propertyNames, Type[] types) {
+    if (SessionHandler.isCheckingDirtySession()) {
+      // onFlushDirty gets invoked on actual flushes but also when checking session dirty, in later
+      // case nothing should be done here.
+      return false;
+    }
 
     // this can happen when someone has set the id of an object but has not set the
     // new object to true
--- a/src/org/openbravo/dal/core/SessionHandler.java	Thu Jan 26 14:31:05 2017 +0100
+++ b/src/org/openbravo/dal/core/SessionHandler.java	Fri Jan 27 11:02:07 2017 +0100
@@ -74,6 +74,7 @@
 
   // The threadlocal which handles the session
   private static ThreadLocal<SessionHandler> sessionHandler = new ThreadLocal<SessionHandler>();
+  private static ThreadLocal<Boolean> checkingSessionDirty = new ThreadLocal<Boolean>();
 
   /**
    * Removes the current SessionHandler from the ThreadLocal. A call to getSessionHandler will
@@ -129,6 +130,26 @@
     return session;
   }
 
+  /**
+   * Checks whether current session is dirty (there are remaining changes to be sent to DB). Note
+   * {@link Session#isDirty()} should not be directly invoked because it triggers Entity Persistence
+   * Observers to be executed for modified entities. This method handles it so that they are not
+   * called.
+   */
+  public boolean isSessionDirty() {
+    try {
+      checkingSessionDirty.set(true);
+      return getSession().isDirty();
+    } finally {
+      checkingSessionDirty.set(false);
+    }
+  }
+
+  /** Returns true when the session is in process of checking for dirtiness. */
+  static boolean isCheckingDirtySession() {
+    return Boolean.TRUE.equals(checkingSessionDirty.get());
+  }
+
   protected void setSession(Session thisSession) {
     session = thisSession;
   }
@@ -367,7 +388,7 @@
     // during flush, flush several times until
     // the session is really cleaned up
     int countFlushes = 0;
-    while (OBDal.getInstance().getSession().isDirty()) {
+    while (isSessionDirty()) {
       OBDal.getInstance().flush();
       countFlushes++;
       // arbitrary point to give up...
--- a/src/org/openbravo/dal/service/OBDal.java	Thu Jan 26 14:31:05 2017 +0100
+++ b/src/org/openbravo/dal/service/OBDal.java	Fri Jan 27 11:02:07 2017 +0100
@@ -168,6 +168,16 @@
   }
 
   /**
+   * Checks if the session associated with this DAL instance is dirty. Note isDirty method should
+   * not be directly invoked on the Session instance.
+   * 
+   * @see SessionHandler#isSessionDirty(String)
+   */
+  public boolean isSessionDirty() {
+    return SessionHandler.getInstance().isSessionDirty();
+  }
+
+  /**
    * Commits the transaction and closes session.
    */
   public void commitAndClose() {