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