Force deferred locks persistence query property (#1007)

New "eclipselink.cache.query-force-deferred-locks" property force all queries and relationships
 to use deferred lock strategy during object building and L2 cache population.
 It helps to solve dead lock issues in multithreaded environments where one L2 cache is accessed/populated
 by multiple threads.
 Threads create objects from the same object graph but from different starting point.
 Dead lock issue should happens in large object graphs and entities connected with relationships with EAGER fetch strategy.

Signed-off-by: Radek Felcman <radek.felcman@oracle.com>
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/PersistenceUnitProperties.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/PersistenceUnitProperties.java
index 594d80e..9b8f158 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/PersistenceUnitProperties.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/PersistenceUnitProperties.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 1998, 2019 IBM Corporation. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
@@ -1482,6 +1482,18 @@
      */
     public static final String DATABASE_EVENT_LISTENER = "eclipselink.cache.database-event-listener";
 
+    /**
+     * The "<code>eclipselink.cache.query-force-deferred-locks</code>" property force all queries and relationships
+     * to use deferred lock strategy during object building and L2 cache population.
+     * <p>
+     * <b>Allowed Values</b> (String)<b>:</b>
+     * <ul>
+     * <li>"<code>false</code>" (DEFAULT) - use use mixed object cache locking strategy
+     * <li>"<code>true</code>" - use deferred locking strategy all queries and relationships
+     * </ul>
+     */
+    public static final String CACHE_QUERY_FORCE_DEFERRED_LOCKS = "eclipselink.cache.query-force-deferred-locks";
+
     // Customizations properties
 
     // Logging properties
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/queries/ObjectBuildingQuery.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/queries/ObjectBuildingQuery.java
index 2213200..6e891da 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/queries/ObjectBuildingQuery.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/queries/ObjectBuildingQuery.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -608,7 +608,11 @@
      * with an object the acquires deferred locks behaves the same as its owner
      */
     public void setRequiresDeferredLocks(boolean cascadeDeferredLocks) {
-        this.requiresDeferredLocks = Boolean.valueOf(cascadeDeferredLocks);
+        if (session != null && session.getProject().isQueryCacheForceDeferredLocks()) {
+            this.requiresDeferredLocks = true;
+        } else {
+            this.requiresDeferredLocks = Boolean.valueOf(cascadeDeferredLocks);
+        }
     }
 
     /**
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/sessions/Project.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/sessions/Project.java
index 3281fac..88ff19d 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/sessions/Project.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/sessions/Project.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -190,6 +190,9 @@
     protected Collection<String> classNamesForWeaving;
     protected Collection<String> structConverters;
 
+     /** Force all queries and relationships to use deferred lock strategy during object building and L2 cache population. */
+    protected boolean queryCacheForceDeferredLocks = false;
+
     /**
      * PUBLIC:
      * Create a new project.
@@ -248,6 +251,22 @@
 
     /**
      * PUBLIC:
+     * Get property to Force all queries and relationships to use deferred lock strategy during object building and L2 cache population.
+     */
+    public boolean isQueryCacheForceDeferredLocks() {
+        return queryCacheForceDeferredLocks;
+    }
+
+    /**
+     * PUBLIC:
+     * Set property to Force all queries and relationships to use deferred lock strategy during object building and L2 cache population.
+     * By default there is false value - use use mixed object cache locking strategy (depends on relationship and fetch type) */
+    public void setQueryCacheForceDeferredLocks(boolean queryCacheForceDeferredLocks) {
+        this.queryCacheForceDeferredLocks = queryCacheForceDeferredLocks;
+    }
+
+    /**
+     * PUBLIC:
      * Return the default setting for configuring if dates and calendars are mutable.
      * Mutable means that changes to the date's year/month/day are detected.
      * By default they are treated as not mutable.
diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java
index 597c838..5ddecb3 100644
--- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java
+++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerSetupImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 1998, 2019 IBM Corporation. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
@@ -1494,6 +1494,12 @@
         if ((queryCache != null) && queryCache.equalsIgnoreCase("true")) {
             session.getProject().setDefaultQueryResultsCachePolicy(new QueryResultsCachePolicy());
         }
+        String queryCacheForceDeferredLocks = getConfigPropertyAsStringLogDebug(PersistenceUnitProperties.CACHE_QUERY_FORCE_DEFERRED_LOCKS, m, session);
+        if ((queryCacheForceDeferredLocks != null) && queryCacheForceDeferredLocks.equalsIgnoreCase("true")) {
+            session.getProject().setQueryCacheForceDeferredLocks(true);
+        } else {
+            session.getProject().setQueryCacheForceDeferredLocks(false);
+        }
 
         Map typeMap = PropertiesHandler.getPrefixValuesLogDebug(PersistenceUnitProperties.CACHE_TYPE_, m, session);
         Map sizeMap = PropertiesHandler.getPrefixValuesLogDebug(PersistenceUnitProperties.CACHE_SIZE_, m, session);