View Javadoc

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