001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: JEApplicationMBean.java,v 1.6.2.2 2008/01/07 15:14:04 cwl Exp $
007: */
008:
009: package jmx;
010:
011: import java.io.File;
012: import java.lang.reflect.Constructor;
013: import java.util.List;
014:
015: import javax.management.Attribute;
016: import javax.management.AttributeList;
017: import javax.management.AttributeNotFoundException;
018: import javax.management.DynamicMBean;
019: import javax.management.InvalidAttributeValueException;
020: import javax.management.MBeanAttributeInfo;
021: import javax.management.MBeanConstructorInfo;
022: import javax.management.MBeanException;
023: import javax.management.MBeanInfo;
024: import javax.management.MBeanNotificationInfo;
025: import javax.management.MBeanOperationInfo;
026: import javax.management.MBeanParameterInfo;
027:
028: import com.sleepycat.je.DatabaseException;
029: import com.sleepycat.je.Environment;
030: import com.sleepycat.je.jmx.JEMBeanHelper;
031:
032: /**
033: * JEApplicationMBean is an example of how a JE application can incorporate JE
034: * monitoring into its existing MBean. It may be installed as is, or used as a
035: * starting point for building a MBean which includes JE support.
036: * <p>
037: * JE management is divided between the JEApplicationMBean class and
038: * JEMBeanHelper class. JEApplicationMBean contains an instance of
039: * JEMBeanHelper, which knows about JE attributes, operations and
040: * notifications. JEApplicationMBean itself has the responsibility of
041: * configuring, opening and closing the JE environment along with any other
042: * resources used by the application, and maintains a
043: * com.sleepycat.je.Environment handle.
044: * <p>
045: * The approach taken for accessing the environment is an application specific
046: * choice. Some of the salient considerations are:
047: * <ul>
048: * <li>Applications may open one or many Environment objects per process
049: * against a given environment.</li>
050: *
051: * <li>All Environment handles reference the same underlying JE environment
052: * implementation object.</li>
053:
054: * <li> The first Environment object instantiated in the process does the real
055: * work of configuring and opening the environment. Follow-on instantiations of
056: * Environment merely increment a reference count. Likewise,
057: * Environment.close() only does real work when it's called by the last
058: * Environment object in the process. </li>
059: * </ul>
060: * <p>
061: * Another MBean approach for environment access can be seen in
062: * com.sleepycat.je.jmx.JEMonitor. That MBean does not take responsibility for
063: * opening and closing environments, and can only operate against already-open
064: * environments.
065: */
066:
067: public class JEApplicationMBean implements DynamicMBean {
068:
069: private static final String DESCRIPTION = "A MBean for an application which uses JE. Provides open and close "
070: + "operations which configure and open a JE environment as part of the "
071: + "applications's resources. Also supports general JE monitoring.";
072:
073: private MBeanInfo mbeanInfo; // this MBean's visible interface.
074: private JEMBeanHelper jeHelper; // gets JE management interface
075: private Environment targetEnv; // saved environment handle
076:
077: /**
078: * This MBean provides an open operation to open the JE environment.
079: */
080: public static final String OP_OPEN = "openJE";
081:
082: /**
083: * This MBean provides a close operation to release the JE environment.
084: * Note that environments must be closed to release resources.
085: */
086: public static final String OP_CLOSE = "closeJE";
087:
088: /**
089: * Instantiate a JEApplicationMBean
090: *
091: * @param environmentHome home directory of the target JE environment.
092: */
093: public JEApplicationMBean(String environmentHome) {
094:
095: File environmentDirectory = new File(environmentHome);
096: jeHelper = new JEMBeanHelper(environmentDirectory, true);
097: resetMBeanInfo();
098: }
099:
100: /**
101: * @see DynamicMBean#getAttribute
102: */
103: public Object getAttribute(String attributeName)
104: throws AttributeNotFoundException, MBeanException {
105:
106: return jeHelper.getAttribute(targetEnv, attributeName);
107: }
108:
109: /**
110: * @see DynamicMBean#setAttribute
111: */
112: public void setAttribute(Attribute attribute)
113: throws AttributeNotFoundException,
114: InvalidAttributeValueException {
115:
116: jeHelper.setAttribute(targetEnv, attribute);
117: }
118:
119: /**
120: * @see DynamicMBean#getAttributes
121: */
122: public AttributeList getAttributes(String[] attributes) {
123:
124: /* Sanity checking. */
125: if (attributes == null) {
126: throw new IllegalArgumentException(
127: "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: */
147: public AttributeList setAttributes(AttributeList attributes) {
148:
149: /* Sanity checking. */
150: if (attributes == null) {
151: throw new IllegalArgumentException(
152: "attribute list can't be null");
153: }
154:
155: /* Set each attribute specified. */
156: AttributeList results = new AttributeList();
157: for (int i = 0; i < attributes.size(); i++) {
158: Attribute attr = (Attribute) attributes.get(i);
159: try {
160: /* Set new value. */
161: jeHelper.setAttribute(targetEnv, attr);
162:
163: /*
164: * Add the name and new value to the result list. Be sure
165: * to ask the MBean for the new value, rather than simply
166: * using attr.getValue(), because the new value may not
167: * be same if it is modified according to the JE
168: * implementation.
169: */
170: String name = attr.getName();
171: Object newValue = jeHelper
172: .getAttribute(targetEnv, name);
173: results.add(new Attribute(name, newValue));
174: } catch (Exception e) {
175: e.printStackTrace();
176: }
177: }
178: return results;
179: }
180:
181: /**
182: * @see DynamicMBean#invoke
183: */
184: public Object invoke(String actionName, Object[] params,
185: String[] signature) throws MBeanException {
186:
187: Object result = null;
188:
189: if (actionName == null) {
190: throw new IllegalArgumentException(
191: "actionName cannot be null");
192: }
193:
194: if (actionName.equals(OP_OPEN)) {
195: openEnvironment();
196: return null;
197: } else if (actionName.equals(OP_CLOSE)) {
198: closeEnvironment();
199: return null;
200: } else {
201: result = jeHelper.invoke(targetEnv, actionName, params,
202: signature);
203: }
204:
205: return result;
206: }
207:
208: /**
209: * @see DynamicMBean#getMBeanInfo
210: */
211: public MBeanInfo getMBeanInfo() {
212: return mbeanInfo;
213: }
214:
215: /**
216: * Create the available management interface for this environment.
217: * The attributes and operations available vary according to
218: * environment configuration.
219: *
220: */
221: private synchronized void resetMBeanInfo() {
222:
223: /*
224: * Get JE attributes, operation and notification information
225: * from JEMBeanHelper. An application may choose to add functionality
226: * of its own when constructing the MBeanInfo.
227: */
228:
229: /* Attributes. */
230: List attributeList = jeHelper.getAttributeList(targetEnv);
231: MBeanAttributeInfo[] attributeInfo = new MBeanAttributeInfo[attributeList
232: .size()];
233: attributeList.toArray(attributeInfo);
234:
235: /* Constructors. */
236: Constructor[] constructors = this .getClass().getConstructors();
237: MBeanConstructorInfo[] constructorInfo = new MBeanConstructorInfo[constructors.length];
238: for (int i = 0; i < constructors.length; i++) {
239: constructorInfo[i] = new MBeanConstructorInfo(this
240: .getClass().getName(), 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
252: .add(new MBeanOperationInfo(
253: OP_OPEN,
254: "Configure and open the JE environment.",
255: new MBeanParameterInfo[0], // no params
256: "java.lang.Boolean",
257: MBeanOperationInfo.ACTION_INFO));
258: } else {
259: operationList.add(new MBeanOperationInfo(OP_CLOSE,
260: "Close the JE environment.",
261: new MBeanParameterInfo[0], // no params
262: "void", MBeanOperationInfo.ACTION_INFO));
263: }
264:
265: MBeanOperationInfo[] operationInfo = new MBeanOperationInfo[operationList
266: .size()];
267: operationList.toArray(operationInfo);
268:
269: /* Notifications. */
270: MBeanNotificationInfo[] notificationInfo = jeHelper
271: .getNotificationInfo(targetEnv);
272:
273: /* Generate the MBean description. */
274: mbeanInfo = new MBeanInfo(this .getClass().getName(),
275: DESCRIPTION, attributeInfo, constructorInfo,
276: operationInfo, notificationInfo);
277: }
278:
279: /**
280: * Open a JE environment using the configuration specified through
281: * MBean attributes and recorded within the JEMBeanHelper.
282: */
283: private void openEnvironment() throws MBeanException {
284:
285: try {
286: if (targetEnv == null) {
287: /*
288: * The environment configuration has been set through
289: * mbean attributes managed by the JEMBeanHelper.
290: */
291: targetEnv = new Environment(jeHelper
292: .getEnvironmentHome(), jeHelper
293: .getEnvironmentOpenConfig());
294: resetMBeanInfo();
295: }
296: } catch (DatabaseException e) {
297: throw new MBeanException(e);
298: }
299: }
300:
301: /**
302: * Release the environment handle contained within the MBean to properly
303: * release resources.
304: */
305: private void closeEnvironment() throws MBeanException {
306:
307: try {
308: if (targetEnv != null) {
309: targetEnv.close();
310: targetEnv = null;
311: resetMBeanInfo();
312: }
313: } catch (DatabaseException e) {
314: throw new MBeanException(e);
315: }
316: }
317: }
|