You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2010/04/29 08:07:41 UTC

svn commit: r939204 - in /openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring: ./ MBeanExporter.java MBeanInfoBuilder.java Managed.java ObjectNames.java

Author: dblevins
Date: Thu Apr 29 06:07:40 2010
New Revision: 939204

URL: http://svn.apache.org/viewvc?rev=939204&view=rev
Log:
Ability to easily export annotated stats beans as JMX objects.  Based on Martin Traverso's jmxutils.  Still a work in progress.

Added:
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanExporter.java   (with props)
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanInfoBuilder.java   (with props)
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/Managed.java   (with props)
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ObjectNames.java   (with props)

Added: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanExporter.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanExporter.java?rev=939204&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanExporter.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanExporter.java Thu Apr 29 06:07:40 2010
@@ -0,0 +1,101 @@
+/**
+ * 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 javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanException;
+import javax.management.modelmbean.ModelMBeanInfo;
+import javax.management.modelmbean.RequiredModelMBean;
+import javax.management.modelmbean.ModelMBeanInfoSupport;
+import javax.management.modelmbean.ModelMBeanAttributeInfo;
+import javax.management.modelmbean.ModelMBeanConstructorInfo;
+import javax.management.modelmbean.ModelMBeanOperationInfo;
+import javax.management.modelmbean.ModelMBeanNotificationInfo;
+import java.util.List;
+import java.util.ArrayList;
+
+public class MBeanExporter {
+    private final MBeanServer server;
+
+    public MBeanExporter(MBeanServer server) {
+        this.server = server;
+    }
+
+    public void export(String name, Object object) {
+        try {
+            ObjectName objectName = new ObjectName(name);
+
+            MBeanInfoBuilder builder = new MBeanInfoBuilder();
+            ModelMBeanInfo info = builder.buildInfo(object.getClass());
+
+            // Use the GetterStrippingMBeanInfo to work around http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6339571.
+            RequiredModelMBean mbean = new RequiredModelMBean(new GetterStrippingMBeanInfo(info));
+            mbean.setManagedResource(object, "objectReference");
+
+            server.registerMBean(mbean, objectName);
+        }
+        catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    static class GetterStrippingMBeanInfo extends ModelMBeanInfoSupport {
+        
+        public GetterStrippingMBeanInfo(ModelMBeanInfo info) {
+            super(info);
+        }
+
+        @Override
+        public GetterStrippingMBeanInfo clone() {
+            return new GetterStrippingMBeanInfo(this);
+        }
+
+        /**
+         * Get rid of getter and setter operations as the mbeaninfo is serialized
+         * Clients will see just the attributes
+         *
+         * @return
+         */
+        private Object writeReplace() {
+            List<MBeanOperationInfo> operations = new ArrayList<MBeanOperationInfo>();
+
+            for (MBeanOperationInfo operation : getOperations()) {
+    //            Descriptor descriptor = operation.getDescriptor();
+    //            String role = (String) descriptor.getFieldValue("role");
+    //            if (!"getter".equalsIgnoreCase(role) && !"setter".equalsIgnoreCase(role)) {
+                operations.add(operation);
+    //            }
+            }
+
+            try {
+                return new ModelMBeanInfoSupport(
+                        this.getClassName(),
+                        this.getDescription(),
+                        (ModelMBeanAttributeInfo[]) this.getAttributes(),
+                        (ModelMBeanConstructorInfo[]) this.getConstructors(),
+                        operations.toArray(new ModelMBeanOperationInfo[0]),
+                        (ModelMBeanNotificationInfo[]) this.getNotifications(),
+                        this.getMBeanDescriptor());
+            }
+            catch (MBeanException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanExporter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanInfoBuilder.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanInfoBuilder.java?rev=939204&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanInfoBuilder.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanInfoBuilder.java Thu Apr 29 06:07:40 2010
@@ -0,0 +1,158 @@
+/**
+ * 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.jee.oejb2.ClassFilterType;
+import org.apache.xbean.finder.ClassFinder;
+
+import javax.management.Descriptor;
+import javax.management.IntrospectionException;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.modelmbean.DescriptorSupport;
+import javax.management.modelmbean.ModelMBeanAttributeInfo;
+import javax.management.modelmbean.ModelMBeanConstructorInfo;
+import javax.management.modelmbean.ModelMBeanInfo;
+import javax.management.modelmbean.ModelMBeanInfoSupport;
+import javax.management.modelmbean.ModelMBeanNotificationInfo;
+import javax.management.modelmbean.ModelMBeanOperationInfo;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class MBeanInfoBuilder {
+    private final static Pattern getterOrSetterPattern = Pattern.compile("(get|set|is)(.+)");
+
+    private static final String SUFFIX = MBeanInfoBuilder.class.getName();
+    private final static String DESCRIPTION = SUFFIX + ".description";
+    private final static String METHOD_INSTANCE = SUFFIX + ".methodInstance";
+    private final static String GET_METHOD_INSTANCE = SUFFIX + ".getMethodInstance";
+    private final static String SET_METHOD_INSTANCE = SUFFIX + ".setMethodInstance";
+
+    public ModelMBeanInfo buildInfo(Class clazz) throws IntrospectionException {
+        
+        Map<String, DescriptorSupport> attributes = new HashMap<String, DescriptorSupport>();
+        List<DescriptorSupport> operations = new ArrayList<DescriptorSupport>();
+
+        ClassFinder finder = new ClassFinder(clazz);
+
+        List<Method> methods = finder.findAnnotatedMethods(Managed.class);
+
+        for (Method method : methods) {
+            Managed annotation = method.getAnnotation(Managed.class);
+
+            DescriptorSupport operationDescriptor = new DescriptorSupport();
+            operationDescriptor.setField("name", method.getName());
+            operationDescriptor.setField("class", clazz.getName());
+            operationDescriptor.setField("descriptorType", "operation");
+            operationDescriptor.setField(DESCRIPTION, annotation.description());
+            operationDescriptor.setField(METHOD_INSTANCE, method);
+
+            operations.add(operationDescriptor);
+
+            Matcher matcher = getterOrSetterPattern.matcher(method.getName());
+            if (matcher.matches()) {
+                String type = matcher.group(1);
+                String attributeName = matcher.group(2);
+
+                DescriptorSupport descriptor = attributes.get(attributeName);
+                if (descriptor == null) {
+                    descriptor = new DescriptorSupport();
+                    descriptor.setField("name", attributeName);
+                    descriptor.setField("descriptorType", "attribute");
+                    descriptor.setField(DESCRIPTION, annotation.description());
+
+                    attributes.put(attributeName, descriptor);
+                }
+
+                if (type.equals("get") || type.equals("is")) {
+                    descriptor.setField(GET_METHOD_INSTANCE, method);
+                    descriptor.setField("getMethod", method.getName());
+                    operationDescriptor.setField("role", "getter");
+                } else if (type.equals("set")) {
+                    descriptor.setField(SET_METHOD_INSTANCE, method);
+                    descriptor.setField("setMethod", method.getName());
+                    operationDescriptor.setField("role", "setter");
+                }
+            } else {
+                operationDescriptor.setField("role", "operation");
+            }
+        }
+
+        List<ModelMBeanAttributeInfo> attributeInfos = new ArrayList<ModelMBeanAttributeInfo>();
+
+        for (DescriptorSupport attribute : attributes.values()) {
+            Method getter = (Method) attribute.getFieldValue(GET_METHOD_INSTANCE);
+            Method setter = (Method) attribute.getFieldValue(SET_METHOD_INSTANCE);
+            String description = (String) attribute.getFieldValue(DESCRIPTION);
+
+            // we're piggybacking on Descriptor to hold values that we need here. Remove them before passing
+            // them on, as they will cause problems if they are not serializable (e.g., Method)
+            strip(attribute);
+
+            attributeInfos.add(new ModelMBeanAttributeInfo(attribute.getFieldValue("name").toString(),
+                    description,
+                    getter,
+                    setter,
+                    attribute));
+        }
+
+        List<ModelMBeanOperationInfo> operationInfos = new ArrayList<ModelMBeanOperationInfo>();
+
+        for (DescriptorSupport operation : operations) {
+            String description = (String) operation.getFieldValue(DESCRIPTION);
+            Method method = (Method) operation.getFieldValue(METHOD_INSTANCE);
+
+            // we're piggybacking on Descriptor to hold values that we need here. Remove them before passing
+            // them on, as they will cause problems if they are not serializable (e.g., Method)
+            strip(operation);
+
+            Class<?>[] types = method.getParameterTypes();
+            String[] names = new String[types.length];
+            for (int i = 0; i < names.length; i++) {
+                names[i] = "arg" + i;
+            }
+
+            MBeanParameterInfo[] params = new MBeanParameterInfo[names.length];
+
+            for (int i = 0; i < names.length; ++i) {
+                params[i] = new MBeanParameterInfo(names[i], types[i].getName(), null);
+            }
+
+            operationInfos.add(new ModelMBeanOperationInfo(method.getName(), description, params,
+                    method.getReturnType().toString(), MBeanOperationInfo.UNKNOWN, operation));
+        }
+
+        return new ModelMBeanInfoSupport(clazz.getName(), null,
+                attributeInfos.toArray(new ModelMBeanAttributeInfo[0]),
+                new ModelMBeanConstructorInfo[0],
+                operationInfos.toArray(new ModelMBeanOperationInfo[0]),
+                new ModelMBeanNotificationInfo[0]);
+    }
+
+    private void strip(Descriptor descriptor) {
+        for (String name : descriptor.getFieldNames()) {
+            if (name.startsWith(SUFFIX)) {
+                descriptor.removeField(name);
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanInfoBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 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=939204&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/Managed.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/Managed.java Thu Apr 29 06:07:40 2010
@@ -0,0 +1,28 @@
+/**
+ * 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})
+public @interface Managed {
+    String description() default "";
+}
\ No newline at end of file

Propchange: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/Managed.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ObjectNames.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ObjectNames.java?rev=939204&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ObjectNames.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ObjectNames.java Thu Apr 29 06:07:40 2010
@@ -0,0 +1,66 @@
+/**
+ * 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 static java.lang.String.format;
+import java.lang.annotation.Annotation;
+
+/**
+ * Generate JMX object names.
+ */
+public class ObjectNames {
+
+    /**
+     * Produce a standardized JMX object name.
+     *
+     * @param clazz
+     * @return JMX object name of the form "[package_name]:name=[class_name]"
+     */
+    public static String generatedNameOf(Class<?> clazz) {
+        return format("%s:name=%s",
+                clazz.getPackage().getName(),
+                clazz.getSimpleName());
+    }
+
+    /**
+     * Produce a generated JMX object name.
+     *
+     * @param clazz
+     * @param annotation
+     * @return JMX object name of the form "[package_name]:type=[class_name],name=[ann_class_name]"
+     */
+    public static String generatedNameOf(Class<?> clazz, Annotation annotation) {
+        return format("%s:type=%s,name=%s",
+                clazz.getPackage().getName(),
+                clazz.getSimpleName(),
+                annotation.annotationType().getSimpleName());
+    }
+
+    /**
+     * Produce a generated JMX object name.
+     *
+     * @param clazz
+     * @param annotationClass
+     * @return JMX object name of the form "[package_name]:type=[class_name],name=[ann_class_name]"
+     */
+    public static String generatedNameOf(Class<?> clazz, Class<? extends Annotation> annotationClass) {
+        return format("%s:type=%s,name=%s",
+                clazz.getPackage().getName(),
+                clazz.getSimpleName(),
+                annotationClass.getSimpleName());
+    }
+}
\ No newline at end of file

Propchange: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ObjectNames.java
------------------------------------------------------------------------------
    svn:eol-style = native