Author: rmannibucau
Date: Tue Jan 1 20:21:15 2013
New Revision: 1427549
URL: http://svn.apache.org/viewvc?rev=1427549&view=rev
Log:
some caching - on isdebugenabled on our logger + method resolution in jaxws
invocation + skipping reflection to get threadname in tomee from ContextBindings
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Logger.java
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/ejb/EjbMethodInvoker.java
openejb/trunk/openejb/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatThreadContextListener.java
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java?rev=1427549&r1=1427548&r2=1427549&view=diff
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java
(original)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java
Tue Jan 1 20:21:15 2013
@@ -34,8 +34,6 @@ import org.apache.openejb.core.webservic
import org.apache.openejb.monitoring.StatsInterceptor;
import org.apache.openejb.spi.SecurityService;
import org.apache.openejb.util.Duration;
-import org.apache.openejb.util.LogCategory;
-import org.apache.openejb.util.Logger;
import org.apache.xbean.finder.ClassFinder;
import javax.ejb.ConcurrentAccessTimeoutException;
@@ -46,10 +44,10 @@ import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import javax.interceptor.AroundInvoke;
import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import static org.apache.openejb.core.transaction.EjbTransactionUtil.*;
@@ -63,6 +61,8 @@ public class SingletonContainer implemen
private HashMap<String, BeanContext> deploymentRegistry = new
HashMap<String, BeanContext>();
+ private final ConcurrentMap<Class<?>, List<Method>> interceptorCache = new
ConcurrentHashMap<Class<?>, List<Method>>();
+
private Object containerID = null;
private SecurityService securityService;
private Duration accessTimeout;
@@ -331,19 +331,33 @@ public class SingletonContainer implemen
if (interceptor == null) throw new
IllegalArgumentException("Interceptor instance is null.");
+ final Class<?> interceptorClass = interceptor.getClass();
+
// Add the webservice interceptor to the list of interceptor instances
Map<String, Object> interceptors = new HashMap<String,
Object>(instance.interceptors);
{
- interceptors.put(interceptor.getClass().getName(), interceptor);
+ interceptors.put(interceptorClass.getName(), interceptor);
}
// Create an InterceptorData for the webservice interceptor to the
list of interceptorDatas for this method
List<InterceptorData> interceptorDatas = new
ArrayList<InterceptorData>();
{
- InterceptorData providerData = new
InterceptorData(interceptor.getClass());
- ClassFinder finder = new ClassFinder(interceptor.getClass());
-
providerData.getAroundInvoke().addAll(finder.findAnnotatedMethods(AroundInvoke.class));
- interceptorDatas.add(providerData);
+ final InterceptorData providerData = new
InterceptorData(interceptorClass);
+
+ List<Method> aroundInvokes =
interceptorCache.get(interceptorClass);
+ if (aroundInvokes == null) {
+ aroundInvokes = new
ClassFinder(interceptorClass).findAnnotatedMethods(AroundInvoke.class);
+ if (SingletonContainer.class.getClassLoader() ==
interceptorClass.getClassLoader()) { // use cache only for server classes
+ final List<Method> value = new
CopyOnWriteArrayList<Method>(aroundInvokes);
+ aroundInvokes =
interceptorCache.putIfAbsent(interceptorClass, value); // ensure it to be
thread safe
+ if (aroundInvokes == null) {
+ aroundInvokes = value;
+ }
+ }
+ }
+
+ providerData.getAroundInvoke().addAll(aroundInvokes);
+ interceptorDatas.add(0, providerData);
interceptorDatas.addAll(beanContext.getMethodInterceptors(runMethod));
}
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java?rev=1427549&r1=1427548&r2=1427549&view=diff
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
(original)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
Tue Jan 1 20:21:15 2013
@@ -26,6 +26,9 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import javax.ejb.EJBAccessException;
import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;
@@ -49,8 +52,6 @@ import org.apache.openejb.core.timer.Ejb
import org.apache.openejb.core.transaction.TransactionPolicy;
import org.apache.openejb.core.webservices.AddressingSupport;
import org.apache.openejb.core.webservices.NoAddressingSupport;
-import org.apache.openejb.monitoring.LocalMBeanServer;
-import org.apache.openejb.monitoring.ManagedMBean;
import org.apache.openejb.monitoring.StatsInterceptor;
import org.apache.openejb.spi.SecurityService;
import org.apache.openejb.util.Duration;
@@ -61,6 +62,7 @@ import org.apache.xbean.finder.ClassFind
* @org.apache.xbean.XBean element="statelessContainer"
*/
public class StatelessContainer implements org.apache.openejb.RpcContainer {
+ private final ConcurrentMap<Class<?>, List<Method>> interceptorCache = new
ConcurrentHashMap<Class<?>, List<Method>>();
private StatelessInstanceManager instanceManager;
@@ -284,6 +286,8 @@ public class StatelessContainer implemen
// of our stack.
Object interceptor = args[1];
+ final Class<?> interceptorClass = interceptor.getClass();
+
// Add the webservice interceptor to the list of interceptor instances
Map<String, Object> interceptors = new HashMap<String,
Object>(instance.interceptors);
@@ -294,10 +298,21 @@ public class StatelessContainer implemen
// Create an InterceptorData for the webservice interceptor to the
list of interceptorDatas for this method
List<InterceptorData> interceptorDatas = new
ArrayList<InterceptorData>();
{
- InterceptorData providerData = new
InterceptorData(interceptor.getClass());
- ClassFinder finder = new ClassFinder(interceptor.getClass());
-
providerData.getAroundInvoke().addAll(finder.findAnnotatedMethods(AroundInvoke.class));
-// interceptorDatas.add(providerData);
+ final InterceptorData providerData = new
InterceptorData(interceptorClass);
+
+ List<Method> aroundInvokes =
interceptorCache.get(interceptorClass);
+ if (aroundInvokes == null) {
+ aroundInvokes = new
ClassFinder(interceptorClass).findAnnotatedMethods(AroundInvoke.class);
+ if (StatelessContainer.class.getClassLoader() ==
interceptorClass.getClassLoader()) { // use cache only for server classes
+ final List<Method> value = new
CopyOnWriteArrayList<Method>(aroundInvokes);
+ aroundInvokes =
interceptorCache.putIfAbsent(interceptorClass, aroundInvokes); // ensure it to
be thread safe
+ if (aroundInvokes == null) {
+ aroundInvokes = value;
+ }
+ }
+ }
+
+ providerData.getAroundInvoke().addAll(aroundInvokes);
interceptorDatas.add(0, providerData);
interceptorDatas.addAll(beanContext.getMethodInterceptors(runMethod));
}
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Logger.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Logger.java?rev=1427549&r1=1427548&r2=1427549&view=diff
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Logger.java
(original)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/util/Logger.java
Tue Jan 1 20:21:15 2013
@@ -249,11 +249,13 @@ public class Logger {
private final LogCategory category;
private final LogStream logStream;
private final String baseName;
+ private final boolean debug;
public Logger(final LogCategory category, final LogStream logStream, final
String baseName) {
this.category = category;
this.logStream = logStream;
this.baseName = baseName;
+ this.debug = logStream.isDebugEnabled(); // commonly used and can be
slow so cache it
}
public static Logger getInstance(final LogCategory category, final Class
clazz) {
@@ -344,7 +346,7 @@ public class Logger {
}
public boolean isDebugEnabled() {
- return logStream.isDebugEnabled();
+ return debug;
}
public boolean isErrorEnabled() {
Modified:
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/ejb/EjbMethodInvoker.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/ejb/EjbMethodInvoker.java?rev=1427549&r1=1427548&r2=1427549&view=diff
==============================================================================
---
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/ejb/EjbMethodInvoker.java
(original)
+++
openejb/trunk/openejb/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/ejb/EjbMethodInvoker.java
Tue Jan 1 20:21:15 2013
@@ -17,14 +17,6 @@
*/
package org.apache.openejb.server.cxf.ejb;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Map;
-
-import javax.interceptor.InvocationContext;
-import javax.xml.ws.WebFault;
-import javax.xml.ws.handler.MessageContext.Scope;
-
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.AbstractJAXWSMethodInvoker;
import org.apache.cxf.jaxws.context.WebServiceContextImpl;
@@ -39,6 +31,15 @@ import org.apache.openejb.RpcContainer;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
+import javax.interceptor.InvocationContext;
+import javax.xml.ws.WebFault;
+import javax.xml.ws.handler.MessageContext.Scope;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
public class EjbMethodInvoker extends AbstractJAXWSMethodInvoker {
private static final Logger log = Logger.getInstance(LogCategory.CXF,
EjbMethodInvoker.class);
@@ -115,7 +116,7 @@ public class EjbMethodInvoker extends Ab
Class callInterface = this.beanContext
.getServiceEndpointInterface();
- method = getMostSpecificMethod(method, callInterface);
+ method = getMostSpecificMethod(beanContext, method, callInterface);
Object res = container.invoke(
this.beanContext.getDeploymentID(),
InterfaceType.SERVICE_ENDPOINT, callInterface, method,
@@ -162,6 +163,31 @@ public class EjbMethodInvoker extends Ab
}
}
+ // seems the cxf impl is slow so caching it in BeanContext
+ private Method getMostSpecificMethod(final BeanContext beanContext, final
Method method, final Class callInterface) {
+ MostSpecificMethodCache cache =
beanContext.get(MostSpecificMethodCache.class);
+
+ if (cache == null) {
+ synchronized (beanContext) { // no need to use a lock IMO here
+ cache = beanContext.get(MostSpecificMethodCache.class);
+ if (cache == null) {
+ cache = new MostSpecificMethodCache();
+ beanContext.set(MostSpecificMethodCache.class, cache);
+ }
+ }
+ }
+
+ final MostSpecificMethodKey key = new
MostSpecificMethodKey(callInterface, method);
+
+ Method m = cache.methods.get(key);
+ if (m == null) { // no need of more synchro since Method will be
resolved to the same instance
+ m = getMostSpecificMethod(method, callInterface);
+ cache.methods.putIfAbsent(key, m);
+ }
+
+ return m;
+ }
+
public Object directEjbInvoke(Exchange exchange, Method m,
List<Object> params) throws Exception {
Object[] paramArray;
@@ -172,4 +198,48 @@ public class EjbMethodInvoker extends Ab
}
return performInvocation(exchange, null, m, paramArray);
}
+
+ public static class MostSpecificMethodCache { // just a wrapper to put in
BeanContext without conflict
+ public final ConcurrentMap<MostSpecificMethodKey, Method> methods =
new ConcurrentHashMap<MostSpecificMethodKey, Method>();
+ }
+
+ public static class MostSpecificMethodKey {
+ public final Class<?> ejbInterface;
+ public final Method method;
+ private int hashCode;
+
+ public MostSpecificMethodKey(final Class<?> ejbInterface, final Method
method) {
+ this.ejbInterface = ejbInterface;
+ this.method = method;
+
+ // this class exists for map usage so simply precalculate hashcode
+ hashCode = ejbInterface != null ? ejbInterface.hashCode() : 0;
+ hashCode = 31 * hashCode + (method != null ? method.hashCode() :
0);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final MostSpecificMethodKey that = (MostSpecificMethodKey) o;
+
+ if (!(ejbInterface != null ?
!ejbInterface.equals(that.ejbInterface) : that.ejbInterface != null)) {
+ if (!(method != null ? !method.equals(that.method) :
that.method != null)) {
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+ }
}
\ No newline at end of file
Modified:
openejb/trunk/openejb/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatThreadContextListener.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatThreadContextListener.java?rev=1427549&r1=1427548&r2=1427549&view=diff
==============================================================================
---
openejb/trunk/openejb/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatThreadContextListener.java
(original)
+++
openejb/trunk/openejb/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatThreadContextListener.java
Tue Jan 1 20:21:15 2013
@@ -24,8 +24,10 @@ import org.apache.openejb.util.LogCatego
import org.apache.openejb.util.Logger;
import javax.naming.NamingException;
+import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.Hashtable;
/**
* Tomcat thread context listener.
@@ -48,24 +50,23 @@ public class TomcatThreadContextListener
* getThreadName method in class ContextBindings
*/
protected Method method;
+ private Hashtable<Thread, Object> threadNameBindings;
/**
* Creates a new instance.
*/
public TomcatThreadContextListener() {
ContextBindings.bindContext(OPENEJB_CONTEXT, new OpenEJBContext());
- boolean accessible = false;
try {
// someone decided to make the getThreadName package protected so
we have to use reflection
method = ContextBindings.class.getDeclaredMethod("getThreadName");
-// accessible = method.isAccessible();
method.setAccessible(true);
- } catch (NoSuchMethodException e) {
+
+ final Field threadNameBindingsField =
ContextBindings.class.getDeclaredField("threadNameBindings");
+ threadNameBindingsField.setAccessible(true);
+ threadNameBindings = (Hashtable<Thread, Object>)
threadNameBindingsField.get(null);
+ } catch (Exception e) {
logger.error("Expected ContextBinding to have the method
getThreadName()");
-// } finally {
-// if (!accessible) {
-// method.setAccessible(accessible);
-// }
}
}
@@ -78,13 +79,14 @@ public class TomcatThreadContextListener
Data data = new Data(getThreadName());
newContext.set(Data.class, data);
} catch (NamingException ignored) {
+ // no-op
}
// set the new context
try {
- ContextBindings.bindThread(OPENEJB_CONTEXT);
+ ContextBindings.bindThread(OPENEJB_CONTEXT, null);
} catch (NamingException e) {
- ContextBindings.unbindContext(OPENEJB_CONTEXT);
+ ContextBindings.unbindContext(OPENEJB_CONTEXT, null);
throw new IllegalArgumentException("Unable to bind OpenEJB enc");
}
}
@@ -94,13 +96,13 @@ public class TomcatThreadContextListener
*/
public void contextExited(ThreadContext exitedContext, ThreadContext
reenteredContext) {
// unbind the new context
- ContextBindings.unbindThread(OPENEJB_CONTEXT);
+ ContextBindings.unbindThread(OPENEJB_CONTEXT, null);
// attempt to restore the old context
Data data = exitedContext.get(Data.class);
if (data != null && data.oldContextName != null) {
try {
- ContextBindings.bindThread(data.oldContextName);
+ ContextBindings.bindThread(data.oldContextName, null);
} catch (NamingException e) {
logger.error("Exception in method contextExited", e);
}
@@ -115,8 +117,14 @@ public class TomcatThreadContextListener
*/
private Object getThreadName() throws NamingException {
try {
- Object threadName = method.invoke(null);
- return threadName;
+ return threadNameBindings.get(Thread.currentThread());
+ } catch (Exception e) {
+ // no-op: try the old implementation
+ }
+
+ // this implementation is probably better but slower
+ try {
+ return method.invoke(null);
} catch (InvocationTargetException e) {
// if it's a naming exception, it should be treated by the caller