Author: dblevins
Date: Mon May 10 00:34:42 2010
New Revision: 942636
URL: http://svn.apache.org/viewvc?rev=942636&view=rev
Log:
OPENEJB-1275: JMX: EJB Method invocations
Added:
openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/Monitor.java
(with props)
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ManagedCollection.java
(with props)
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MethodScratchPad.java
(with props)
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/StatsInterceptor.java
(with props)
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/Managed.java
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ManagedMBean.java
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ScratchPad.java
Added:
openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/Monitor.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/Monitor.java?rev=942636&view=auto
==============================================================================
---
openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/Monitor.java
(added)
+++
openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/Monitor.java
Mon May 10 00:34:42 2010
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openejb.api;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Annotation that matches the <ejb-deployment> element in the openejb-jar.xml
file
+ */
+...@target({ElementType.TYPE, ElementType.METHOD})
+...@retention(RetentionPolicy.RUNTIME)
+public @interface Monitor {
+
+ int sample() default 2000;
+
+}
Propchange:
openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/Monitor.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/Managed.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/Managed.java?rev=942636&r1=942635&r2=942636&view=diff
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/Managed.java
(original)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/Managed.java
Mon May 10 00:34:42 2010
@@ -26,4 +26,4 @@ import java.lang.annotation.Target;
public @interface Managed {
String description() default "";
boolean append() default false;
-}
\ No newline at end of file
+}
Added:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ManagedCollection.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ManagedCollection.java?rev=942636&view=auto
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ManagedCollection.java
(added)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ManagedCollection.java
Mon May 10 00:34:42 2010
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openejb.monitoring;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+...@retention(RetentionPolicy.RUNTIME)
+...@target({ElementType.METHOD, ElementType.FIELD})
+public @interface ManagedCollection {
+ String description() default "";
+ String key() default "";
+ boolean append() default false;
+ Class<?> type();
+}
Propchange:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ManagedCollection.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ManagedMBean.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ManagedMBean.java?rev=942636&r1=942635&r2=942636&view=diff
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ManagedMBean.java
(original)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ManagedMBean.java
Mon May 10 00:34:42 2010
@@ -17,66 +17,136 @@
package org.apache.openejb.monitoring;
import org.apache.xbean.finder.ClassFinder;
+import org.apache.xbean.propertyeditor.PropertyEditors;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
+import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
-import javax.management.AttributeNotFoundException;
+import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
-import javax.management.ReflectionException;
-import javax.management.Attribute;
-import javax.management.InvalidAttributeValueException;
-import javax.management.AttributeList;
import javax.management.MBeanInfo;
-import javax.management.MBeanConstructorInfo;
-import javax.management.MBeanOperationInfo;
import javax.management.MBeanNotificationInfo;
-import java.util.List;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.ReflectionException;
+import javax.management.MBeanFeatureInfo;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.annotation.Annotation;
import java.util.ArrayList;
-import java.util.Map;
-import java.util.HashMap;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
/**
* @version $Rev$ $Date$
-*/
+ */
class ManagedMBean implements DynamicMBean {
private final List<MBeanAttributeInfo> attributes = new
ArrayList<MBeanAttributeInfo>();
- private final Map<String, Member> map = new HashMap<String, Member>();
+ private final List<MBeanOperationInfo> operations = new
ArrayList<MBeanOperationInfo>();
+ private final Map<String, Member> attributesMap = new HashMap<String,
Member>();
+ private final Map<String, MethodMember> operationsMap = new
HashMap<String, MethodMember>();
+ private final List<Member> dynamic = new ArrayList<Member>();
+
+ private Pattern includes = Pattern.compile("");
+ private Pattern excludes = Pattern.compile("");
+ private boolean filterAttributes;
+ private MBeanParameterInfo excludeInfo;
+ private MBeanParameterInfo includeInfo;
ManagedMBean(Object managed) {
- scan(managed, "");
+ this(managed, "");
+
+ try {
+ Method method = this.getClass().getMethod("setAttributesFilter",
String.class, String.class);
+
+ String description = "Filters the attributes that show up in the
MBeanInfo." +
+ " The exclude is applied first, then any attributes that
match the " +
+ "include are re-added. It may be required to disconnect
and reconnect " +
+ "the JMX console to force a refresh of the MBeanInfo";
+
+ excludeInfo = new MBeanParameterInfo("excludeRegex",
"java.lang.String", "\"" + excludes.pattern() + "\"");
+ includeInfo = new MBeanParameterInfo("includeRegex",
"java.lang.String", "\"" + includes.pattern() + "\"");
+ MBeanOperationInfo filterOperation = new
MBeanOperationInfo("FilterAttributes", description, new MBeanParameterInfo[]{
+ excludeInfo,
+ includeInfo,
+ }, "void", 3);
+ operations.add(filterOperation);
+ operationsMap.put(filterOperation.getName(), new
MethodMember(method, this, ""));
- for (Member member : map.values()) {
+ filterAttributes = true;
+ } catch (NoSuchMethodException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ ManagedMBean(Object managed, String prefix) {
+ scan(managed, prefix);
+
+ for (Member member : attributesMap.values()) {
attributes.add(new MBeanAttributeInfo(member.getName(),
member.getType().getName(), "", true, false, false));
}
- Collections.sort(attributes, new Comparator<MBeanAttributeInfo>(){
+ for (Member member : operationsMap.values()) {
+ MBeanOperationInfo op = new MBeanOperationInfo("", ((MethodMember)
member).getter);
+ operations.add(new MBeanOperationInfo(member.getName(), "",
op.getSignature(), op.getReturnType(), op.getImpact()));
+ }
+ filterAttributes = true;
+ excludeInfo = new MBeanParameterInfo("excludeRegex",
"java.lang.String", "\"" + excludes.pattern() + "\"");
+ includeInfo = new MBeanParameterInfo("includeRegex",
"java.lang.String", "\"" + includes.pattern() + "\"");
+ }
+
+ private void sortAttributes(List<MBeanAttributeInfo> attributes) {
+ Collections.sort(attributes, new Comparator<MBeanAttributeInfo>() {
public int compare(MBeanAttributeInfo o1, MBeanAttributeInfo o2) {
return o1.getName().compareTo(o2.getName());
}
});
}
- private void scan(Object managed, String prefix) {
- ClassFinder finder = new ClassFinder(managed.getClass());
+ private void sortOperations(List<MBeanOperationInfo> operations) {
+ Collections.sort(operations, new Comparator<MBeanOperationInfo>() {
+ public int compare(MBeanOperationInfo o1, MBeanOperationInfo o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ });
+ }
+
+ private void scan(Object target, String prefix) {
+ ClassFinder finder = new ClassFinder(target.getClass());
List<Field> fields = finder.findAnnotatedFields(Managed.class);
for (Field field : fields) {
- scan(new FieldMember(field, managed, prefix));
+ attribute(new FieldMember(field, target, prefix));
+ }
+
+ List<Method> managed = finder.findAnnotatedMethods(Managed.class);
+ for (Method method : managed) {
+ MethodMember member = new MethodMember(method, target, prefix);
+ if (!method.getName().matches("(get|is)[A-Z_].*")) {
+ operationsMap.put(member.getName(), member);
+ } else {
+ attribute(new MethodMember(method, target, prefix));
+ }
}
- List<Method> methods = finder.findAnnotatedMethods(Managed.class);
- for (Method method : methods) {
- scan(new MethodMember(method, managed, prefix));
+ List<Method> collections =
finder.findAnnotatedMethods(ManagedCollection.class);
+ for (Method method : collections) {
+ dynamic.add(new MethodMember(method, target, prefix));
}
}
- private void scan(Member member) {
+ private void attribute(Member member) {
Class<?> type = member.getType();
Managed managed = type.getAnnotation(Managed.class);
@@ -91,13 +161,13 @@ class ManagedMBean implements DynamicMBe
e.printStackTrace();
}
} else {
- map.put(member.getName(), member);
+ attributesMap.put(member.getName(), member);
}
}
public Object getAttribute(String s) throws AttributeNotFoundException,
MBeanException, ReflectionException {
try {
- Member member = map.get(s);
+ Member member = attributesMap.get(s);
if (member == null) throw new AttributeNotFoundException(s);
@@ -127,12 +197,91 @@ class ManagedMBean implements DynamicMBe
return new AttributeList();
}
- public Object invoke(String s, Object[] objects, String[] strings) throws
MBeanException, ReflectionException {
- return null;
+ public Object invoke(String operation, Object[] args, String[] types)
throws MBeanException, ReflectionException {
+ MethodMember member = operationsMap.get(operation);
+ Method method = member.getter;
+
+ for (int i = 0; i < method.getParameterTypes().length; i++) {
+ Object value = args[i];
+ Class<?> expectedType = method.getParameterTypes()[i];
+ if (value instanceof String && (expectedType != Object.class)) {
+ String stringValue = (String) value;
+ value = PropertyEditors.getValue(expectedType, stringValue);
+ }
+ args[i] = value;
+ }
+
+ try {
+ return method.invoke(member.target, args);
+ } catch (InvocationTargetException e) {
+ throw new ReflectionException((Exception)e.getCause());
+ } catch (Exception e) {
+ throw new ReflectionException(e);
+ }
}
public MBeanInfo getMBeanInfo() {
- return new MBeanInfo(this.getClass().getName(), "The description",
attributes.toArray(new MBeanAttributeInfo[0]), new MBeanConstructorInfo[0], new
MBeanOperationInfo[0], new MBeanNotificationInfo[0]);
+
+ List<MBeanAttributeInfo> attributes = new
ArrayList<MBeanAttributeInfo>(this.attributes);
+ List<MBeanOperationInfo> operations = new
ArrayList<MBeanOperationInfo>(this.operations);
+
+ for (Member member : dynamic) {
+ try {
+ ManagedCollection managedCollection =
member.getAnnotation(ManagedCollection.class);
+ Collection collection = (Collection) member.get();
+ for (Object o : collection) {
+ try {
+ Field field =
o.getClass().getDeclaredField(managedCollection.key());
+ field.setAccessible(true);
+ Object key = field.get(o);
+ ManagedMBean bean = new ManagedMBean(o,
key.toString());
+ for (MBeanAttributeInfo info :
bean.getMBeanInfo().getAttributes()) {
+ attributes.add(info);
+ }
+ for (MBeanOperationInfo info :
bean.getMBeanInfo().getOperations()) {
+ operations.add(info);
+ }
+ attributesMap.putAll(bean.attributesMap);
+ operationsMap.putAll(bean.operationsMap);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ sortOperations(operations);
+ sortAttributes(attributes);
+
+ if (filterAttributes) {
+ Iterator<MBeanAttributeInfo> iterator = attributes.iterator();
+ while (iterator.hasNext()) {
+ MBeanAttributeInfo info = iterator.next();
+ if (includes.matcher(info.getName()).matches()) continue;
+ if (excludes.matcher(info.getName()).matches())
iterator.remove();
+ }
+ }
+
+ return new MBeanInfo(this.getClass().getName(), "",
attributes.toArray(new MBeanAttributeInfo[0]), new MBeanConstructorInfo[0],
operations.toArray(new MBeanOperationInfo[0]), new MBeanNotificationInfo[0]);
+ }
+
+ public void setAttributesFilter(String exclude, String include) {
+ if (include == null) include = "";
+ if (exclude == null) exclude = "";
+ includes = Pattern.compile(include);
+ excludes = Pattern.compile(exclude);
+
+ try {
+ // Set the current value as the description
+ Field field =
MBeanFeatureInfo.class.getDeclaredField("description");
+ field.setAccessible(true);
+ field.set(includeInfo, "\"" + includes.pattern() + "\"");
+ field.set(excludeInfo, "\"" + excludes.pattern() + "\"");
+ } catch (Exception e) {
+ // Oh well, we tried
+ }
}
/**
@@ -147,6 +296,9 @@ class ManagedMBean implements DynamicMBe
String getName();
Class getType();
+
+ <T extends Annotation> T getAnnotation(Class<T> annotationClass);
+
}
/**
@@ -173,18 +325,25 @@ class ManagedMBean implements DynamicMBe
return getter.getDeclaringClass();
}
+ public <T extends Annotation> T getAnnotation(Class<T>
annotationClass) {
+ return getter.getAnnotation(annotationClass);
+ }
+
/**
* The method name needs to be changed from "getFoo" to "foo"
*
* @return
*/
public String getName() {
- StringBuilder name = new StringBuilder(getter.getName());
+ String method = getter.getName();
+
+ StringBuilder name = new StringBuilder(method);
// remove 'get'
- name.delete(0, 3);
+ if (method.matches("get[A-Z].*")) name.delete(0, 3);
+ if (method.matches("is[A-Z].*")) name.delete(0, 2);
- if (!"".equals(prefix)){
+ if (!"".equals(prefix)) {
if (!"".equals(name.toString())) name.insert(0, ".");
name.insert(0, prefix);
}
@@ -229,12 +388,16 @@ class ManagedMBean implements DynamicMBe
return field.getDeclaringClass();
}
+ public <T extends Annotation> T getAnnotation(Class<T>
annotationClass) {
+ return field.getAnnotation(annotationClass);
+ }
+
public String getName() {
StringBuilder name = new StringBuilder(field.getName());
name.setCharAt(0, Character.toUpperCase(name.charAt(0)));
- if (!"".equals(prefix)){
+ if (!"".equals(prefix)) {
if (!"".equals(name.toString())) name.insert(0, ".");
name.insert(0, prefix);
}
Added:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MethodScratchPad.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MethodScratchPad.java?rev=942636&view=auto
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MethodScratchPad.java
(added)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MethodScratchPad.java
Mon May 10 00:34:42 2010
@@ -0,0 +1,131 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openejb.monitoring;
+
+import org.apache.openejb.api.Monitor;
+
+import javax.interceptor.InvocationContext;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.lang.reflect.Method;
+import java.lang.management.ManagementFactory;
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class MethodScratchPad {
+ public static void main(String[] args) throws Exception {
+ new MethodScratchPad().main();
+ }
+
+ public void main() throws Exception {
+
+ List<Context> contexts = new ArrayList<Context>();
+ Class<MyBean> clazz = MyBean.class;
+ contexts.add(new Context(clazz.getMethod("red")));
+ contexts.add(new Context(clazz.getMethod("red")));
+ contexts.add(new Context(clazz.getMethod("red")));
+ contexts.add(new Context(clazz.getMethod("red")));
+ contexts.add(new Context(clazz.getMethod("red")));
+ contexts.add(new Context(clazz.getMethod("blue")));
+ contexts.add(new Context(clazz.getMethod("blue")));
+ contexts.add(new Context(clazz.getMethod("blue")));
+ contexts.add(new Context(clazz.getMethod("green")));
+ contexts.add(new Context(clazz.getMethod("green")));
+ contexts.add(new Context(clazz.getMethod("orange")));
+
+ Random random = new Random();
+ StatsInterceptor interceptor = new StatsInterceptor(clazz);
+
+ interceptor.invoke(contexts.get(random(random, 0, contexts.size())));
+ interceptor.invoke(contexts.get(random(random, 0, contexts.size())));
+
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+ server.registerMBean(new ManagedMBean(interceptor), new
ObjectName("something:name=Invocations"));
+
+ snooze(5000);
+ while (true) {
+ interceptor.invoke(contexts.get(random(random, 0,
contexts.size())));
+ }
+// new CountDownLatch(1).await();
+
+ }
+
+ @Monitor
+ public static class MyBean {
+ public void red(){}
+ public void green(){}
+ public void blue(){}
+ public void orange(){}
+ }
+
+ private void snooze(int millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ Thread.interrupted();
+ }
+ }
+
+ public static int random(Random random, int min, int max) {
+ int i = random.nextInt();
+ if (i < 0) i *= -1;
+ return (i % (max - min)) + min;
+ }
+
+ private class Context implements InvocationContext {
+
+ private final Random random = new Random();
+
+ private final Method method;
+
+ private Context(Method method) {
+ this.method = method;
+ }
+
+ public Object getTarget() {
+ return null;
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+
+ public Object[] getParameters() {
+ return new Object[0];
+ }
+
+ public void setParameters(Object[] objects) {
+ }
+
+ public Map<String, Object> getContextData() {
+ return null;
+ }
+
+ public Object proceed() throws Exception {
+ snooze((int) (System.nanoTime() / 1000 % 1000));
+
+ return null;
+ }
+ }
+
+}
Propchange:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MethodScratchPad.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ScratchPad.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ScratchPad.java?rev=942636&r1=942635&r2=942636&view=diff
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ScratchPad.java
(original)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ScratchPad.java
Mon May 10 00:34:42 2010
@@ -17,8 +17,10 @@
package org.apache.openejb.monitoring;
import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
import java.util.List;
import java.util.ArrayList;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -27,6 +29,7 @@ import org.apache.openejb.util.Duration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
+import javax.interceptor.InvocationContext;
/**
* @version $Rev$ $Date$
Added:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/StatsInterceptor.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/StatsInterceptor.java?rev=942636&view=auto
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/StatsInterceptor.java
(added)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/StatsInterceptor.java
Mon May 10 00:34:42 2010
@@ -0,0 +1,269 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openejb.monitoring;
+
+import
org.apache.commons.math.stat.descriptive.SynchronizedDescriptiveStatistics;
+import org.apache.xbean.finder.ClassFinder;
+import org.apache.openejb.api.Monitor;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.ejb.PostActivate;
+import javax.ejb.PrePassivate;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.InvocationContext;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class StatsInterceptor {
+
+ private final Map<Method, Stats> map = new ConcurrentHashMap<Method,
Stats>();
+ private final AtomicLong invocations = new AtomicLong();
+
+ private Monitor monitor;
+
+ public StatsInterceptor(Class<?> componentClass) {
+
+ monitor = componentClass.getAnnotation(Monitor.class);
+ ClassFinder finder = new ClassFinder(componentClass);
+ for (Method method : finder.findAnnotatedMethods(Monitor.class)) {
+ map.put(method, new Stats(method, monitor));
+ }
+ }
+
+ public boolean isMonitoringEnabled() {
+ return monitor != null || map.size() > 0;
+ }
+
+ @Managed
+ public long getInvocations() {
+ return invocations.get();
+ }
+
+ @Managed
+ public long getMonitoredMethods() {
+ return map.size();
+ }
+
+ @ManagedCollection(type = Stats.class, key = "method")
+ public Collection<Stats> stats() {
+ return map.values();
+ }
+
+ @PostConstruct
+ public void constructed(InvocationContext invocationContext) throws
Exception {
+ record(invocationContext);
+ }
+
+ @PreDestroy
+ public void destroy(InvocationContext invocationContext) throws Exception {
+ record(invocationContext);
+ }
+
+ @AroundInvoke
+ public Object invoke(InvocationContext invocationContext) throws Exception
{
+ return record(invocationContext);
+ }
+
+ @PostActivate
+ public void activated(InvocationContext invocationContext) throws
Exception {
+ record(invocationContext);
+ }
+
+ @PrePassivate
+ public void passivate(InvocationContext invocationContext) throws
Exception {
+ record(invocationContext);
+ }
+
+ private Object record(InvocationContext invocationContext) throws
Exception {
+ invocations.incrementAndGet();
+
+ Stats stats = stats(invocationContext);
+ long start = System.nanoTime();
+ try {
+ return invocationContext.proceed();
+ } finally {
+ stats.record(start);
+ }
+ }
+
+ private Stats stats(InvocationContext invocationContext) {
+ Method method = invocationContext.getMethod();
+ Stats stats = map.get(method);
+ if (stats == null && monitor != null) {
+ stats = new Stats(method, monitor);
+ map.put(method, stats);
+ }
+ return stats;
+ }
+
+ public class Stats {
+ private final AtomicLong count = new AtomicLong();
+ private final SynchronizedDescriptiveStatistics samples;
+
+ // Used as the prefix for the MBeanAttributeInfo
+ private final String method;
+
+ public Stats(Method method, Monitor classAnnotation) {
+ Monitor methodAnnotation = method.getAnnotation(Monitor.class);
+
+ int window = (methodAnnotation != null) ?
methodAnnotation.sample() : (classAnnotation != null) ?
classAnnotation.sample() : 2000;
+
+ this.samples = new SynchronizedDescriptiveStatistics(window);
+ String s = ",";
+
+ StringBuilder sb = new StringBuilder(method.getName());
+ sb.append("(");
+ Class<?>[] params = method.getParameterTypes();
+ for (Class<?> clazz : params) {
+ sb.append(clazz.getSimpleName());
+ sb.append(s);
+ }
+ if (params.length > 0) sb.delete(sb.length() - s.length(),
sb.length());
+ sb.append(")");
+
+ this.method = sb.toString();
+ }
+
+ @Managed
+ public void setSampleSize(int i) {
+ samples.setWindowSize(i);
+ }
+
+ @Managed
+ public int getSampleSize() {
+ return samples.getWindowSize();
+ }
+
+ @Managed
+ public long getCount() {
+ return count.get();
+ }
+
+ @Managed
+ public double getPercentile99() {
+ return samples.getPercentile(99.0);
+ }
+
+ @Managed
+ public double getPercentile90() {
+ return samples.getPercentile(90.0);
+ }
+
+ @Managed
+ public double getPercentile75() {
+ return samples.getPercentile(75.0);
+ }
+
+ @Managed
+ public double getPercentile50() {
+ return samples.getPercentile(50.0);
+ }
+
+ @Managed
+ public double getPercentile25() {
+ return samples.getPercentile(25.0);
+ }
+
+ @Managed
+ public double getPercentile10() {
+ return samples.getPercentile(10.0);
+ }
+
+ @Managed
+ public double getPercentile01() {
+ return samples.getPercentile(1.0);
+ }
+
+ @Managed
+ public double getStandardDeviation() {
+ return samples.getStandardDeviation();
+ }
+
+ @Managed
+ public double getMean() {
+ return samples.getMean();
+ }
+
+ @Managed
+ public double getVariance() {
+ return samples.getVariance();
+ }
+
+ @Managed
+ public double getGeometricMean() {
+ return samples.getGeometricMean();
+ }
+
+ @Managed
+ public double getSkewness() {
+ return samples.getSkewness();
+ }
+
+ @Managed
+ public double getKurtosis() {
+ return samples.getKurtosis();
+ }
+
+ @Managed
+ public double getMax() {
+ return samples.getMax();
+ }
+
+ @Managed
+ public double getMin() {
+ return samples.getMin();
+ }
+
+ @Managed
+ public double getSum() {
+ return samples.getSum();
+ }
+
+ @Managed
+ public double getSumsq() {
+ return samples.getSumsq();
+ }
+
+ @Managed
+ public double[] sortedValues() {
+ return samples.getSortedValues();
+ }
+
+ @Managed
+ public double[] values() {
+ return samples.getValues();
+ }
+
+ public void record(long start) {
+ count.incrementAndGet();
+ long time = System.nanoTime() - start;
+ samples.addValue(millis(time));
+ }
+
+ private long millis(long nanos) {
+ return TimeUnit.MILLISECONDS.convert(nanos, TimeUnit.NANOSECONDS);
+ }
+ }
+}
Propchange:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/StatsInterceptor.java
------------------------------------------------------------------------------
svn:eol-style = native