View Javadoc

    1   /*
    2    $Id: GroovyMBean.java 3747 2006-04-17 12:56:57Z glaforge $
    3
    4    Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
    5
    6    Redistribution and use of this software and associated documentation
    7    ("Software"), with or without modification, are permitted provided
    8    that the following conditions are met:
    9
    10   1. Redistributions of source code must retain copyright
    11      statements and notices.  Redistributions must also contain a
    12      copy of this document.
    13
    14   2. Redistributions in binary form must reproduce the
    15      above copyright notice, this list of conditions and the
    16      following disclaimer in the documentation and/or other
    17      materials provided with the distribution.
    18
    19   3. The name "groovy" must not be used to endorse or promote
    20      products derived from this Software without prior written
    21      permission of The Codehaus.  For written permission,
    22      please contact info@codehaus.org.
    23
    24   4. Products derived from this Software may not be called "groovy"
    25      nor may "groovy" appear in their names without prior written
    26      permission of The Codehaus. "groovy" is a registered
    27      trademark of The Codehaus.
    28
    29   5. Due credit should be given to The Codehaus -
    30      http://groovy.codehaus.org/
    31
    32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
    33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
    34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
    36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
    43   OF THE POSSIBILITY OF SUCH DAMAGE.
    44
    45   */
    46  package groovy.util;
    47
    48  import groovy.lang.GroovyObjectSupport;
    49  import groovy.lang.GroovyRuntimeException;
    50
    51  import java.util.HashMap;
    52  import java.util.Map;
    53  import java.util.Collection;
    54  import java.util.ArrayList;
    55  import java.util.List;
    56  import java.util.Iterator;
    57  import java.io.IOException;
    58
    59  import javax.management.Attribute;
    60  import javax.management.JMException;
    61  import javax.management.MBeanException;
    62  import javax.management.MBeanInfo;
    63  import javax.management.MBeanOperationInfo;
    64  import javax.management.MBeanParameterInfo;
    65  import javax.management.ObjectName;
    66  import javax.management.MBeanServerConnection;
    67  import javax.management.MBeanAttributeInfo;
    68
    69
    70  /***
    71   * A GroovyObject facade for an underlying MBean which acts like a normal
    72   * groovy object but which is actually implemented via
    73   * an underlying JMX MBean.
    74   * Properties and normal method invocations
    75   * delegate to the MBeanServer to the actual MBean.
    76   *
    77   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
    78   * @author Steve Button
    79   * @version $Revision: 3747 $
    80   */
    81  public class GroovyMBean extends GroovyObjectSupport {
    82
    83      private MBeanServerConnection server;
    84      private ObjectName name;
    85      private MBeanInfo beanInfo;
    86      private Map operations = new HashMap();
    87
    88
    89      public GroovyMBean(MBeanServerConnection server, ObjectName name) throws JMException, IOException {
    90          this.server = server;
    91          this.name = name;
    92          this.beanInfo = server.getMBeanInfo(name);
    93
    94
    95          MBeanOperationInfo[] operationInfos = beanInfo.getOperations();
    96          for (int i = 0; i < operationInfos.length; i++) {
    97              MBeanOperationInfo info = operationInfos[i];
    98              String signature[] = createSignature(info);
    99
    100             // Include a simple fix here to support overloaded operations on the MBean.
    101             // Construct a simple key for an operation by adding the number of parameters it uses
    102             String operationKey = createOperationKey(info.getName(), signature.length);
    103             operations.put(operationKey, signature);
    104         }
    105
    106     }
    107
    108     public MBeanServerConnection server() {
    109         return server;
    110     }
    111
    112     public ObjectName name() {
    113         return name;
    114     }
    115
    116     public MBeanInfo info() {
    117         return beanInfo;
    118     }
    119
    120     public Object getProperty(String property) {
    121         try {
    122             return server.getAttribute(name, property);
    123         }
    124         catch (MBeanException e) {
    125             throw new GroovyRuntimeException("Could not access property: " + property + ". Reason: " + e, e.getTargetException());
    126         }
    127         catch (Exception e) {
    128             throw new GroovyRuntimeException("Could not access property: " + property + ". Reason: " + e, e);
    129         }
    130     }
    131
    132     public void setProperty(String property, Object value) {
    133         try {
    134             server.setAttribute(name, new Attribute(property, value));
    135         }
    136         catch (MBeanException e) {
    137             throw new GroovyRuntimeException("Could not set property: " + property + ". Reason: " + e, e.getTargetException());
    138         }
    139         catch (Exception e) {
    140             throw new GroovyRuntimeException("Could not set property: " + property + ". Reason: " + e, e);
    141         }
    142     }
    143
    144     public Object invokeMethod(String method, Object arguments) {
    145         // Moved this outside the try block so we can obtain the number of parameters
    146         // specified in the arguments array, which is needed to find the correct method.
    147         Object[] argArray = null;
    148         if (arguments instanceof Object[]) {
    149             argArray = (Object[]) arguments;
    150         } else {
    151             argArray = new Object[]{arguments};
    152         }
    153         // Locate the specific method based on the name and number of parameters
    154         String operationKey = createOperationKey(method, argArray.length);
    155         String[] signature = (String[]) operations.get(operationKey);
    156
    157         if (signature != null) {
    158             try {
    159                 return server.invoke(name, method, argArray, signature);
    160             }
    161             catch (MBeanException e) {
    162                 throw new GroovyRuntimeException("Could not invoke method: " + method + ". Reason: " + e, e.getTargetException());
    163             }
    164             catch (Exception e) {
    165                 throw new GroovyRuntimeException("Could not invoke method: " + method + ". Reason: " + e, e);
    166             }
    167         } else {
    168             return super.invokeMethod(method, arguments);
    169         }
    170     }
    171
    172     protected String[] createSignature(MBeanOperationInfo info) {
    173         MBeanParameterInfo[] params = info.getSignature();
    174         String[] answer = new String[params.length];
    175         for (int i = 0; i < params.length; i++) {
    176             answer[i] = params[i].getType();
    177         }
    178         return answer;
    179     }
    180
    181     /***
    182      * Construct a simple key based on the method name and the number of parameters
    183      *
    184      * @param operation - the mbean operation name
    185      * @param params    - the number of parameters the operation supports
    186      * @return simple unique identifier for a method
    187      */
    188     protected String createOperationKey(String operation, int params) {
    189         // This could be changed to support some hash of the parameter types, etc.
    190         return operation + "_" + params;
    191     }
    192
    193     /***
    194      * List of the names of each of the attributes on the MBean
    195      *
    196      * @return list of attribute names
    197      */
    198     public Collection listAttributeNames() {
    199         ArrayList list = new ArrayList();
    200         try {
    201             MBeanAttributeInfo[] attrs = beanInfo.getAttributes();
    202             for (int i = 0; i < attrs.length; i++) {
    203                 MBeanAttributeInfo attr = attrs[i];
    204                 list.add(attr.getName());
    205             }
    206         }
    207         catch (Throwable t) {
    208         }
    209         finally {
    210         }
    211         return list;
    212     }
    213
    214     /***
    215      * The values of each of the attributes on the MBean
    216      *
    217      * @return list of values of each attribute
    218      */
    219     public List listAttributeValues() {
    220         ArrayList list = new ArrayList();
    221         Collection names = listAttributeNames();
    222         for (Iterator iterator = names.iterator(); iterator.hasNext();) {
    223             String name = (String) iterator.next();
    224             try {
    225                 Object val = this.getProperty(name);
    226                 if (val != null) {
    227                     list.add(name + " : " + val.toString());
    228                 }
    229             }
    230             catch (RuntimeException e) {
    231                 // todo: fix this behaviour properly
    232                 // Do nothing here, just handle the error silently.
    233                 //e.printStackTrace();
    234             }
    235         }
    236         return list;
    237     }
    238
    239
    240     /***
    241      * List of string representations of all of the attributes on the MBean.
    242      *
    243      * @return list of descriptions of each attribute on the mbean
    244      */
    245     public Collection listAttributeDescriptions() {
    246         ArrayList list = new ArrayList();
    247         try {
    248             MBeanAttributeInfo[] attrs = beanInfo.getAttributes();
    249             for (int i = 0; i < attrs.length; i++) {
    250                 MBeanAttributeInfo attr = attrs[i];
    251                 list.add(describeAttribute(attr));
    252             }
    253         }
    254         catch (Throwable t) {
    255         }
    256         finally {
    257         }
    258         return list;
    259     }
    260
    261     /***
    262      * Description of the specified attribute name.
    263      *
    264      * @param attr - the attribute
    265      * @return String the description
    266      */
    267     protected String describeAttribute(MBeanAttributeInfo attr) {
    268         StringBuffer buf = new StringBuffer();
    269         buf.append("(");
    270         if (attr.isReadable()) {
    271             buf.append("r");
    272         }
    273         if (attr.isWritable()) {
    274             buf.append("w");
    275         }
    276         buf.append(") ")
    277                 .append(attr.getType())
    278                 .append(" ")
    279                 .append(attr.getName());
    280         return buf.toString();
    281     }
    282
    283     /***
    284      * Description of the specified attribute name.
    285      *
    286      * @param attributeName - stringified name of the attribute
    287      * @return the description
    288      */
    289     public String describeAttribute(String attributeName) {
    290         String ret = "Attribute not found";
    291         try {
    292             MBeanAttributeInfo[] attributes = beanInfo.getAttributes();
    293             for (int i = 0; i < attributes.length; i++) {
    294                 MBeanAttributeInfo attribute = attributes[i];
    295                 if (attribute.getName().equals(attributeName)) {
    296                     return describeAttribute(attribute);
    297                 }
    298             }
    299         }
    300         catch (Throwable t) {
    301         }
    302         return ret;
    303     }
    304
    305     /***
    306      * Names of all the operations available on the MBean.
    307      *
    308      * @return all the operations on the MBean
    309      */
    310     public Collection listOperationNames() {
    311         ArrayList list = new ArrayList();
    312         try {
    313             MBeanOperationInfo[] operations = beanInfo.getOperations();
    314             for (int i = 0; i < operations.length; i++) {
    315                 MBeanOperationInfo operation = operations[i];
    316                 list.add(operation.getName());
    317             }
    318         }
    319         catch (Throwable t) {
    320         }
    321         return list;
    322     }
    323
    324
    325     /***
    326      * Description of all of the operations available on the MBean.
    327      *
    328      * @return full description of each operation on the MBean
    329      */
    330     public Collection listOperationDescriptions() {
    331         ArrayList list = new ArrayList();
    332         try {
    333             MBeanOperationInfo[] operations = beanInfo.getOperations();
    334             for (int i = 0; i < operations.length; i++) {
    335                 MBeanOperationInfo operation = operations[i];
    336                 list.add(describeOperation(operation));
    337             }
    338         }
    339         catch (Throwable t) {
    340         }
    341         return list;
    342     }
    343
    344     /***
    345      * Get the dessciptions of the named operation.  This returns a Collection since
    346      * operations can be overloaded and one operationName can have multiple forms.
    347      *
    348      * @param operationName
    349      * @return Collection of operation description
    350      */
    351     public List describeOperation(String operationName) {
    352         ArrayList list = new ArrayList();
    353         try {
    354             MBeanOperationInfo[] operations = beanInfo.getOperations();
    355             for (int i = 0; i < operations.length; i++) {
    356                 MBeanOperationInfo operation = operations[i];
    357                 if (operation.getName().equals(operationName)) {
    358                     list.add(describeOperation(operation));
    359                 }
    360             }
    361         }
    362         catch (Throwable t) {
    363         }
    364         return list;
    365     }
    366
    367     /***
    368      * Dessciption of the named operation.
    369      *
    370      * @param operation
    371      * @return description
    372      */
    373     protected String describeOperation(MBeanOperationInfo operation) {
    374         StringBuffer buf = new StringBuffer();
    375         buf.append(operation.getReturnType())
    376                 .append(" ")
    377                 .append(operation.getName())
    378                 .append("(");
    379
    380         MBeanParameterInfo[] params = operation.getSignature();
    381         for (int j = 0; j < params.length; j++) {
    382             MBeanParameterInfo param = params[j];
    383             if (j != 0) {
    384                 buf.append(", ");
    385             }
    386             buf.append(param.getType())
    387                     .append(" ")
    388                     .append(param.getName());
    389         }
    390         buf.append(")");
    391         return buf.toString();
    392     }
    393
    394
    395     /***
    396      * Return an end user readable representation of the underlying MBean
    397      * @return the user readable description
    398      */
    399     public String toString() {
    400         StringBuffer buf = new StringBuffer();
    401         buf.append("MBean Name:")
    402                 .append("\n  ")
    403                 .append(name.getCanonicalName())
    404                 .append("\n  ");
    405         if (!listAttributeDescriptions().isEmpty()) {
    406             buf.append("\nAttributes:");
    407             for (Iterator iterator = listAttributeDescriptions().iterator(); iterator.hasNext();) {
    408                 buf.append("\n  ")
    409                         .append((String) iterator.next());
    410             }
    411         }
    412         if (!listOperationDescriptions().isEmpty()) {
    413             buf.append("\nOperations:");
    414             for (Iterator iterator = listOperationDescriptions().iterator(); iterator.hasNext();) {
    415                 buf.append("\n  ")
    416                         .append((String) iterator.next());
    417             }
    418         }
    419         return buf.toString();
    420   }
    421 }