Fixes issue 38903: BaseOBObjects stored in OBContext are properly initialized
authorAugusto Mauch <augusto.mauch@openbravo.com>
Wed, 08 Aug 2018 09:00:32 +0200
changeset 34497 e17a08d06f29
parent 34495 d535ae1bfc55
child 34498 0956448be546
Fixes issue 38903: BaseOBObjects stored in OBContext are properly initialized

Now all the first level BaseOBObject properties of the BaseOBObjects stored in the context (user,
organization, role, language, warehouse) are properly initialized using Hibernate.initialize.

This way, they are no longer proxies, so they can be accessed outside the DAL session where they
were created.
src-test/src/org/openbravo/test/dal/OBContextTest.java
src/org/openbravo/dal/core/OBContext.java
--- a/src-test/src/org/openbravo/test/dal/OBContextTest.java	Wed Aug 08 06:11:43 2018 +0000
+++ b/src-test/src/org/openbravo/test/dal/OBContextTest.java	Wed Aug 08 09:00:32 2018 +0200
@@ -22,8 +22,12 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import org.hibernate.LazyInitializationException;
 import org.junit.Test;
+import org.openbravo.base.model.Entity;
+import org.openbravo.base.structure.BaseOBObject;
 import org.openbravo.dal.core.OBContext;
+import org.openbravo.dal.service.OBDal;
 import org.openbravo.test.base.OBBaseTest;
 
 /**
@@ -175,6 +179,50 @@
     OBContext.restorePreviousMode();
   }
 
+  /**
+   * Test that checks the first level properties of all the properties stored in the OBContext
+   * (user, organization, language, role, warehouse) are not proxies See issue
+   * https://issues.openbravo.com/view.php?id=38903
+   */
+  @Test
+  public void testBaseObjectsInContextAreNotProxies() {
+    setTestUserContext();
+    OBDal.getInstance().commitAndClose();
+    assertTrue("User should be initialized", firstLevelPropertiesAreInitialized(OBContext
+        .getOBContext().getUser()));
+    assertTrue("Organization should be initialized", firstLevelPropertiesAreInitialized(OBContext
+        .getOBContext().getCurrentOrganization()));
+    assertTrue("Language should be initialized", firstLevelPropertiesAreInitialized(OBContext
+        .getOBContext().getLanguage()));
+    assertTrue("Role should be initialized", firstLevelPropertiesAreInitialized(OBContext
+        .getOBContext().getRole()));
+    assertTrue("Warehouse should be initialized", firstLevelPropertiesAreInitialized(OBContext
+        .getOBContext().getWarehouse()));
+  }
+
+  private boolean firstLevelPropertiesAreInitialized(BaseOBObject bob) {
+    if (bob == null) {
+      return true;
+    }
+    try {
+      OBContext.setAdminMode(true);
+      Entity entity = bob.getEntity();
+      // invoke the getIdentifier method on all first level properties that return BaseOBObjects
+      // if they are proxies, a LazyInitializationException will be thrown
+      entity.getProperties().stream() //
+          .filter(property -> !property.isOneToMany()) //
+          .map(property -> bob.get(property.getName())) //
+          .filter(BaseOBObject.class::isInstance) //
+          .map(BaseOBObject.class::cast) //
+          .forEach(referencedBob -> referencedBob.getIdentifier());
+    } catch (LazyInitializationException e) {
+      return false;
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+    return true;
+  }
+
   // the scenario:
   // thread1 T1
   // thread2 T2
--- a/src/org/openbravo/dal/core/OBContext.java	Wed Aug 08 06:11:43 2018 +0000
+++ b/src/org/openbravo/dal/core/OBContext.java	Wed Aug 08 09:00:32 2018 +0200
@@ -39,6 +39,7 @@
 import org.hibernate.Hibernate;
 import org.hibernate.query.Query;
 import org.openbravo.base.exception.OBSecurityException;
+import org.openbravo.base.model.Entity;
 import org.openbravo.base.provider.OBNotSingleton;
 import org.openbravo.base.provider.OBProvider;
 import org.openbravo.base.structure.BaseOBObject;
@@ -712,10 +713,12 @@
   }
 
   public void setCurrentClient(Client currentClient) {
+    initializeFirstLevelProperties(currentClient);
     this.currentClient = currentClient;
   }
 
   public void setCurrentOrganization(Organization currentOrganization) {
+    initializeFirstLevelProperties(currentOrganization);
     this.currentOrganization = currentOrganization;
   }
 
@@ -724,6 +727,7 @@
   }
 
   public void setLanguage(Language language) {
+    initializeFirstLevelProperties(language);
     this.language = language;
     setRTL(language.isRTLLanguage());
   }
@@ -866,16 +870,6 @@
     getAdminModeStack(AdminType.ADMIN_MODE).push(am);
     try {
       setUser(u);
-      Hibernate.initialize(getUser().getClient());
-      Hibernate.initialize(getUser().getOrganization());
-      Hibernate.initialize(getUser().getDefaultOrganization());
-      Hibernate.initialize(getUser().getDefaultWarehouse());
-      Hibernate.initialize(getUser().getDefaultClient());
-      Hibernate.initialize(getUser().getDefaultRole());
-      Hibernate.initialize(getUser().getDefaultLanguage());
-      if (getUser().getBusinessPartner() != null) {
-        Hibernate.initialize(getUser().getBusinessPartner());
-      }
 
       organizationStructureProviderByClient = new HashMap<String, OrganizationStructureProvider>();
       acctSchemaStructureProviderByClient = new HashMap<String, AcctSchemaStructureProvider>();
@@ -1068,6 +1062,7 @@
   }
 
   public void setUser(User user) {
+    initializeFirstLevelProperties(user);
     this.user = user;
   }
 
@@ -1076,6 +1071,7 @@
   }
 
   public void setRole(Role role) {
+    initializeFirstLevelProperties(role);
     isAdministrator = (role.getId()).equals("0");
     isPortalRole = role.isForPortalUsers();
     isWebServiceEnabled = role.isWebServiceEnabled();
@@ -1265,6 +1261,7 @@
   }
 
   public void setWarehouse(Warehouse warehouse) {
+    initializeFirstLevelProperties(warehouse);
     this.warehouse = warehouse;
   }
 
@@ -1331,4 +1328,18 @@
     this.translationInstalled = translationInstalled;
   }
 
+  private void initializeFirstLevelProperties(BaseOBObject bob) {
+    if (bob == null) {
+      return;
+    }
+    Entity entity = bob.getEntity();
+    entity.getProperties().stream() //
+        .filter(property -> !property.isOneToMany()) //
+        .map(property -> bob.get(property.getName())) //
+        .filter(propertyValue -> !Hibernate.isInitialized(propertyValue)) //
+        .filter(BaseOBObject.class::isInstance) //
+        .map(BaseOBObject.class::cast) //
+        .forEach(Hibernate::initialize);
+  }
+
 }