    1   /*-
    2   * See the file LICENSE for redistribution information.
    3   *
    4   * Copyright (c) 2002-2005
    5   *      Sleepycat Software.  All rights reserved.
    6   *
    7   * $Id: JEMBeanHelper.java 4644 2006-09-20 22:40:21Z paul_jack $
    8   */
    9
    10  package org.archive.util;
    11
    12  import java.io.File;
    13  import java.util.ArrayList;
    14  import java.util.List;
    15
    16  import javax.management.Attribute;
    17  import javax.management.AttributeNotFoundException;
    18  import javax.management.InvalidAttributeValueException;
    19  import javax.management.MBeanAttributeInfo;
    20  import javax.management.MBeanException;
    21  import javax.management.MBeanNotificationInfo;
    22  import javax.management.MBeanOperationInfo;
    23  import javax.management.MBeanParameterInfo;
    24
    25  import com.sleepycat.je.CheckpointConfig;
    26  import com.sleepycat.je.Database;
    27  import com.sleepycat.je.DatabaseConfig;
    28  import com.sleepycat.je.DatabaseException;
    29  import com.sleepycat.je.DatabaseStats;
    30  import com.sleepycat.je.DbInternal;
    31  import com.sleepycat.je.Environment;
    32  import com.sleepycat.je.EnvironmentConfig;
    33  import com.sleepycat.je.EnvironmentMutableConfig;
    34  import com.sleepycat.je.StatsConfig;
    35
    36  /***
    37   * JEMBeanHelper is a utility class for the MBean implementation which wants to
    38   * add management of a JE environment to its capabilities. MBean
    39   * implementations can contain a JEMBeanHelper instance to get MBean metadata
    40   * for JE and to set attributes, get attributes, and invoke operations.
    41   * <p>
    42   * com.sleepycat.je.jmx.JEMonitor and
    43   * the example program jmx.JEApplicationMBean are two MBean implementations
    44   * which provide support different application use cases. See those classes for
    45   * examples of how to use JEMBeanHelper.
    46   * <p>This class was copied from the bdb je 2.0 jmx examples.
    47   */
    48
    49  public class JEMBeanHelper {
    50
    51      /*
    52       * A note to JE developers: all available JE attributes and operations are
    53       * described in the following static info arrays. New management
    54       * functionality can be added to the helper by adding to the appropriate
    55       * set of static definitions. For example, if we want to add a new JE
    56       * attribute called "foo", which is available for open environments, we
    57       * need to define a new MBeanAttributeInfo in the OPEN_ATTR array. The
    58       * helper then needs to provide an implementation in set/getAttribute.
    59       */
    60
    61      /* --------------------- Attributes -------------------------- */
    62
    63      /* Attribute names. */
    64      public static final String ATT_ENV_HOME = "environmentHome";
    65      public static final String ATT_OPEN = "isOpen";
    66      public static final String ATT_IS_READ_ONLY = "isReadOnly";
    67      public static final String ATT_IS_TRANSACTIONAL = "isTransactional";
    68      public static final String ATT_CACHE_SIZE = "cacheSize";
    69      public static final String ATT_CACHE_PERCENT = "cachePercent";
    70      public static final String ATT_LOCK_TIMEOUT = "lockTimeout";
    71      public static final String ATT_IS_SERIALIZABLE = "isSerializableIsolation";
    72      public static final String ATT_TXN_TIMEOUT = "transactionTimeout";
    73      public static final String ATT_SET_READ_ONLY = "openReadOnly";
    74      public static final String ATT_SET_TRANSACTIONAL = "openTransactional";
    75      public static final String ATT_SET_SERIALIZABLE =
    76          "openSerializableIsolation";
    77
    78      /* COMMON_ATTR attributes are available for any environment. */
    79      private static final MBeanAttributeInfo [] COMMON_ATTR = {
    80
    81          new MBeanAttributeInfo(ATT_ENV_HOME,
    82                                 "java.lang.String",
    83                                 "Environment home directory.",
    84                                 true,   // readable
    85                                 false,  // writable
    86                                 false), // isIs
    87          new MBeanAttributeInfo(ATT_OPEN,
    88                                 "java.lang.Boolean",
    89                                 "True if this environment is open.",
    90                                 true,   // readable
    91                                 false,  // writable
    92                                 true)   // isIs
    93      };
    94
    95      /* OPEN_ATTR attributes are available for all open environments. */
    96      private static final MBeanAttributeInfo [] OPEN_ATTR = {
    97
    98          new MBeanAttributeInfo(ATT_IS_READ_ONLY,
    99                                 "java.lang.Boolean",
    100                                "True if this environment is read only.",
    101                                true,   // readable
    102                                false,  // writable
    103                                true),  // isIs
    104         new MBeanAttributeInfo(ATT_IS_TRANSACTIONAL,
    105                                "java.lang.Boolean",
    106                              "True if this environment supports transactions.",
    107                                true,   // readable
    108                                false,  // writable
    109                                true),  // isIs
    110         new MBeanAttributeInfo(ATT_CACHE_SIZE,
    111                                "java.lang.Long",
    112                                "Cache size, in bytes.",
    113                                true,   // readable
    114                                true,   // writable
    115                                false), // isIs
    116         new MBeanAttributeInfo(ATT_CACHE_PERCENT,
    117                                "java.lang.Integer",
    118                                "By default, cache size is (cachePercent * " +
    119                                "JVM maximum memory. To change the cache size "+
    120                                "using a percentage of the heap size, set " +
    121                                "the cache size to 0 and cachePercent to the "+
    122                                "desired percentage value.",
    123                                true,   // readable
    124                                true,   // writable
    125                                false), // isIs
    126         new MBeanAttributeInfo(ATT_LOCK_TIMEOUT,
    127                                "java.lang.Long",
    128                                "Lock timeout, in microseconds.",
    129                                true,   // readable
    130                                false,  // writable
    131                                false), // isIs
    132     };
    133
    134     /*
    135      * TRANSACTIONAL_ATTR attributes are available only for open, transactional
    136      * environments.
    137      */
    138     private static final MBeanAttributeInfo [] TRANSACTIONAL_ATTR = {
    139
    140         new MBeanAttributeInfo(ATT_IS_SERIALIZABLE,
    141                                "java.lang.Boolean",
    142                                "True if this environment provides " +
    143                                "Serializable (degree 3) isolation. The " +
    144                                "default is RepeatableRead isolation.",
    145                                true,   // readable
    146                                false,  // writable
    147                                true),  // isIs
    148         new MBeanAttributeInfo(ATT_TXN_TIMEOUT,
    149                                "java.lang.Long",
    150                                "Transaction timeout, in seconds. A value " +
    151                                "of 0 means there is no timeout.",
    152                                true,   // readable
    153                                false,  // writable
    154                                false)  // isIs
    155     };
    156
    157     /*
    158      * CREATE_ATTR attributes are available when the mbean is configured to
    159      * support configuration and opening by the mbean. They express the
    160      * configuration settings.
    161      */
    162     private static final MBeanAttributeInfo [] CREATE_ATTR = {
    163
    164         new MBeanAttributeInfo(ATT_SET_READ_ONLY,
    165                                "java.lang.Boolean",
    166                                "True if this environment should be opened " +
    167                                "in readonly mode.",
    168                                true,   // readable
    169                                true,   // writable
    170                                false), // isIs
    171         new MBeanAttributeInfo(ATT_SET_TRANSACTIONAL,
    172                                "java.lang.Boolean",
    173                                "True if this environment should be opened " +
    174                                "in transactional mode.",
    175                                true,   // readable
    176                                true,   // writable
    177                                false), // isIs
    178         new MBeanAttributeInfo(ATT_SET_SERIALIZABLE,
    179                                "java.lang.Boolean",
    180                                "True if this environment should be opened " +
    181                                "with serializableIsolation. The default is "+
    182                                "false.",
    183                                true,   // readable
    184                                true,   // writable
    185                                false), // isIs
    186     };
    187
    188     /* --------------------- Operations  -------------------------- */
    189
    190     /* Operation names */
    191     static final String OP_CLEAN = "cleanLog";
    192     static final String OP_EVICT = "evictMemory";
    193     static final String OP_CHECKPOINT = "checkpoint";
    194     static final String OP_SYNC = "sync";
    195     static final String OP_ENV_STAT = "getEnvironmentStats";
    196     static final String OP_ENV_STAT_STR = "getEnvironmentStatsToString";
    197     static final String OP_LOCK_STAT = "getLockStats";
    198     static final String OP_LOCK_STAT_STR = "getLockStatsToString";
    199     static final String OP_TXN_STAT = "getTxnStats";
    200     static final String OP_DB_NAMES = "getDatabaseNames";
    201     static final String OP_DB_STAT = "getDatabaseStats";
    202
    203     private static final MBeanOperationInfo OP_CLEAN_INFO =
    204         new MBeanOperationInfo(OP_CLEAN,
    205                                "Remove obsolete environment log files. " +
    206                                "Zero or more log files will be cleaned as " +
    207                                "necessary to bring the disk space " +
    208                                "utilization of the environment above the " +
    209                                "configured minimum utilization threshold " +
    210                                "as determined by the setting " +
    211                                "je.cleaner.minUtilization. Returns the " +
    212                                "number of files cleaned, that will be " +
    213                                "deleted at the next qualifying checkpoint.",
    214                                new MBeanParameterInfo[0], // no params
    215                                "java.lang.Integer",
    216                                MBeanOperationInfo.UNKNOWN);
    217
    218     private static final MBeanOperationInfo OP_EVICT_INFO =
    219         new MBeanOperationInfo(OP_EVICT,
    220                                "Reduce cache usage to the threshold " +
    221                                "determined by the setting " +
    222                                "je.evictor.useMemoryFloor. ",
    223                                new MBeanParameterInfo[0], // no params
    224                                "void",
    225                                MBeanOperationInfo.UNKNOWN);
    226
    227     /* parameter for checkpoint operation. */
    228     private static final MBeanParameterInfo [] checkpointParams = {
    229         new MBeanParameterInfo ("force", "java.lang.Boolean",
    230                                 "If true, force a checkpoint even if " +
    231                                 "there has been no activity since the last " +
    232                                 "checkpoint. Returns true if a checkpoint " +
    233                                 "executed.")
    234     };
    235
    236     private static final MBeanOperationInfo OP_CHECKPOINT_INFO =
    237         new MBeanOperationInfo(OP_CHECKPOINT,
    238                                "Checkpoint the environment.",
    239                                checkpointParams,
    240                                "void",
    241                                MBeanOperationInfo.UNKNOWN);
    242
    243     private static final MBeanOperationInfo OP_SYNC_INFO =
    244         new MBeanOperationInfo(OP_SYNC,
    245                                "Flush the environment to stable storage.",
    246                                new MBeanParameterInfo[0], // no params
    247                                "void",
    248                                MBeanOperationInfo.UNKNOWN);
    249
    250     private static final MBeanParameterInfo [] statParams = {
    251         new MBeanParameterInfo ("clear", "java.lang.Boolean",
    252                                 "If true, reset statistics after reading."),
    253         new MBeanParameterInfo ("fast", "java.lang.Boolean",
    254                                 "If true, only return statistics which do " +
    255                                 "not require expensive computation.")
    256
    257     };
    258
    259     private static final MBeanOperationInfo OP_ENV_STAT_INFO =
    260         new MBeanOperationInfo(OP_ENV_STAT,
    261                                "Get environment statistics.",
    262                                statParams,
    263                                "com.sleepycat.je.EnvironmentStats",
    264                                MBeanOperationInfo.INFO);
    265
    266     private static final MBeanOperationInfo OP_ENV_STAT_STR_INFO =
    267         new MBeanOperationInfo(OP_ENV_STAT_STR,
    268                                "Get environment statistics.",
    269                                statParams,
    270                                "java.lang.String",
    271                                MBeanOperationInfo.INFO);
    272
    273     private static final MBeanOperationInfo OP_LOCK_STAT_INFO =
    274         new MBeanOperationInfo(OP_LOCK_STAT,
    275                                "Get locking statistics.",
    276                                statParams,
    277                                "com.sleepycat.je.LockStats",
    278                                MBeanOperationInfo.INFO);
    279
    280     private static final MBeanOperationInfo OP_LOCK_STAT_STR_INFO =
    281         new MBeanOperationInfo(OP_LOCK_STAT_STR,
    282                                "Get locking statistics.",
    283                                statParams,
    284                                "java.lang.String",
    285                                MBeanOperationInfo.INFO);
    286
    287     private static final MBeanOperationInfo OP_TXN_STAT_INFO =
    288         new MBeanOperationInfo(OP_TXN_STAT,
    289                                "Get transactional statistics.",
    290                                statParams,
    291                                "com.sleepycat.je.TransactionStats",
    292                                MBeanOperationInfo.INFO);
    293
    294     private static final MBeanOperationInfo OP_DB_NAMES_INFO =
    295         new MBeanOperationInfo(OP_DB_NAMES,
    296                               "Get the names of databases in the environment.",
    297                                new MBeanParameterInfo[0], // no params
    298                                "java.lang.String",
    299                                MBeanOperationInfo.INFO);
    300
    301     private static final MBeanOperationInfo OP_DB_STAT_INFO =
    302         new MBeanOperationInfo(OP_DB_STAT,
    303                                "Get database statistics.",
    304                                statParams,
    305                                "com.sleepycat.je.TransactionStats",
    306                                MBeanOperationInfo.INFO);
    307 /*
    308     private static final MBeanParameterInfo [] dbStatParams = {
    309         new MBeanParameterInfo ("clear", "java.lang.Boolean",
    310                                 "If true, reset statistics after reading."),
    311         new MBeanParameterInfo ("fast", "java.lang.Boolean",
    312                                 "If true, only return statistics which do " +
    313                                 "not require expensive computation."),
    314         new MBeanParameterInfo ("databaseName", "java.lang.String",
    315                                 "database name")
    316
    317     };
    318 */
    319     /* target JE environment home directory. */
    320     private File environmentHome;
    321
    322     /*
    323      * If canConfigure is true, this helper will make environment configuration
    324      * attributes available in the mbean metadata. Configuration attributes
    325      * will be saved in the openConfig instance.
    326      */
    327     private boolean canConfigure;
    328     private EnvironmentConfig openConfig;
    329
    330     /* true if the mbean metadata needs to be refreshed. */
    331     private boolean needReset;
    332
    333     /*
    334      * Save whether the environment was open the last time we fetched
    335      * mbean attributes. Use to detect a change in environment status.
    336      */
    337     private boolean envWasOpen;
    338
    339     /***
    340      * Instantiate a helper, specifying environment home and open capabilities.
    341      *
    342      * @param environmentHome home directory of the target JE environment.
    343      * @param canConfigure If true, the helper will show environment
    344      * configuration attributes.
    345      */
    346     public JEMBeanHelper(EnvironmentConfig config,
    347             File environmentHome, boolean canConfigure) {
    348
    349         if (environmentHome == null) {
    350             throw new IllegalArgumentException(
    351                                         "Environment home cannot be null");
    352         }
    353         this.environmentHome = environmentHome;
    354         this.canConfigure = canConfigure;
    355         if (canConfigure) {
    356             openConfig = config;
    357         }
    358     }
    359
    360     /***
    361      * Return the target environment directory.
    362      * @return the environment directory.
    363      */
    364     public File getEnvironmentHome() {
    365         return environmentHome;
    366     }
    367
    368     /***
    369      * If the helper was instantiated with canConfigure==true, it shows
    370      * environment configuration attributes. Those attributes are returned
    371      * within this EnvironmentConfig object for use in opening environments.
    372      *
    373      * @return EnvironmentConfig object which saves configuration attributes
    374      * recorded through MBean attributes.
    375      */
    376     public EnvironmentConfig getEnvironmentOpenConfig() {
    377         return openConfig;
    378     }
    379
    380     /***
    381      * Return an Environment only if the environment has already been opened
    382      * in this process. A helper method for MBeans which want to only access
    383      * open environments.
    384      * @return Environment if already open, null if not open.
    385      */
    386     public Environment getEnvironmentIfOpen() {
    387         if (environmentHome == null) {
    388             return null;
    389         }
    390
    391         return DbInternal.getEnvironmentShell(environmentHome);
    392     }
    393
    394     /***
    395      * Tell the MBean if the available set of functionality has changed.
    396      *
    397      * @return true if the MBean should regenerate its JE metadata.
    398      */
    399     public synchronized boolean getNeedReset() {
    400         return needReset;
    401     }
    402
    403     /*********************************************************************/
    404     /* MBean Attributes                                                 */
    405     /*********************************************************************/
    406
    407     /***
    408      * Get MBean attribute metadata for this environment.
    409      * @param targetEnv The target JE environment. May be null if the
    410      * environment is not open.
    411      * @return list of MBeanAttributeInfo objects describing the available
    412      * attributes.
    413      */
    414     public List<MBeanAttributeInfo> getAttributeList(Environment targetEnv) {
    415
    416         /* Turn off reset because the mbean metadata is being refreshed. */
    417         setNeedReset(false);
    418
    419         ArrayList<MBeanAttributeInfo> attrList
    420          = new ArrayList<MBeanAttributeInfo>();
    421
    422         /* Add attributes for all JE environments. */
    423         for (int i = 0; i < COMMON_ATTR.length; i++) {
    424             attrList.add(COMMON_ATTR[i]);
    425         }
    426
    427         if (targetEnv == null) {
    428             if (canConfigure) {
    429                 /* Add attributes for configuring an environment. */
    430                 for (int i = 0; i < CREATE_ATTR.length; i++) {
    431                     attrList.add(CREATE_ATTR[i]);
    432                 }
    433             }
    434         } else {
    435             /* Add attributes for an open environment. */
    436             for (int i = 0; i < OPEN_ATTR.length; i++) {
    437                 attrList.add(OPEN_ATTR[i]);
    438             }
    439
    440             /* Add attributes for an open, transactional environment. */
    441             try {
    442                 EnvironmentConfig config = targetEnv.getConfig();
    443                 if (config.getTransactional()) {
    444                     for (int i = 0; i < TRANSACTIONAL_ATTR.length; i++) {
    445                         attrList.add(TRANSACTIONAL_ATTR[i]);
    446                     }
    447                 }
    448             } catch (DatabaseException ignore) {
    449             	/* ignore */
    450             }
    451         }
    452
    453         return attrList;
    454     }
    455
    456     /***
    457      * Get an attribute value for the given environment. Check
    458      * JEMBeanHelper.getNeedReset() after this call because the helper may
    459      * detect that the environment has changed and that the MBean metadata
    460      * should be reset.
    461      *
    462      * @param targetEnv The target JE environment. May be null if the
    463      * environment is not open.
    464      * @param attributeName attribute name.
    465      * @return attribute value.
    466      */
    467     public Object getAttribute(Environment targetEnv,
    468                                String attributeName)
    469         throws AttributeNotFoundException,
    470                MBeanException {
    471
    472         /* Sanity check. */
    473         if (attributeName == null) {
    474             throw new AttributeNotFoundException(
    475                                             "Attribute name cannot be null");
    476         }
    477
    478         /* These attributes are available regardless of environment state. */
    479         try {
    480             if (attributeName.equals(ATT_ENV_HOME)) {
    481                 return environmentHome.getCanonicalPath();
    482             } else if (attributeName.equals(ATT_OPEN)) {
    483                 boolean envIsOpen = (targetEnv != null);
    484                 resetIfOpenStateChanged(envIsOpen);
    485                 return new Boolean(envIsOpen);
    486             } else if (attributeName.equals(ATT_SET_READ_ONLY)) {
    487                 return new Boolean(openConfig.getReadOnly());
    488             } else if (attributeName.equals(ATT_SET_TRANSACTIONAL)) {
    489                 return new Boolean(openConfig.getTransactional());
    490             } else if (attributeName.equals(ATT_SET_SERIALIZABLE)) {
    491                 return new Boolean(openConfig.getTxnSerializableIsolation());
    492             } else {
    493                 /* The rest are JE environment attributes. */
    494                 if (targetEnv != null) {
    495
    496                     EnvironmentConfig config = targetEnv.getConfig();
    497
    498                     if (attributeName.equals(ATT_IS_READ_ONLY)) {
    499                         return new Boolean(config.getReadOnly());
    500                     } else if (attributeName.equals(ATT_IS_TRANSACTIONAL)) {
    501                         return new Boolean(config.getTransactional());
    502                     } else if (attributeName.equals(ATT_CACHE_SIZE)) {
    503                         return new Long(config.getCacheSize());
    504                     } else if (attributeName.equals(ATT_CACHE_PERCENT)) {
    505                         return new Integer(config.getCachePercent());
    506                     } else if (attributeName.equals(ATT_LOCK_TIMEOUT)) {
    507                         return new Long(config.getLockTimeout());
    508                     } else if (attributeName.equals(ATT_IS_SERIALIZABLE)) {
    509                         return new
    510                             Boolean(config.getTxnSerializableIsolation());
    511                     } else if (attributeName.equals(ATT_TXN_TIMEOUT)) {
    512                         return new Long(config.getTxnTimeout());
    513                     } else {
    514                         throw new AttributeNotFoundException("attribute " +
    515                                                              attributeName +
    516                                                              " is not valid.");
    517                     }
    518                 }
    519                 return null;
    520             }
    521         } catch (Exception e) {
    522             /*
    523              * Add both the message and the exception for easiest deciphering
    524              * of the problem. Sometimes the original exception stacktrace gets
    525              * hidden in server logs.
    526              */
    527             throw new MBeanException(e, e.getMessage());
    528         }
    529     }
    530
    531     /***
    532      * Set an attribute value for the given environment.
    533      *
    534      * @param targetEnv The target JE environment. May be null if the
    535      * environment is not open.
    536      * @param attribute name/value pair
    537      */
    538     public void setAttribute(Environment targetEnv,
    539                              Attribute attribute)
    540         throws AttributeNotFoundException,
    541                InvalidAttributeValueException {
    542
    543         if (attribute == null) {
    544             throw new AttributeNotFoundException("Attribute cannot be null");
    545         }
    546
    547         /* Sanity check parameters. */
    548         String name = attribute.getName();
    549         Object value = attribute.getValue();
    550
    551 	if (name == null) {
    552 	    throw new AttributeNotFoundException(
    553                                      "Attribute name cannot be null");
    554 	}
    555
    556 	if (value == null) {
    557 	    throw new InvalidAttributeValueException(
    558                                       "Attribute value for attribute " +
    559                                       name + " cannot be null");
    560 	}
    561
    562         try {
    563             if (name.equals(ATT_SET_READ_ONLY)) {
    564                 openConfig.setReadOnly(((Boolean) value).booleanValue());
    565             } else if (name.equals(ATT_SET_TRANSACTIONAL)) {
    566                 openConfig.setTransactional(((Boolean) value).booleanValue());
    567             } else if (name.equals(ATT_SET_SERIALIZABLE)) {
    568                 openConfig.setTxnSerializableIsolation(
    569                                              ((Boolean) value).booleanValue());
    570             } else {
    571                 /* Set the specified attribute if the environment is open. */
    572                 if (targetEnv != null) {
    573
    574                     EnvironmentMutableConfig config =
    575                         targetEnv.getMutableConfig();
    576
    577                     if (name.equals(ATT_CACHE_SIZE)) {
    578                         config.setCacheSize(((Long) value).longValue());
    579                         targetEnv.setMutableConfig(config);
    580                     } else if (name.equals(ATT_CACHE_PERCENT)) {
    581                         config.setCachePercent(((Integer) value).intValue());
    582                         targetEnv.setMutableConfig(config);
    583                     } else {
    584                         throw new AttributeNotFoundException("attribute " +
    585                                                              name +
    586                                                              " is not valid.");
    587                     }
    588                 } else {
    589                     throw new AttributeNotFoundException("attribute " +
    590                                                          name +
    591                                                          " is not valid.");
    592                 }
    593             }
    594         } catch (NumberFormatException e) {
    595             throw new InvalidAttributeValueException("attribute name=" + name);
    596         } catch (DatabaseException e) {
    597             throw new InvalidAttributeValueException("attribute name=" + name +
    598                                                      e.getMessage());
    599         }
    600     }
    601
    602     /*********************************************************************/
    603     /* JE Operations                                                    */
    604     /*********************************************************************/
    605
    606     /***
    607      * Get mbean operation metadata for this environment.
    608      *
    609      * @param targetEnv The target JE environment. May be null if the
    610      * environment is not open.
    611      * @return List of MBeanOperationInfo describing available operations.
    612      */
    613     public List<MBeanOperationInfo> getOperationList(Environment targetEnv) {
    614         setNeedReset(false);
    615
    616         List<MBeanOperationInfo> operationList = new ArrayList<MBeanOperationInfo>();
    617
    618         if (targetEnv != null) {
    619             /*
    620              * These operations are only available if the environment is
    621              * open.
    622              */
    623             operationList.add(OP_CLEAN_INFO);
    624             operationList.add(OP_EVICT_INFO);
    625             operationList.add(OP_ENV_STAT_INFO);
    626             operationList.add(OP_ENV_STAT_STR_INFO);
    627             operationList.add(OP_LOCK_STAT_INFO);
    628             operationList.add(OP_LOCK_STAT_STR_INFO);
    629             operationList.add(OP_DB_NAMES_INFO);
    630             operationList.add(OP_DB_STAT_INFO);
    631
    632             /* Add checkpoint only for transactional environments. */
    633             boolean isTransactional = false;
    634             try {
    635                 EnvironmentConfig config = targetEnv.getConfig();
    636                 isTransactional = config.getTransactional();
    637             } catch (DatabaseException e) {
    638                 /* Don't make any operations available. */
    639                 return new ArrayList<MBeanOperationInfo>();
    640             }
    641
    642             if (isTransactional) {
    643                 operationList.add(OP_CHECKPOINT_INFO);
    644                 operationList.add(OP_TXN_STAT_INFO);
    645             } else {
    646                 operationList.add(OP_SYNC_INFO);
    647             }
    648         }
    649
    650         return operationList;
    651     }
    652
    653     /***
    654      * Invoke an operation for the given environment.
    655      *
    656      * @param targetEnv The target JE environment. May be null if the
    657      * environment is not open.
    658      * @param actionName operation name.
    659      * @param params operation parameters. May be null.
    660      * @param signature operation signature. May be null.
    661      * @return the operation result
    662      */
    663     public Object invoke(Environment targetEnv,
    664                          String actionName,
    665                          Object [] params,
    666                          String [] signature)
    667         throws MBeanException {
    668
    669         /* Sanity checking. */
    670         if (actionName == null) {
    671             throw new IllegalArgumentException("actionName cannot be null");
    672         }
    673
    674         try {
    675             if (targetEnv != null) {
    676                 if (actionName.equals(OP_CLEAN)) {
    677                     int numFiles = targetEnv.cleanLog();
    678                     return new Integer(numFiles);
    679                 } else if (actionName.equals(OP_EVICT)) {
    680                     targetEnv.evictMemory();
    681                     return null;
    682                 } else if (actionName.equals(OP_CHECKPOINT)) {
    683                     CheckpointConfig config = new CheckpointConfig();
    684                     if ((params != null) && (params.length > 0)) {
    685                         Boolean force = (Boolean) params[0];
    686                         config.setForce(force.booleanValue());
    687                     }
    688                     targetEnv.checkpoint(config);
    689                     return null;
    690                 } else if (actionName.equals(OP_SYNC)) {
    691                     targetEnv.sync();
    692                     return null;
    693                 } else if (actionName.equals(OP_ENV_STAT)) {
    694                     return targetEnv.getStats(getStatsConfig(params));
    695                 } else if (actionName.equals(OP_ENV_STAT_STR)) {
    696                     return targetEnv.getStats(getStatsConfig(params)).toString();
    697                 } else if (actionName.equals(OP_LOCK_STAT)) {
    698                     return targetEnv.getLockStats(getStatsConfig(params));
    699                 } else if (actionName.equals(OP_LOCK_STAT_STR)) {
    700                     return targetEnv.getLockStats(getStatsConfig(params)).toString();
    701                 } else if (actionName.equals(OP_TXN_STAT)) {
    702                     return targetEnv.getTransactionStats(
    703                                                        getStatsConfig(params));
    704                 } else if (actionName.equals(OP_DB_NAMES)) {
    705                     return targetEnv.getDatabaseNames();
    706                 } else if (actionName.equals(OP_DB_STAT)) {
    707                     return getDatabaseStats(targetEnv, params);
    708                 }
    709             }
    710
    711             return new IllegalArgumentException("actionName: " +
    712                                                 actionName +
    713                                                 " is not valid");
    714         } catch (DatabaseException e) {
    715             /*
    716              * Add both the message and the exception for easiest
    717              * deciphering of the problem. Sometimes the original exception
    718              * stacktrace gets hidden in server logs.
    719              */
    720             throw new MBeanException(e, e.getMessage());
    721         }
    722     }
    723
    724     /***
    725      * Helper for creating a StatsConfig object to use as an operation
    726      * parameter.
    727      */
    728     private StatsConfig getStatsConfig(Object [] params) {
    729         StatsConfig statsConfig = new StatsConfig();
    730         if ((params != null) && (params.length > 0) && (params[0] != null)) {
    731             Boolean clear = (Boolean) params[0];
    732             statsConfig.setClear(clear.booleanValue());
    733         }
    734         if ((params != null) && (params.length > 1) && (params[1] != null)) {
    735             Boolean fast = (Boolean) params[1];
    736             statsConfig.setFast(fast.booleanValue());
    737         }
    738         return statsConfig;
    739     }
    740
    741     /***
    742      * Helper to get statistics for a given database.
    743      * @param params operation parameters
    744      * @return DatabaseStats object
    745      */
    746     private DatabaseStats getDatabaseStats(Environment targetEnv,
    747                                            Object [] params)
    748         throws IllegalArgumentException,
    749 	       DatabaseException {
    750
    751         if ((params == null) || (params.length < 3)) {
    752             return null;
    753         }
    754         String dbName = (String)params[2];
    755
    756         Database db = null;
    757         try {
    758             DatabaseConfig dbConfig = new DatabaseConfig();
    759             dbConfig.setReadOnly(true);
    760             DbInternal.setUseExistingConfig(dbConfig, true);
    761             db = targetEnv.openDatabase(null, dbName, dbConfig);
    762             return db.getStats(getStatsConfig(params));
    763         } finally {
    764             if (db != null) {
    765                 db.close();
    766             }
    767         }
    768     }
    769
    770     /*********************************************************************/
    771     /* JE Notifications.
    772     /********************************************************************/
    773
    774     /***
    775      * No notifications are supported.
    776      * @return List of MBeanNotificationInfo for available notifications.
    777      */
    778     public MBeanNotificationInfo []
    779         getNotificationInfo(Environment targetEnv) {
    780         return null;
    781     }
    782
    783     /*********************************************************************/
    784     /* private helpers.
    785     /********************************************************************/
    786
    787     private synchronized void setNeedReset(boolean reset) {
    788         needReset = reset;
    789     }
    790
    791     private synchronized void resetIfOpenStateChanged(boolean isOpen) {
    792         if (isOpen != envWasOpen) {
    793             setNeedReset(true);
    794             envWasOpen = isOpen;
    795         }
    796     }
    797 }
    798