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 74639edbf..76f723334 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,6 +29,7 @@ public class JNDIManagedRuntime implements ManagedRuntime { private String _tmLoc = "java:/TransactionManager"; + private static TransactionManager _tm; /** * Return the location of the {@link TransactionManager} in JNDI. @@ -44,13 +45,18 @@ public class JNDIManagedRuntime _tmLoc = name; } - public TransactionManager getTransactionManager() - throws Exception { - Context ctx = new InitialContext(); - try { - return (TransactionManager) ctx.lookup(_tmLoc); - } finally { - ctx.close(); + /** + * Return the cached TransactionManager instance. + */ + public TransactionManager getTransactionManager() throws Exception { + if (_tm == null) { + Context ctx = new InitialContext(); + try { + _tm = (TransactionManager) ctx.lookup(_tmLoc); + } finally { + ctx.close(); + } } - } + return _tm; + } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java index 41c39e0ed..b63db3320 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java @@ -64,7 +64,8 @@ public abstract class AbstractBrokerFactory // configuration private final OpenJPAConfiguration _conf; private transient boolean _readOnly = false; - private transient RuntimeException _closed = null; + private transient boolean _closed = false; + private transient RuntimeException _closedException = null; private Map _userObjects = null; // internal lock: spec forbids synchronization on this object @@ -267,7 +268,7 @@ public abstract class AbstractBrokerFactory * Returns true if this broker factory is closed. */ public boolean isClosed() { - return _closed != null; + return _closed; } public void close() { @@ -297,7 +298,10 @@ public abstract class AbstractBrokerFactory (_conf.getMetaDataRepositoryInstance()); _conf.close(); - _closed = new IllegalStateException(); + _closed = true; + Log log = _conf.getLog(OpenJPAConfiguration.LOG_RUNTIME); + if (log.isTraceEnabled()) + _closedException = new IllegalStateException(); } finally { unlock(); } @@ -546,12 +550,18 @@ public abstract class AbstractBrokerFactory } /** - * Throw an exception if the factory is closed. + * Throw an exception if the factory is closed. The exact message and + * content of the exception varies whether TRACE is enabled or not. */ private void assertOpen() { - if (_closed != null) - throw new InvalidStateException(_loc.get("closed-factory")). - setCause(_closed); + if (_closed) { + if (_closedException == null) // TRACE not enabled + throw new InvalidStateException(_loc + .get("closed-factory-notrace")); + else + throw new InvalidStateException(_loc.get("closed-factory")) + .setCause(_closedException); + } } //////////////////// 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 e080aa83a..42edeae43 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,6 +63,7 @@ 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; @@ -138,6 +139,9 @@ 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 @@ -215,7 +219,8 @@ public class BrokerImpl // status private int _flags = 0; - private RuntimeException _closed = null; + private boolean _closed = false; + private RuntimeException _closedException = null; // event managers private TransactionEventManager _transEventManager = null; @@ -1096,8 +1101,7 @@ public class BrokerImpl cls)); return PCRegistry.newObjectId(cls, (String) val); } - - if (meta.getObjectIdType().isAssignableFrom(val.getClass())) { + if (isAssignable(meta.getObjectIdType(), val.getClass())) { if (!meta.isOpenJPAIdentity() && meta.isObjectIdTypeShared()) return new ObjectId(cls, val); return val; @@ -1118,6 +1122,37 @@ 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. */ @@ -3969,11 +4004,11 @@ public class BrokerImpl /////////// public boolean isClosed() { - return _closed != null; + return _closed; } public boolean isCloseInvoked() { - return _closed != null || (_flags & FLAG_CLOSE_INVOKED) != 0; + return _closed || (_flags & FLAG_CLOSE_INVOKED) != 0; } public void close() { @@ -4055,8 +4090,10 @@ public class BrokerImpl _lm.close(); _store.close(); - _closed = new IllegalStateException(); _flags = 0; + _closed = true; + if (_log.isTraceEnabled()) + _closedException = new IllegalStateException(); if (err != null) throw err; @@ -4246,11 +4283,19 @@ public class BrokerImpl ///////// // Utils ///////// - + /** + * Throw an exception if the context is closed. The exact message and + * content of the exception varies whether TRACE is enabled or not. + */ public void assertOpen() { - if (_closed != null) - throw new InvalidStateException(_loc.get("closed"), _closed). - setFatal(true); + if (_closed) { + if (_closedException == null) // TRACE not enabled + throw new InvalidStateException(_loc.get("closed-notrace")) + .setFatal(true); + else + throw new InvalidStateException(_loc.get("closed"), + _closedException).setFatal(true); + } } public void assertActiveTransaction() { 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 b505c11fd..113efe2df 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,6 +36,8 @@ 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; @@ -58,6 +60,10 @@ 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. */ @@ -613,11 +619,37 @@ public class FetchConfigurationImpl } /** - * Whether either of the two types is assignable from the other. + * 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 c1, Class c2) { - return c1 != null && c2 != null - && (c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1)); + 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; } /** 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 99f367ede..b6432f78e 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,6 +17,10 @@ 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; + /** * Identity class extended by builtin OpenJPA identity objects. * @@ -31,6 +35,9 @@ public abstract class OpenJPAId // type has his based on the least-derived non-object class so that // user-given ids with non-exact types match ids with exact types private transient int _typeHash = 0; + // cache the types' generated hashcodes + private static ConcurrentReferenceHashMap _typeCache = + new ConcurrentReferenceHashMap(ReferenceMap.HARD, ReferenceMap.WEAK); protected OpenJPAId() { } @@ -82,13 +89,25 @@ public abstract class OpenJPAId */ protected abstract boolean idEquals(OpenJPAId other); + /** + * Generate the hashcode for this Id. Cache the type's generated hashcode + * so that it doesn't have to be generated each time. + */ public int hashCode() { if (_typeHash == 0) { - Class base = type; - while (base.getSuperclass() != null - && base.getSuperclass() != Object.class) - base = base.getSuperclass(); - _typeHash = base.hashCode(); + Integer typeHashInt = (Integer) _typeCache.get(type); + if (typeHashInt == null) { + Class base = type; + Class superclass = base.getSuperclass(); + while (superclass != null && superclass != Object.class) { + base = base.getSuperclass(); + superclass = base.getSuperclass(); + } + _typeHash = base.hashCode(); + _typeCache.put(type, new Integer(_typeHash)); + } else { + _typeHash = typeHashInt.intValue(); + } } return _typeHash ^ idHash(); } diff --git a/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties b/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties index afd0726d2..f86a47ff7 100644 --- a/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties +++ b/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties @@ -94,8 +94,13 @@ trans-active: The "{0}" transaction property cannot be set during an \ active: This operation cannot be performed while a Transaction is active. closed: The context has been closed. The stack trace at which the \ context was closed is held in the embedded exception. +closed-notrace: The context has been closed. The stack trace at which the \ + context was closed is available if Runtime=TRACE logging is enabled. closed-factory: The factory has been closed. The stack trace at \ which the factory was closed is held in the embedded exception. +closed-factory-notrace: The factory has been closed. The stack trace at \ + which the factory was closed is available if Runtime=TRACE logging is \ + enabled. non-trans-read: To perform reads on persistent data outside of a transaction, \ the "NontransactionalRead" property must be set on the Transaction. non-trans-write: To perform writes on persistent data outside of a \ diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ObjectValue.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ObjectValue.java index 163d5f0c7..a9c0675d1 100644 --- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ObjectValue.java +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ObjectValue.java @@ -17,6 +17,8 @@ package org.apache.openjpa.lib.conf; import org.apache.commons.lang.ObjectUtils; import org.apache.openjpa.lib.util.Localizer; +import org.apache.openjpa.lib.util.ReferenceMap; +import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap; /** * An object {@link Value}. @@ -28,6 +30,10 @@ public class ObjectValue extends Value { private static final Localizer _loc = Localizer.forPackage (ObjectValue.class); + // cache the types' classloader + private static ConcurrentReferenceHashMap _classloaderCache = + new ConcurrentReferenceHashMap(ReferenceMap.HARD, ReferenceMap.WEAK); + private Object _value = null; public ObjectValue(String prop) { @@ -81,10 +87,16 @@ public class ObjectValue extends Value { * Allow subclasses to instantiate additional plugins. This method does * not perform configuration. */ - public Object newInstance(String clsName, Class type, - Configuration conf, boolean fatal) { - return Configurations.newInstance(clsName, this, conf, - type.getClassLoader(), fatal); + public Object newInstance(String clsName, Class type, Configuration conf, + boolean fatal) { + ClassLoader cl = (ClassLoader) _classloaderCache.get(type); + if (cl == null) { + cl = type.getClassLoader(); + if (cl != null) { // System classloader is returned as null + _classloaderCache.put(type, cl); + } + } + return Configurations.newInstance(clsName, this, conf, cl, fatal); } public Class getValueType() {