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