    1   /* JmxUtils
    2    *
    3    * Created on May 18, 2005
    4    *
    5    * Copyright (C) 2005 Internet Archive.
    6    *
    7    * This file is part of the Heritrix web crawler (crawler.archive.org).
    8    *
    9    * Heritrix is free software; you can redistribute it and/or modify
    10   * it under the terms of the GNU Lesser Public License as published by
    11   * the Free Software Foundation; either version 2.1 of the License, or
    12   * any later version.
    13   *
    14   * Heritrix is distributed in the hope that it will be useful,
    15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17   * GNU Lesser Public License for more details.
    18   *
    19   * You should have received a copy of the GNU Lesser Public License
    20   * along with Heritrix; if not, write to the Free Software
    21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    22   */
    23  package org.archive.util;
    24
    25  import java.net.InetSocketAddress;
    26  import java.util.Arrays;
    27  import java.util.Iterator;
    28  import java.util.List;
    29  import java.util.Map;
    30  import java.util.logging.Level;
    31  import java.util.logging.Logger;
    32
    33  import javax.management.MBeanAttributeInfo;
    34  import javax.management.MBeanOperationInfo;
    35  import javax.management.MBeanParameterInfo;
    36  import javax.management.MBeanServer;
    37  import javax.management.MalformedObjectNameException;
    38  import javax.management.ObjectName;
    39  import javax.management.RuntimeOperationsException;
    40  import javax.management.openmbean.CompositeType;
    41  import javax.management.openmbean.InvalidOpenTypeException;
    42  import javax.management.openmbean.OpenDataException;
    43  import javax.management.openmbean.OpenMBeanAttributeInfo;
    44  import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
    45  import javax.management.openmbean.OpenMBeanOperationInfo;
    46  import javax.management.openmbean.OpenMBeanOperationInfoSupport;
    47  import javax.management.openmbean.OpenMBeanParameterInfo;
    48  import javax.management.openmbean.OpenMBeanParameterInfoSupport;
    49  import javax.management.openmbean.OpenType;
    50  import javax.management.openmbean.SimpleType;
    51
    52
    53  /***
    54   * Static utility used by JMX.
    55   * @author stack
    56   * @version $Date: 2005-12-15 00:35:44 +0000 (Thu, 15 Dec 2005) $, $Revision: 4022 $
    57   */
    58  public class JmxUtils {
    59      private static final Logger LOGGER =
    60          Logger.getLogger(JmxUtils.class.getName());
    61      public static final String TYPE = "type";
    62      public static final String SERVICE = "CrawlService";
    63      public static final String JOB = SERVICE + ".Job";
    64      public static final String NAME = "name";
    65      public static final String HOST = "host";
    66      public static final String JMX_PORT = "jmxport";
    67      public static final String GUI_PORT = "guiport";
    68      public static final String KEY = "key";
    69
    70      /***
    71       * Key for name of the Heritrix instance hosting a Job: i.e. the
    72       * CrawlJob's host/'mother'.
    73       */
    74      public static final String MOTHER = "mother";
    75
    76      public static final ObjectName MBEAN_SERVER_DELEGATE;
    77      static {
    78          try {
    79              MBEAN_SERVER_DELEGATE = new ObjectName(
    80                  "JMImplementation:type=MBeanServerDelegate");
    81          } catch (Exception e) {
    82              e.printStackTrace();
    83              throw new RuntimeException(e);
    84          }
    85      }
    86
    87      private static final List OPENTYPES =
    88          Arrays.asList(OpenType.ALLOWED_CLASSNAMES);
    89
    90      protected JmxUtils() {
    91          super();
    92      }
    93
    94      /***
    95       * Return a string suitable for logging on registration.
    96       * @param mbeanName Mbean that got registered.
    97       * @param mbeanServer Server we were registered to.
    98       * @param registrationDone Whether we registered successfully or not.
    99       * @return String suitable for logging.
    100      */
    101     public static String getLogRegistrationMsg(final String mbeanName,
    102             final MBeanServer mbeanServer, final boolean registrationDone) {
    103         return mbeanName + (registrationDone? " " : " NOT ") +
    104             "registered to " + JmxUtils.getServerDetail(mbeanServer);
    105     }
    106
    107     public static String getLogUnregistrationMsg(final String mbeanName,
    108             final MBeanServer mbeanServer) {
    109         return mbeanName + " unregistered from " +
    110             JmxUtils.getServerDetail(mbeanServer);
    111     }
    112
    113     public static String getServerDetail(final MBeanServer server) {
    114         ObjectName delegateName = null;
    115         try {
    116             delegateName = new ObjectName(
    117                     "JMImplementation:type=MBeanServerDelegate");
    118         } catch (MalformedObjectNameException e) {
    119             LOGGER.log(Level.SEVERE, "Failed to create ObjectName for " +
    120                     "JMImplementation:type=MBeanServerDelegate", e);
    121             return null;
    122         }
    123         StringBuffer buffer = new StringBuffer("MBeanServerId=");
    124         try {
    125             buffer.append((String) server.getAttribute(delegateName,
    126                     "MBeanServerId"));
    127             buffer.append(", SpecificationVersion=");
    128             buffer.append((String) server.getAttribute(delegateName,
    129                     "SpecificationVersion"));
    130             buffer.append(", ImplementationVersion=");
    131             buffer.append((String) server.getAttribute(delegateName,
    132                     "ImplementationVersion"));
    133             buffer.append(", SpecificationVendor=");
    134             buffer.append((String) server.getAttribute(delegateName,
    135                     "SpecificationVendor"));
    136         } catch (Exception e) {
    137             LOGGER.log(Level.SEVERE, "Failed gettting server detail for " +
    138                     "JMImplementation:type=MBeanServerDelegate", e);
    139         }
    140         return buffer.toString();
    141     }
    142
    143     /***
    144      * @param operationName
    145      *            Name of operation we're checking params on (Used in exception
    146      *            if one thrown).
    147      * @param params
    148      *            Amount of params passed.
    149      * @param count
    150      *            Count of params expected.
    151      */
    152     public static void checkParamsCount(String operationName, Object[] params,
    153             int count) {
    154         if ((params.length != count)) {
    155             throw new RuntimeOperationsException(
    156                 new IllegalArgumentException(
    157                   "Cannot invoke " + operationName + ": Passed " +
    158                   Integer.toString(params.length) + " argument(s) " +
    159                   "but expected " + Integer.toString(count)),
    160                   "Wrong number of arguments passed: unable to invoke " +
    161                   operationName + " method");
    162         }
    163     }
    164
    165     /***
    166      * @param in MBeanOperation to convert.
    167      * @return An OpenMBeanOperation version of the passed MBeanOperation.
    168      */
    169     public static OpenMBeanOperationInfo convertToOpenMBeanOperation(
    170             MBeanOperationInfo in) {
    171         return convertToOpenMBeanOperation(in, null, null);
    172     }
    173
    174     /***
    175      * @param in MBeanOperation to convert.
    176      * @param prefix A prefix to add to the name of new operation.
    177      * @param returnType Return type to use in new operation.  Use this
    178      * parameter to override the passed <code>in</code> return type.
    179      * @return An OpenMBeanOperation version of the passed MBeanOperation.
    180      */
    181     public static OpenMBeanOperationInfo convertToOpenMBeanOperation(
    182             final MBeanOperationInfo in, final String prefix,
    183             final OpenType returnType) {
    184         MBeanParameterInfo [] params = in.getSignature();
    185         OpenMBeanParameterInfo [] signature =
    186             new OpenMBeanParameterInfo[params.length];
    187         for (int i = 0; i < params.length; i++) {
    188             signature[i] = convertToOpenMBeanOperationInfo(params[i]);
    189         }
    190         return new OpenMBeanOperationInfoSupport(
    191                 ((prefix != null)? prefix + in.getName(): in.getName()),
    192                 in.getDescription(), signature,
    193                 (returnType != null)?
    194                         returnType: getOpenType(in.getReturnType()),
    195                 convertImpact(in.getImpact()));
    196     }
    197
    198     public static int convertImpact(final int impact) {
    199         if (impact != MBeanOperationInfo.ACTION &&
    200                 impact != MBeanOperationInfo.ACTION_INFO &&
    201                 impact != MBeanOperationInfo.INFO) {
    202             // Don't allow back MBeanOperationInfo.UNKNOWN impact.
    203             return MBeanOperationInfo.ACTION_INFO;
    204         }
    205         return impact;
    206     }
    207
    208     /***
    209      * @param in MBeanParameterInfo to convert to an OpenMBeanParameterInfo.
    210      * @return OpenMBeanParameterInfo version of <code>in</code>
    211      */
    212     public static OpenMBeanParameterInfo
    213             convertToOpenMBeanOperationInfo(MBeanParameterInfo in) {
    214         return new OpenMBeanParameterInfoSupport(in.getName(),
    215                 in.getDescription(), getOpenType(in.getType()));
    216     }
    217
    218     public static boolean isOpenType(final Class c) {
    219         return isOpenType(c.getName());
    220     }
    221
    222     public static boolean isOpenType(final String classname) {
    223         return OPENTYPES.contains(classname);
    224     }
    225
    226     /***
    227      * @param classString Java class name.
    228      * @return Its OpenType equivalent.
    229      */
    230     public static OpenType getOpenType(final String classString) {
    231         return getOpenType(classString, null);
    232     }
    233
    234     /***
    235      * @param classString Java class name.
    236      * @param defaultType If no equivalent found, use passed defaultType.
    237      * @return Its OpenType equivalent.
    238      */
    239     public static OpenType getOpenType(String classString,
    240             final OpenType defaultType) {
    241         if (classString.equals("void")) {
    242             return SimpleType.VOID;
    243         }
    244         if (!isOpenType(classString)) {
    245             throw new InvalidOpenTypeException(classString);
    246         }
    247         if (classString.equals(String.class.getName())) {
    248             return SimpleType.STRING;
    249         } else if (classString.equals(Boolean.class.getName())) {
    250             return SimpleType.BOOLEAN;
    251         } else if (classString.equals(Long.class.getName())) {
    252             return SimpleType.LONG;
    253         } else if (classString.equals(Integer.class.getName())) {
    254             return SimpleType.INTEGER;
    255         } else if (classString.equals(Float.class.getName())) {
    256             return SimpleType.FLOAT;
    257         } else if (classString.equals(Double.class.getName())) {
    258             return SimpleType.DOUBLE;
    259         } else if (defaultType != null) {
    260             return defaultType;
    261         }
    262         throw new RuntimeException("Unsupported type: " + classString);
    263     }
    264
    265     /***
    266      * @param in AttributeInfo to convert.
    267      * @return OpenMBeanAttributeInfo version of <code>in</code>.
    268      */
    269     public static OpenMBeanAttributeInfo
    270     convertToOpenMBeanAttribute(MBeanAttributeInfo in) {
    271         return convertToOpenMBeanAttribute(in, null);
    272     }
    273
    274     /***
    275      * @param in AttributeInfo to convert.
    276      * @param prefix Prefix to add to names of new attributes. If null, nothing
    277      * is added.
    278      * @return OpenMBeanAttributeInfo version of <code>in</code>.
    279      */
    280     public static OpenMBeanAttributeInfo
    281             convertToOpenMBeanAttribute(final MBeanAttributeInfo in,
    282                     final String prefix) {
    283         return createOpenMBeanAttributeInfo(getOpenType(in.getType()), in,
    284                 prefix);
    285     }
    286
    287     /***
    288      * @param type Type of new OpenMBeanAttributeInfo.
    289      * @param in The MBeanAttributeInfo we're converting.
    290      * @param prefix Prefix to add to name of new Attribute (If null, nothing
    291      * is added).
    292      * @return New OpenMBeanAttributeInfo based on <code>in</code>.
    293      */
    294     public static OpenMBeanAttributeInfo createOpenMBeanAttributeInfo(
    295             final OpenType type, final MBeanAttributeInfo in,
    296             final String prefix) {
    297         return new OpenMBeanAttributeInfoSupport(
    298                 ((prefix != null)? prefix + in.getName(): in.getName()),
    299                 in.getDescription(), type, in.isReadable(),
    300                 in.isWritable(), in.isIs());
    301     }
    302
    303     /***
    304      * @param m A map to make a CompositeType of (Assumption is that order does
    305      * not matter. If it does, pass a map of sorted keys).
    306      * @param compositeTypeName Name to give created compositeType.
    307      * @param compositeTypeDescription Description.
    308      * @return CompositeType made by examination of passed TreeMap.
    309      * @throws OpenDataException
    310      */
    311     public static CompositeType createCompositeType(final Map m,
    312             final String compositeTypeName,
    313             final String compositeTypeDescription)
    314     throws OpenDataException {
    315         String [] keys = new String[m.size()];
    316         OpenType [] types = new OpenType[m.size()];
    317         int index = 0;
    318         for (final Iterator i = m.keySet().iterator(); i.hasNext();) {
    319             String key = (String)i.next();
    320             keys[index] = key;
    321             types[index] = getOpenType(m.get(key).getClass().getName());
    322             index++;
    323         }
    324         return new CompositeType(compositeTypeName, compositeTypeDescription,
    325             keys, keys, types);
    326     }
    327
    328     public static InetSocketAddress extractAddress(final ObjectName name) {
    329         return new InetSocketAddress(name.getKeyProperty(HOST),
    330             Integer.parseInt(name.getKeyProperty(JMX_PORT)));
    331     }
    332
    333     /***
    334      * Returns the UID portion of the name key property of
    335      * an object name representing a "CrawlService.Job" bean.
    336      * It is assumed that the name will have the format
    337      * {crawl name}-{uid}.
    338      * @param on A CrawlServer.Job object name.
    339      * @return Uid for a CrawlServer.Job.
    340      */
    341     public static String getUid(final ObjectName on) {
    342         String name = on.getKeyProperty(NAME);
    343         return name.substring(name.indexOf("-") + 1);
    344     }
    345 }