001: /* JFox, the OpenSource J2EE Application Server
002: *
003: * Copyright (C) 2002 huihoo.org
004: * Distributable under GNU LGPL license
005: * See the GNU Lesser General Public License for more details.
006: */
007:
008: package example.jmx.openmbean;
009:
010: import java.io.PrintWriter;
011: import java.io.ByteArrayOutputStream;
012: import java.util.Arrays;
013:
014: import javax.management.openmbean.OpenMBeanInfoSupport;
015: import javax.management.openmbean.OpenMBeanOperationInfoSupport;
016: import javax.management.openmbean.OpenMBeanParameterInfoSupport;
017: import javax.management.openmbean.OpenMBeanParameterInfo;
018: import javax.management.openmbean.SimpleType;
019: import javax.management.openmbean.OpenMBeanConstructorInfoSupport;
020: import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
021: import javax.management.openmbean.OpenDataException;
022: import javax.management.openmbean.CompositeData;
023: import javax.management.openmbean.CompositeDataSupport;
024: import javax.management.openmbean.KeyAlreadyExistsException;
025: import javax.management.openmbean.TabularData;
026: import javax.management.openmbean.TabularDataSupport;
027: import javax.management.openmbean.TabularType;
028: import javax.management.openmbean.CompositeType;
029: import javax.management.openmbean.OpenType;
030: import javax.management.MBeanOperationInfo;
031: import javax.management.MBeanNotificationInfo;
032: import javax.management.MBeanInfo;
033: import javax.management.ReflectionException;
034: import javax.management.MBeanException;
035: import javax.management.RuntimeOperationsException;
036: import javax.management.AttributeList;
037: import javax.management.Attribute;
038: import javax.management.AttributeNotFoundException;
039: import javax.management.InvalidAttributeValueException;
040: import javax.management.DynamicMBean;
041:
042: /**
043: *
044: * @author <a href="mailto:young_yy@hotmail.org">Young Yang</a>
045: */
046:
047: public class SimpleOpenMBean implements DynamicMBean {
048:
049: // Open MBean Info
050: //
051: private OpenMBeanInfoSupport OMBInfo;
052:
053: // Attributes exposed for management
054: //
055: private TabularDataSupport tShirts;
056: private int nbChanges = 0;
057:
058: // Custom open types (and related info) used by this Open MBean class
059: //
060: private static String[] itemNames = { "model", "color", "size",
061: "price" };
062: private static String[] itemDescriptions = { "TShirt's model name",
063: "TShirt's color", "TShirt's size", "TShirt's price" };
064: private static OpenType[] itemTypes = { SimpleType.STRING,
065: SimpleType.STRING, SimpleType.STRING, SimpleType.FLOAT };
066: private static CompositeType tShirtType = null;
067:
068: // TShirts are indexed according to their model, color and size:
069: private static String[] indexNames = { "model", "color", "size" };
070: private static TabularType tShirtsType = null;
071:
072: // Legal values for TShirt features
073: //
074: private static String[] legalModels = { "JDMK", "JMX", "JAVA" };
075: private static OpenMBeanParameterInfoSupport modelParamInfo;
076:
077: private static String[] legalColors = { "black", "white", "red",
078: "green", "blue" };
079: private static OpenMBeanParameterInfoSupport colorParamInfo;
080:
081: private static String[] legalSizes = { "S", "M", "L", "XL", "XXL" };
082: private static OpenMBeanParameterInfoSupport sizeParamInfo;
083:
084: private static float minPrice = 9.00f;
085: private static float maxPrice = 19.99f;
086: private static OpenMBeanParameterInfoSupport priceParamInfo;
087:
088: /* *** Static initialization *** */
089:
090: static {
091:
092: // initializes OpenType instances and ParameterInfo instances
093: //
094: try {
095:
096: // CompositeType instance for a TShirt
097: //
098: tShirtType = new CompositeType("tShirt", "a TShirt",
099: itemNames, itemDescriptions, itemTypes);
100:
101: // TabularType instance for the list of TShirts
102: //
103: tShirtsType = new TabularType("tShirts",
104: "List of available TShirts", tShirtType, // row type
105: indexNames);
106:
107: // Parameter info for the model, color, size and price parameters
108: //
109: modelParamInfo = new OpenMBeanParameterInfoSupport("model",
110: "Valid TShirt model name. Legal models: "
111: + Arrays.asList(legalModels).toString(),
112: SimpleType.STRING, "JMX", // default model is JMX
113: legalModels); // array of legal models
114: colorParamInfo = new OpenMBeanParameterInfoSupport("color",
115: "Valid product color. Legal colors: "
116: + Arrays.asList(legalColors).toString(),
117: SimpleType.STRING, "white", // default color is white
118: legalColors); // array of legal colors
119: sizeParamInfo = new OpenMBeanParameterInfoSupport("size",
120: "Valid product size. Legal sizes: "
121: + Arrays.asList(legalSizes).toString(),
122: SimpleType.STRING, "XL", // default size is XL
123: legalSizes); // array of legal sizes
124: priceParamInfo = new OpenMBeanParameterInfoSupport("price",
125: "Valid product price (ranging from $" + minPrice
126: + " to $" + maxPrice + ")",
127: SimpleType.FLOAT, null, // no default price
128: new Float(minPrice), // Min legal value for price
129: new Float(maxPrice)); // Max legal value for price
130:
131: } catch (OpenDataException e) {
132: // should not happen
133: ByteArrayOutputStream bout = new ByteArrayOutputStream();
134: PrintWriter pout = new PrintWriter(bout);
135: e.printStackTrace(pout);
136: pout.flush();
137: throw new RuntimeException(bout.toString());
138: }
139:
140: }
141:
142: /* *** Contructor *** */
143:
144: /**
145: * Constructs a SimpleOpenMBean instance containing an empty TShirts list
146: */
147: public SimpleOpenMBean() throws OpenDataException {
148:
149: buildMBeanInfo();
150:
151: // Create empty TShirts list
152: tShirts = new TabularDataSupport(tShirtsType);
153: }
154:
155: /* *** Getters *** */
156:
157: /**
158: * Returns a clone of the TShirts list
159: */
160: public TabularData getTShirts() {
161: return (TabularData) tShirts.clone();
162: }
163:
164: /**
165: * Returns the number of time the TShirts list has been updated
166: */
167: public Integer getNbChanges() {
168: return new Integer(nbChanges);
169: }
170:
171: /* *** Operations *** */
172:
173: /**
174: * Adds the tShirt given in parameter to the list of available tShirts, if it does not already exist
175: * and returns Boolean.TRUE if succesful, Boolean.FALSE otherwise.
176: */
177: public Boolean addTShirt(CompositeData tShirt) {
178:
179: try {
180: tShirts.put(tShirt); // throws KeyAlreadyExistsException if index for tShirt already exists in tShirts
181: nbChanges++;
182: return Boolean.TRUE;
183: } catch (KeyAlreadyExistsException e) {
184: return Boolean.FALSE;
185: }
186: }
187:
188: /**
189: * Checks param is a valid value for the specified paramInfo and returns param's value
190: * (returns the default value if param is null and paramInfo defines one),
191: * or throws an OpenDataException otherwise.
192: */
193: protected Object checkParam(OpenMBeanParameterInfo paramInfo,
194: Object param) throws OpenDataException {
195:
196: Object result;
197:
198: if (!paramInfo.isValue(param)) {
199: throw new OpenDataException("parameter "
200: + paramInfo.getName() + "'s value [" + param
201: + "] is not valid");
202: } else if (param == null && paramInfo.hasDefaultValue()) {
203: result = paramInfo.getDefaultValue();
204: } else {
205: result = param;
206: }
207:
208: return result;
209: }
210:
211: /**
212: * Builds and returns a new CompositeData TShirt instance from the specified parameters.
213: * If parameter values are not legal according to the OpenMBeanParameterInfo instances for this method,
214: * it throws an OpenDataException.
215: * If model, color or size are null, it uses the default value provided in the OpenMBeanParameterInfo instances for this method.
216: */
217: public CompositeData buildTShirt(String model, String color,
218: String size, Float price) throws OpenDataException {
219:
220: // Check parameter values are legal, assign default if necessary, or throws OpenDataException
221: //
222: model = (String) checkParam(modelParamInfo, model);
223: color = (String) checkParam(colorParamInfo, color);
224: size = (String) checkParam(sizeParamInfo, size);
225: price = (Float) checkParam(priceParamInfo, price);
226:
227: Object[] itemValues = { model, color, size, price };
228: CompositeData result = new CompositeDataSupport(tShirtType,
229: itemNames, itemValues);
230:
231: return result;
232: }
233:
234: /**
235: * Removes the given tshirt from the list if a tshirt with the same index existed in the list,
236: * or does nothing otherwise.
237: */
238: public void removeTShirt(CompositeData tShirt) {
239:
240: // Calculate index
241: Object[] index = tShirts.calculateIndex(tShirt);
242:
243: // returns removed tshirt, or null if it did not exist
244: // (alternately we could have tested with a containsValue or containsKey call before removing)
245: CompositeData removed = tShirts.remove(index);
246: if (removed != null) {
247: nbChanges++;
248: }
249: }
250:
251: /* *** DynamicMBean interface implementation *** */
252:
253: /**
254: *
255: */
256: public Object getAttribute(String attribute_name)
257: throws AttributeNotFoundException, MBeanException,
258: ReflectionException {
259:
260: if (attribute_name == null) {
261: throw new RuntimeOperationsException(
262: new IllegalArgumentException(
263: "Attribute name cannot be null"),
264: "Cannot call getAttributeInfo with null attribute name");
265: }
266: if (attribute_name.equals("TShirts")) {
267: return getTShirts();
268: }
269: if (attribute_name.equals("NbChanges")) {
270: return getNbChanges();
271: }
272: throw new AttributeNotFoundException("Cannot find "
273: + attribute_name + " attribute ");
274: }
275:
276: /**
277: *
278: */
279: public void setAttribute(Attribute attribute)
280: throws AttributeNotFoundException,
281: InvalidAttributeValueException, MBeanException,
282: ReflectionException {
283:
284: throw new AttributeNotFoundException(
285: "No attribute can be set in this MBean");
286: }
287:
288: /**
289: *
290: */
291: public AttributeList getAttributes(String[] attributeNames) {
292:
293: if (attributeNames == null) {
294: throw new RuntimeOperationsException(
295: new IllegalArgumentException(
296: "attributeNames[] cannot be null"),
297: "Cannot call getAttributes with null attribute names");
298: }
299: AttributeList resultList = new AttributeList();
300:
301: if (attributeNames.length == 0)
302: return resultList;
303:
304: for (int i = 0; i < attributeNames.length; i++) {
305: try {
306: Object value = getAttribute(attributeNames[i]);
307: resultList.add(new Attribute(attributeNames[i], value));
308: } catch (Exception e) {
309: e.printStackTrace();
310: }
311: }
312: return (resultList);
313: }
314:
315: /**
316: *
317: */
318: public AttributeList setAttributes(AttributeList attributes) {
319: return new AttributeList(); // always empty
320: }
321:
322: /**
323: *
324: */
325: public Object invoke(String operationName, Object[] params,
326: String[] signature) throws MBeanException,
327: ReflectionException {
328:
329: if (operationName == null) {
330: throw new RuntimeOperationsException(
331: new IllegalArgumentException(
332: "Operation name cannot be null"),
333: "Cannot call reflectInvoke with null operation name");
334: }
335:
336: // public SimpleData addTShirt(CompositeData tShirt)
337: //
338: if (operationName.equals("addTShirt")) {
339:
340: // check params
341: if ((params.length != 1)
342: || !(params[0] instanceof CompositeData)) {
343: throw new RuntimeOperationsException(
344: new IllegalArgumentException(
345: "cannot reflectInvoke addTShirt: "
346: + "expecting params[i] instanceof CompositeData for i = 0"),
347: "Wrong content for array Object[] params to reflectInvoke addTShirt method");
348: }
349: // reflectInvoke addTShirt
350: try {
351: return addTShirt((CompositeData) params[0]);
352: } catch (Exception e) {
353: throw new MBeanException(e, "invoking addTShirt: "
354: + e.getClass().getName() + "caught ["
355: + e.getMessage() + "]");
356: }
357: }
358:
359: // public void removeTShirt(CompositeData tShirt)
360: //
361: else if (operationName.equals("removeTShirt")) {
362:
363: // check params
364: if ((params.length != 1)
365: || !(params[0] instanceof CompositeData)) {
366: throw new RuntimeOperationsException(
367: new IllegalArgumentException(
368: "cannot reflectInvoke removeTShirt: "
369: + "expecting params[i] instanceof CompositeData for i = 0"),
370: "Wrong content for array Object[] params to reflectInvoke removeTShirt method");
371: }
372: // reflectInvoke removeTShirt
373: try {
374: removeTShirt((CompositeData) params[0]);
375: return null;
376: } catch (Exception e) {
377: throw new MBeanException(e, "invoking removeTShirt: "
378: + e.getClass().getName() + "caught ["
379: + e.getMessage() + "]");
380: }
381: }
382:
383: // public CompositeData buildTShirt(SimpleData model, SimpleData color, SimpleData size, SimpleData price)
384: //
385: else if (operationName.equals("buildTShirt")) {
386:
387: // check params
388: if ((params.length != 4) || !(params[0] instanceof String)
389: || !(params[1] instanceof String)
390: || !(params[2] instanceof String)
391: || !(params[3] instanceof Float)) {
392: throw new RuntimeOperationsException(
393: new IllegalArgumentException(
394: "cannot reflectInvoke buildTShirt: "
395: + "expecting params[i] instanceof SimpleData for i = 0 to 3"),
396: "Wrong content for array Object[] params to reflectInvoke buildTShirt method");
397: }
398: // reflectInvoke buildTShirt
399: try {
400: return buildTShirt((String) params[0],
401: (String) params[1], (String) params[2],
402: (Float) params[3]);
403: } catch (Exception e) {
404: throw new MBeanException(e, "invoking buildTShirt: "
405: + e.getClass().getName() + "caught ["
406: + e.getMessage() + "]");
407: }
408: } else {
409: throw new ReflectionException(new NoSuchMethodException(
410: operationName), "Cannot find the operation "
411: + operationName);
412: }
413: } // reflectInvoke
414:
415: /**
416: *
417: */
418: public MBeanInfo getMBeanInfo() {
419: return OMBInfo;
420: }
421:
422: /* *** Open MBean Info *** */
423:
424: /**
425: *
426: */
427: private void buildMBeanInfo() {
428:
429: OpenMBeanAttributeInfoSupport[] attributes = new OpenMBeanAttributeInfoSupport[2];
430: OpenMBeanConstructorInfoSupport[] constructors = new OpenMBeanConstructorInfoSupport[1];
431: OpenMBeanOperationInfoSupport[] operations = new OpenMBeanOperationInfoSupport[3];
432: MBeanNotificationInfo[] notifications = new MBeanNotificationInfo[0];
433:
434: // attribute TShirts (no default or legal values: not supported for tabular types anyway)
435: attributes[0] = new OpenMBeanAttributeInfoSupport("TShirts",
436: "List of available T-Shirts", tShirtsType, true, false,
437: false);
438:
439: // attribute NbChanges (no default or legal values)
440: attributes[1] = new OpenMBeanAttributeInfoSupport("NbChanges",
441: "Number of times the TShirts list has been updated.",
442: SimpleType.INTEGER, true, false, false);
443:
444: // constructor
445: constructors[0] = new OpenMBeanConstructorInfoSupport(
446: "SimpleOpenMBean",
447: "Constructs a SimpleOpenMBean instance containing an empty TShirts list.",
448: new OpenMBeanParameterInfoSupport[0]);
449:
450: // operation addTShirt
451: OpenMBeanParameterInfo[] params_add = new OpenMBeanParameterInfoSupport[1];
452: params_add[0] = new OpenMBeanParameterInfoSupport("tShirt",
453: "a TShirt", tShirtType);
454: operations[0] = new OpenMBeanOperationInfoSupport(
455: "addTShirt",
456: "Adds the tShirt given in parameter to the list of available tShirts "
457: + "if it does not already exist, and returns Boolean.TRUE if succesful, Boolean.FALSE otherwise.",
458: params_add, SimpleType.BOOLEAN,
459: MBeanOperationInfo.ACTION);
460:
461: // operation removeTShirt
462: OpenMBeanParameterInfo[] params_remove = params_add;
463: operations[1] = new OpenMBeanOperationInfoSupport(
464: "removeTShirt",
465: "Removes the tShirt given in parameter to the list of available tShirts, "
466: + "if a tshirt with the same index existed in the list, or does nothing otherwise.",
467: params_remove, SimpleType.VOID,
468: MBeanOperationInfo.ACTION);
469:
470: // operation buildTShirt
471: OpenMBeanParameterInfo[] params_build = new OpenMBeanParameterInfoSupport[4];
472: params_build[0] = modelParamInfo;
473: params_build[1] = colorParamInfo;
474: params_build[2] = sizeParamInfo;
475: params_build[3] = priceParamInfo;
476: operations[2] = new OpenMBeanOperationInfoSupport(
477: "buildTShirt",
478: "Builds and returns a CompositeData TShirt instance from the specified parameters. "
479: + "If parameter values are not legal according to the OpenMBeanParameterInfo instances for this method, "
480: + "it throws an OpenDataException. "
481: + "If model, color or size are null, it uses the default value provided in the OpenMBeanParameterInfo instances for this method.",
482: params_build, tShirtType, MBeanOperationInfo.INFO);
483:
484: // The OpenMBeanInfo
485: OMBInfo = new OpenMBeanInfoSupport(this .getClass().getName(),
486: "Sample Open MBean", attributes, constructors,
487: operations, notifications);
488: }
489: }
|