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 jmx;
9 
10 import java.io.File;
11 import java.lang.reflect.Constructor;
12 import java.util.List;
13 
14 import javax.management.Attribute;
15 import javax.management.AttributeList;
16 import javax.management.AttributeNotFoundException;
17 import javax.management.DynamicMBean;
18 import javax.management.InvalidAttributeValueException;
19 import javax.management.MBeanAttributeInfo;
20 import javax.management.MBeanConstructorInfo;
21 import javax.management.MBeanException;
22 import javax.management.MBeanInfo;
23 import javax.management.MBeanNotificationInfo;
24 import javax.management.MBeanOperationInfo;
25 import javax.management.MBeanParameterInfo;
26 
27 import com.sleepycat.je.DatabaseException;
28 import com.sleepycat.je.Environment;
29 import com.sleepycat.je.jmx.JEMBeanHelper;
30 
31 /**
32  * JEApplicationMBean is an example of how a JE application can incorporate JE
33  * monitoring into its existing MBean.  It may be installed as is, or used as a
34  * starting point for building a MBean which includes JE support.
35  * <p>
36  * JE management is divided between the JEApplicationMBean class and
37  * JEMBeanHelper class. JEApplicationMBean contains an instance of
38  * JEMBeanHelper, which knows about JE attributes, operations and
39  * notifications. JEApplicationMBean itself has the responsibility of
40  * configuring, opening and closing the JE environment along with any other
41  * resources used by the application, and maintains a
42  * com.sleepycat.je.Environment handle.
43  * <p>
44  * The approach taken for accessing the environment is an application specific
45  * choice. Some of the salient considerations are:
46  * <ul>
47  * <li>Applications may open one or many Environment objects per process
48  * against a given environment.</li>
49  *
50  * <li>All Environment handles reference the same underlying JE environment
51  * implementation object.</li>
52 
53  * <li> The first Environment object instantiated in the process does the real
54  * work of configuring and opening the environment. Follow-on instantiations of
55  * Environment merely increment a reference count. Likewise,
56  * Environment.close() only does real work when it's called by the last
57  * Environment object in the process. </li>
58  * </ul>
59  * <p>
60  * Another MBean approach for environment access can be seen in
61  * com.sleepycat.je.jmx.JEMonitor. That MBean does not take responsibility for
62  * opening and closing environments, and can only operate against already-open
63  * environments.
64  */
65 
66 public class JEApplicationMBean implements DynamicMBean {
67 
68     private static final String DESCRIPTION =
69         "A MBean for an application which uses JE. Provides open and close " +
70         "operations which configure and open a JE environment as part of the "+
71         "applications's resources. Also supports general JE monitoring.";
72 
73     private MBeanInfo mbeanInfo;    // this MBean's visible interface.
74     private JEMBeanHelper jeHelper; // gets JE management interface
75     private Environment targetEnv;  // saved environment handle
76 
77     /**
78      * This MBean provides an open operation to open the JE environment.
79      */
80     public  static final String OP_OPEN = "openJE";
81 
82     /**
83      * This MBean provides a close operation to release the JE environment.
84      * Note that environments must be closed to release resources.
85      */
86     public static final String OP_CLOSE = "closeJE";
87 
88     /**
89      * Instantiate a JEApplicationMBean
90      *
91      * @param environmentHome home directory of the target JE environment.
92      */
JEApplicationMBean(String environmentHome)93     public JEApplicationMBean(String environmentHome) {
94 
95         File environmentDirectory = new File(environmentHome);
96         jeHelper = new JEMBeanHelper(environmentDirectory, true);
97         resetMBeanInfo();
98     }
99 
100     /**
101      * @see DynamicMBean#getAttribute
102      */
getAttribute(String attributeName)103     public Object getAttribute(String attributeName)
104         throws AttributeNotFoundException,
105                MBeanException {
106 
107             return jeHelper.getAttribute(targetEnv, attributeName);
108     }
109 
110     /**
111      * @see DynamicMBean#setAttribute
112      */
setAttribute(Attribute attribute)113     public void setAttribute(Attribute attribute)
114         throws AttributeNotFoundException,
115                InvalidAttributeValueException {
116 
117         jeHelper.setAttribute(targetEnv, attribute);
118     }
119 
120     /**
121      * @see DynamicMBean#getAttributes
122      */
getAttributes(String[] attributes)123     public AttributeList getAttributes(String[] attributes) {
124 
125         /* Sanity checking. */
126         if (attributes == null) {
127             throw new IllegalArgumentException("Attributes cannot be null");
128         }
129 
130         /* Get each requested attribute. */
131         AttributeList results = new AttributeList();
132         for (int i = 0; i < attributes.length; i++) {
133             try {
134                 String name = attributes[i];
135                 Object value = jeHelper.getAttribute(targetEnv, name);
136                 results.add(new Attribute(name, value));
137             } catch (Exception e) {
138                 e.printStackTrace();
139             }
140         }
141         return results;
142     }
143 
144     /**
145      * @see DynamicMBean#setAttributes
146      */
setAttributes(AttributeList attributes)147     public AttributeList setAttributes(AttributeList attributes) {
148 
149         /* Sanity checking. */
150         if (attributes == null) {
151             throw new IllegalArgumentException("attribute list can't be null");
152         }
153 
154         /* Set each attribute specified. */
155         AttributeList results = new AttributeList();
156         for (int i = 0; i < attributes.size(); i++) {
157             Attribute attr = (Attribute) attributes.get(i);
158             try {
159                 /* Set new value. */
160                 jeHelper.setAttribute(targetEnv, attr);
161 
162                 /*
163                  * Add the name and new value to the result list. Be sure
164                  * to ask the MBean for the new value, rather than simply
165                  * using attr.getValue(), because the new value may not
166                  * be same if it is modified according to the JE
167                  * implementation.
168                  */
169                 String name = attr.getName();
170                 Object newValue = jeHelper.getAttribute(targetEnv, name);
171                 results.add(new Attribute(name, newValue));
172             } catch (Exception e) {
173                 e.printStackTrace();
174             }
175         }
176         return results;
177     }
178 
179     /**
180      * @see DynamicMBean#invoke
181      */
invoke(String actionName, Object[] params, String[] signature)182     public Object invoke(String actionName,
183                          Object[] params,
184                          String[] signature)
185         throws MBeanException {
186 
187         Object result = null;
188 
189         if (actionName == null) {
190             throw new IllegalArgumentException("actionName cannot be null");
191         }
192 
193         if (actionName.equals(OP_OPEN)) {
194             openEnvironment();
195             return null;
196         } else if (actionName.equals(OP_CLOSE)) {
197             closeEnvironment();
198             return null;
199         } else {
200             result = jeHelper.invoke(targetEnv, actionName, params, signature);
201         }
202 
203         return result;
204     }
205 
206     /**
207      * @see DynamicMBean#getMBeanInfo
208      */
getMBeanInfo()209     public MBeanInfo getMBeanInfo() {
210         return mbeanInfo;
211     }
212 
213     /**
214      * Create the available management interface for this environment.
215      * The attributes and operations available vary according to
216      * environment configuration.
217      *
218      */
resetMBeanInfo()219     private synchronized void resetMBeanInfo() {
220 
221         /*
222          * Get JE attributes, operation and notification information
223          * from JEMBeanHelper. An application may choose to add functionality
224          * of its own when constructing the MBeanInfo.
225          */
226 
227         /* Attributes. */
228         List attributeList =  jeHelper.getAttributeList(targetEnv);
229         MBeanAttributeInfo[] attributeInfo =
230             new MBeanAttributeInfo[attributeList.size()];
231         attributeList.toArray(attributeInfo);
232 
233         /* Constructors. */
234         Constructor[] constructors = this.getClass().getConstructors();
235         MBeanConstructorInfo[] constructorInfo =
236             new MBeanConstructorInfo[constructors.length];
237         for (int i = 0; i < constructors.length; i++) {
238             constructorInfo[i] =
239                 new MBeanConstructorInfo(this.getClass().getName(),
240                                          constructors[i]);
241         }
242 
243         /* Operations. */
244 
245         /*
246          * Get the list of operations available from the jeHelper. Then add
247          * an open and close operation.
248          */
249         List operationList = jeHelper.getOperationList(targetEnv);
250         if (targetEnv == null) {
251             operationList.add(
252              new MBeanOperationInfo(OP_OPEN,
253                                     "Configure and open the JE environment.",
254                                     new MBeanParameterInfo[0], // no params
255                                     "java.lang.Boolean",
256                                     MBeanOperationInfo.ACTION_INFO));
257         } else {
258             operationList.add(
259              new MBeanOperationInfo(OP_CLOSE,
260                                     "Close the JE environment.",
261                                     new MBeanParameterInfo[0], // no params
262                                     "void",
263                                     MBeanOperationInfo.ACTION_INFO));
264         }
265 
266         MBeanOperationInfo[] operationInfo =
267             new MBeanOperationInfo[operationList.size()];
268         operationList.toArray(operationInfo);
269 
270         /* Notifications. */
271         MBeanNotificationInfo[] notificationInfo =
272             jeHelper.getNotificationInfo(targetEnv);
273 
274         /* Generate the MBean description. */
275         mbeanInfo = new MBeanInfo(this.getClass().getName(),
276                                   DESCRIPTION,
277                                   attributeInfo,
278                                   constructorInfo,
279                                   operationInfo,
280                                   notificationInfo);
281     }
282 
283     /**
284      * Open a JE environment using the configuration specified through
285      * MBean attributes and recorded within the JEMBeanHelper.
286      */
openEnvironment()287     private  void openEnvironment()
288         throws MBeanException {
289 
290         try {
291             if (targetEnv == null) {
292                 /*
293                  * The environment configuration has been set through
294                  * mbean attributes managed by the JEMBeanHelper.
295                  */
296                 targetEnv =
297                     new Environment(jeHelper.getEnvironmentHome(),
298                                     jeHelper.getEnvironmentOpenConfig());
299                 resetMBeanInfo();
300             }
301         } catch (DatabaseException e) {
302             throw new MBeanException(e);
303         }
304     }
305 
306     /**
307      * Release the environment handle contained within the MBean to properly
308      * release resources.
309      */
closeEnvironment()310     private void closeEnvironment()
311         throws MBeanException {
312 
313         try {
314             if (targetEnv != null) {
315                 targetEnv.close();
316                 targetEnv = null;
317                 resetMBeanInfo();
318             }
319         } catch (DatabaseException e) {
320             throw new MBeanException(e);
321         }
322     }
323 }
324