diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/ee/JNDIManagedRuntime.java b/openjpa-kernel/src/main/java/org/apache/openjpa/ee/JNDIManagedRuntime.java index 76f723334..cfe5caf08 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/ee/JNDIManagedRuntime.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/ee/JNDIManagedRuntime.java @@ -29,7 +29,7 @@ public class JNDIManagedRuntime implements ManagedRuntime { private String _tmLoc = "java:/TransactionManager"; - private static TransactionManager _tm; + private TransactionManager _tm = null; /** * Return the location of the {@link TransactionManager} in JNDI. @@ -43,12 +43,14 @@ public class JNDIManagedRuntime */ public void setTransactionManagerName(String name) { _tmLoc = name; + _tm = null; // reset the cached TM } /** * Return the cached TransactionManager instance. */ public TransactionManager getTransactionManager() throws Exception { + if (_tm == null) { Context ctx = new InitialContext(); try { diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java index 42edeae43..8122267ce 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java @@ -63,7 +63,6 @@ import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.ReferenceHashMap; import org.apache.openjpa.lib.util.ReferenceHashSet; import org.apache.openjpa.lib.util.ReferenceMap; -import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap; import org.apache.openjpa.lib.util.concurrent.ReentrantLock; import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.FieldMetaData; @@ -75,6 +74,7 @@ import org.apache.openjpa.util.ApplicationIds; import org.apache.openjpa.util.CallbackException; import org.apache.openjpa.util.Exceptions; import org.apache.openjpa.util.GeneralException; +import org.apache.openjpa.util.ImplHelper; import org.apache.openjpa.util.InternalException; import org.apache.openjpa.util.InvalidStateException; import org.apache.openjpa.util.NoTransactionException; @@ -139,9 +139,6 @@ public class BrokerImpl private static final Localizer _loc = Localizer.forPackage(BrokerImpl.class); - // Cache for from/to type assignments - private static ConcurrentReferenceHashMap _assignableTypes = - new ConcurrentReferenceHashMap(ReferenceMap.HARD, ReferenceMap.WEAK); // the store manager in use; this may be a decorator such as a // data cache store manager around the native store manager @@ -1101,7 +1098,8 @@ public class BrokerImpl cls)); return PCRegistry.newObjectId(cls, (String) val); } - if (isAssignable(meta.getObjectIdType(), val.getClass())) { + if (ImplHelper.isAssignable(meta.getObjectIdType(), val.getClass())) + { if (!meta.isOpenJPAIdentity() && meta.isObjectIdTypeShared()) return new ObjectId(cls, val); return val; @@ -1122,37 +1120,6 @@ public class BrokerImpl } } - /** - * Cache from/to assignments to avoid Class.isAssignableFrom overhead - * @param from the target Class - * @param to the Class to test - * @return true if the "to" class could be assigned to "from" class - */ - private boolean isAssignable(Class from, Class to) { - boolean isAssignable; - ConcurrentReferenceHashMap assignableTo = - (ConcurrentReferenceHashMap) _assignableTypes.get(from); - - if (assignableTo != null) { // "to" cache exists... - isAssignable = (assignableTo.get(to) != null); - if (!isAssignable) { // not in the map yet... - isAssignable = from.isAssignableFrom(to); - if (isAssignable) { - assignableTo.put(to, new Object()); - } - } - } else { // no "to" cache yet... - isAssignable = from.isAssignableFrom(to); - if (isAssignable) { - assignableTo = new ConcurrentReferenceHashMap( - ReferenceMap.HARD, ReferenceMap.WEAK); - _assignableTypes.put(from, assignableTo); - assignableTo.put(to, new Object()); - } - } - return isAssignable; - } - /** * Create a new state manager for the given oid. */ diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java index 113efe2df..fb17730c2 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java @@ -36,11 +36,10 @@ import org.apache.openjpa.lib.rop.ResultObjectProvider; import org.apache.openjpa.lib.rop.SimpleResultList; import org.apache.openjpa.lib.rop.WindowResultList; import org.apache.openjpa.lib.util.Localizer; -import org.apache.openjpa.lib.util.ReferenceMap; -import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap; import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.FetchGroup; import org.apache.openjpa.meta.FieldMetaData; +import org.apache.openjpa.util.ImplHelper; import org.apache.openjpa.util.InternalException; import org.apache.openjpa.util.NoTransactionException; import org.apache.openjpa.util.UserException; @@ -60,10 +59,6 @@ public class FetchConfigurationImpl private static final Localizer _loc = Localizer.forPackage (FetchConfigurationImpl.class); - // Cache the from/to isAssignable invocations - private static ConcurrentReferenceHashMap _assignableTypes = - new ConcurrentReferenceHashMap(ReferenceMap.HARD, ReferenceMap.WEAK); - /** * Configurable state shared throughout a traversal chain. */ @@ -563,7 +558,7 @@ public class FetchConfigurationImpl // see if there's a previous limit int avail = Integer.MIN_VALUE; for (FetchConfigurationImpl f = this; f != null; f = f._parent) { - if (isAssignable(type, f._fromType)) { + if (ImplHelper.isAssignable(type, f._fromType)) { avail = f._availableRecursion; if (traverse) avail = reduce(avail); @@ -588,15 +583,15 @@ public class FetchConfigurationImpl max = cur; } // reduce max if we're traversing a self-type relation - if (traverse && max != Integer.MIN_VALUE - && isAssignable(meta.getDescribedType(), type)) + if (traverse && max != Integer.MIN_VALUE + && ImplHelper.isAssignable(meta.getDescribedType(), type)) max = reduce(max); // take min/defined of previous avail and fetch group max if (avail == Integer.MIN_VALUE && max == Integer.MIN_VALUE) { int def = FetchGroup.RECURSION_DEPTH_DEFAULT; - return (traverse && isAssignable(meta.getDescribedType(), type)) - ? def - 1 : def; + return (traverse && ImplHelper.isAssignable( + meta.getDescribedType(), type)) ? def - 1 : def; } if (avail == Integer.MIN_VALUE || avail == FetchGroup.DEPTH_INFINITE) return max; @@ -618,40 +613,6 @@ public class FetchConfigurationImpl return null; } - /** - * Whether either of the two types is assignable from the other. Optimize - * for the repeat calls with similar parameters by caching the from/to - * type parameters. - */ - private static boolean isAssignable(Class from, Class to) { - boolean isAssignable; - - if (from == null || to == null) - return false; - ConcurrentReferenceHashMap assignableTo = - (ConcurrentReferenceHashMap) _assignableTypes.get(from); - - if (assignableTo != null) { // "to" cache exists... - isAssignable = (assignableTo.get(to) != null); - if (!isAssignable) { // not in the map yet... - isAssignable = from.isAssignableFrom(to); - if (isAssignable) { - assignableTo.put(to, new Object()); - } - } - } else { // no "to" cache yet... - isAssignable = from.isAssignableFrom(to); - if (isAssignable) { - assignableTo = new ConcurrentReferenceHashMap( - ReferenceMap.HARD, ReferenceMap.WEAK); - _assignableTypes.put(from, assignableTo); - assignableTo.put(to, new Object()); - } - } - - return isAssignable; - } - /** * Reduce the given logical depth by 1. */ diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java index 1392dde7c..415c07bb9 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java @@ -20,8 +20,8 @@ import java.util.BitSet; import java.util.Collection; import java.util.Collections; import java.util.Iterator; +import java.util.Map; -import org.apache.commons.lang.StringUtils; import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.kernel.FetchConfiguration; import org.apache.openjpa.kernel.LockManager; @@ -30,7 +30,10 @@ import org.apache.openjpa.kernel.PCState; import org.apache.openjpa.kernel.StoreContext; import org.apache.openjpa.kernel.StoreManager; import org.apache.openjpa.lib.util.Closeable; +import org.apache.openjpa.lib.util.ReferenceMap; import org.apache.openjpa.lib.util.UUIDGenerator; +import org.apache.openjpa.lib.util.concurrent.ConcurrentHashMap; +import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap; import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.meta.JavaTypes; @@ -46,6 +49,10 @@ import org.apache.openjpa.meta.ValueStrategies; */ public class ImplHelper { + // Cache for from/to type assignments + private static ConcurrentReferenceHashMap _assignableTypes = + new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD); + /** * Helper for store manager implementations. This method simply delegates * to the proper singular method for each state manager. @@ -187,4 +194,34 @@ public class ImplHelper { public static boolean isManageable(Object instance) { return instance instanceof PersistenceCapable; } + + /** + * Returns true if the referenced "to" class is assignable to the "from" + * class. This helper method utilizes a cache to help avoid the overhead + * of the Class.isAssignableFrom() method. + * + * @param from target class instance to be checked for assignability + * @param to second class instance to be checked for assignability + * @return true if the "to" class is assignable to the "from" class + */ + public static boolean isAssignable(Class from, Class to) { + Boolean isAssignable = null; + if (from == null || to == null) + return false; + Map assignableTo = (Map) _assignableTypes.get(from); + + if (assignableTo == null) { // "to" cache doesn't exist, so create it... + assignableTo = new ConcurrentHashMap(); + _assignableTypes.put(from, assignableTo); + } else { // "to" cache exists... + isAssignable = (Boolean) assignableTo.get(to); + } + + if (isAssignable == null) {// we don't have a record of this pair... + isAssignable = new Boolean(from.isAssignableFrom(to)); + assignableTo.put(to, isAssignable); + } + + return isAssignable.booleanValue(); + } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java index b6432f78e..f2c081b20 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java @@ -17,7 +17,6 @@ package org.apache.openjpa.util; import java.io.Serializable; -import org.apache.openjpa.lib.util.ReferenceHashSet; import org.apache.openjpa.lib.util.ReferenceMap; import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap; @@ -37,7 +36,7 @@ public abstract class OpenJPAId private transient int _typeHash = 0; // cache the types' generated hashcodes private static ConcurrentReferenceHashMap _typeCache = - new ConcurrentReferenceHashMap(ReferenceMap.HARD, ReferenceMap.WEAK); + new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD); protected OpenJPAId() { }