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


Reply via email to