Source for gnu.java.lang.management.BeanImpl

   1: /* BeanImpl.java - A common superclass for bean implementations.
   2:    Copyright (C) 2006 Free Software Foundation
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package gnu.java.lang.management;
  39: 
  40: import gnu.javax.management.Translator;
  41: 
  42: import java.lang.management.ManagementPermission;
  43: 
  44: import java.lang.reflect.Array;
  45: import java.lang.reflect.Method;
  46: import java.lang.reflect.InvocationTargetException;
  47: import java.util.ArrayList;
  48: import java.util.Iterator;
  49: import java.util.List;
  50: import java.util.Map;
  51: import java.util.Set;
  52: 
  53: import javax.management.AttributeNotFoundException;
  54: import javax.management.MBeanAttributeInfo;
  55: import javax.management.MBeanConstructorInfo;
  56: import javax.management.MBeanException;
  57: import javax.management.MBeanInfo;
  58: import javax.management.MBeanOperationInfo;
  59: import javax.management.MBeanParameterInfo;
  60: import javax.management.NotCompliantMBeanException;
  61: import javax.management.ReflectionException;
  62: import javax.management.StandardMBean;
  63: 
  64: import javax.management.openmbean.ArrayType;
  65: import javax.management.openmbean.CompositeDataSupport;
  66: import javax.management.openmbean.CompositeType;
  67: import javax.management.openmbean.OpenDataException;
  68: import javax.management.openmbean.OpenMBeanAttributeInfo;
  69: import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
  70: import javax.management.openmbean.OpenMBeanConstructorInfo;
  71: import javax.management.openmbean.OpenMBeanConstructorInfoSupport;
  72: import javax.management.openmbean.OpenMBeanInfo;
  73: import javax.management.openmbean.OpenMBeanInfoSupport;
  74: import javax.management.openmbean.OpenMBeanOperationInfo;
  75: import javax.management.openmbean.OpenMBeanOperationInfoSupport;
  76: import javax.management.openmbean.OpenMBeanParameterInfo;
  77: import javax.management.openmbean.OpenMBeanParameterInfoSupport;
  78: import javax.management.openmbean.OpenType;
  79: import javax.management.openmbean.TabularData;
  80: import javax.management.openmbean.TabularDataSupport;
  81: import javax.management.openmbean.TabularType;
  82: 
  83: /**
  84:  * A common superclass for bean implementations.
  85:  *
  86:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
  87:  * @since 1.5
  88:  */
  89: public class BeanImpl
  90:   extends StandardMBean
  91: {
  92: 
  93:   /**
  94:    * Cached open bean information.
  95:    */
  96:   private OpenMBeanInfo openInfo;
  97: 
  98:   /**
  99:    * Constructs a new <code>BeanImpl</code>.
 100:    *
 101:    * @param iface the bean interface being implemented.
 102:    * @throws NotCompliantMBeanException if this class doesn't implement
 103:    *                                    the interface or a method appears
 104:    *                                    in the interface that doesn't comply
 105:    *                                    with the naming conventions.
 106:    */
 107:   protected BeanImpl(Class iface)
 108:     throws NotCompliantMBeanException
 109:   {
 110:     super(iface);
 111:   }
 112: 
 113:   protected void cacheMBeanInfo(MBeanInfo info)
 114:   {
 115:     if (info == null)
 116:       return;
 117:     try
 118:       {
 119:         MBeanAttributeInfo[] oldA = info.getAttributes();
 120:         OpenMBeanAttributeInfo[] attribs =
 121:           new OpenMBeanAttributeInfoSupport[oldA.length];
 122:         for (int a = 0; a < oldA.length; ++a)
 123:           {
 124:             OpenMBeanParameterInfo param = Translator.translate(oldA[a].getType());
 125:             if (param.getMinValue() == null)
 126:               {
 127:                 Object[] lv;
 128:                 if (param.getLegalValues() == null)
 129:                   lv = null;
 130:                 else
 131:                   lv = param.getLegalValues().toArray();
 132:                 attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(),
 133:                                                                oldA[a].getDescription(),
 134:                                                                ((OpenType<Object>)
 135:                                                                 param.getOpenType()),
 136:                                                                oldA[a].isReadable(),
 137:                                                                oldA[a].isWritable(),
 138:                                                                oldA[a].isIs(),
 139:                                                                param.getDefaultValue(),
 140:                                                                lv);
 141:               }
 142:             else
 143:               attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(),
 144:                                                              oldA[a].getDescription(),
 145:                                                              ((OpenType<Object>)
 146:                                                               param.getOpenType()),
 147:                                                              oldA[a].isReadable(),
 148:                                                              oldA[a].isWritable(),
 149:                                                              oldA[a].isIs(),
 150:                                                              param.getDefaultValue(),
 151:                                                              ((Comparable<Object>)
 152:                                                                param.getMinValue()),
 153:                                                              ((Comparable<Object>)
 154:                                                                param.getMaxValue()));
 155:           }
 156:         MBeanConstructorInfo[] oldC = info.getConstructors();
 157:         OpenMBeanConstructorInfo[] cons = new OpenMBeanConstructorInfoSupport[oldC.length];
 158:         for (int a = 0; a < oldC.length; ++a)
 159:           cons[a] =
 160:             new OpenMBeanConstructorInfoSupport(oldC[a].getName(),
 161:                                                 oldC[a].getDescription(),
 162:                                                 translateSignature(oldC[a].getSignature()));
 163:         MBeanOperationInfo[] oldO = info.getOperations();
 164:         OpenMBeanOperationInfo[] ops = new OpenMBeanOperationInfoSupport[oldO.length];
 165:         for (int a = 0; a < oldO.length; ++a)
 166:           ops[a] =
 167:         new OpenMBeanOperationInfoSupport(oldO[a].getName(),
 168:                                           oldO[a].getDescription(),
 169:                                           translateSignature(oldO[a].getSignature()),
 170:                                           Translator.translate(oldO[a].getReturnType()).getOpenType(),
 171:                                           oldO[a].getImpact());
 172:         openInfo = new OpenMBeanInfoSupport(info.getClassName(), info.getDescription(),
 173:                                             attribs, cons, ops, info.getNotifications());
 174:       }
 175:     catch (OpenDataException e)
 176:       {
 177:         throw (InternalError) (new InternalError("A problem occurred creating the open type " +
 178:                                                  "descriptors.").initCause(e));
 179:       }
 180:   }
 181: 
 182:   protected void checkMonitorPermissions()
 183:   {
 184:     SecurityManager sm = System.getSecurityManager();
 185:     if (sm != null)
 186:       sm.checkPermission(new ManagementPermission("monitor"));
 187:   }
 188: 
 189:   protected void checkControlPermissions()
 190:   {
 191:     SecurityManager sm = System.getSecurityManager();
 192:     if (sm != null)
 193:       sm.checkPermission(new ManagementPermission("control"));
 194:   }
 195: 
 196:   public Object getAttribute(String attribute)
 197:     throws AttributeNotFoundException, MBeanException,
 198:            ReflectionException
 199:   {
 200:     Object value = super.getAttribute(attribute);
 201:     if (value instanceof Enum)
 202:       return ((Enum) value).name();
 203:     Class vClass = value.getClass();
 204:     if (vClass.isArray())
 205:       vClass = vClass.getComponentType();
 206:     String cName = vClass.getName();
 207:     String[] allowedTypes = OpenType.ALLOWED_CLASSNAMES;
 208:     for (int a = 0; a < allowedTypes.length; ++a)
 209:       if (cName.equals(allowedTypes[a]))
 210:         return value;
 211:     OpenMBeanInfo info = (OpenMBeanInfo) getMBeanInfo();
 212:     MBeanAttributeInfo[] attribs =
 213:       (MBeanAttributeInfo[]) info.getAttributes();
 214:     OpenType type = null;
 215:     for (int a = 0; a < attribs.length; ++a)
 216:       if (attribs[a].getName().equals(attribute))
 217:         type = ((OpenMBeanAttributeInfo) attribs[a]).getOpenType();
 218:     if (value instanceof List)
 219:       {
 220:         try
 221:           {
 222:             Class e =
 223:               Class.forName(((ArrayType) type).getElementOpenType().getClassName());
 224:             List l = (List) value;
 225:             Object[] array = (Object[]) Array.newInstance(e, l.size());
 226:             return l.toArray(array);
 227:           }
 228:         catch (ClassNotFoundException e)
 229:           {
 230:             throw (InternalError) (new InternalError("The class of the list " +
 231:                                                      "element type could not " +
 232:                                                      "be created").initCause(e));
 233:           }
 234:       }
 235:     if (value instanceof Map)
 236:       {
 237:         TabularType ttype = (TabularType) type;
 238:         TabularData data = new TabularDataSupport(ttype);
 239:         Iterator it = ((Map) value).entrySet().iterator();
 240:         while (it.hasNext())
 241:           {
 242:             Map.Entry entry = (Map.Entry) it.next();
 243:             try
 244:               {
 245:                 data.put(new CompositeDataSupport(ttype.getRowType(),
 246:                                                   new String[] {
 247:                                                     "key",
 248:                                                     "value"
 249:                                                   },
 250:                                                   new Object[] {
 251:                                                     entry.getKey(),
 252:                                                     entry.getValue()
 253:                                                   }));
 254:               }
 255:             catch (OpenDataException e)
 256:               {
 257:                 throw (InternalError) (new InternalError("A problem occurred " +
 258:                                                          "converting the map " +
 259:                                                          "to a composite data " +
 260:                                                          "structure.").initCause(e));
 261:               }
 262:           }
 263:         return data;
 264:       }
 265:     CompositeType cType = (CompositeType) type;
 266:     Set names = cType.keySet();
 267:     Iterator it = names.iterator();
 268:     List values = new ArrayList(names.size());
 269:     while (it.hasNext())
 270:       {
 271:         String field = (String) it.next();
 272:         Method getter = null;
 273:         try
 274:           {
 275:             getter = vClass.getMethod("get" + field);
 276:           }
 277:         catch (NoSuchMethodException e)
 278:           {
 279:             /* Ignored; the type tells us it's there. */
 280:           }
 281:         try
 282:           {
 283:             values.add(getter.invoke(value));
 284:           }
 285:         catch (IllegalAccessException e)
 286:           {
 287:             throw new ReflectionException(e, "Failed to retrieve " + field);
 288:           }
 289:         catch (IllegalArgumentException e)
 290:           {
 291:             throw new ReflectionException(e, "Failed to retrieve " + field);
 292:           }
 293:         catch (InvocationTargetException e)
 294:           {
 295:             throw new MBeanException((Exception) e.getCause(),
 296:                                      "The getter of " + field +
 297:                                      " threw an exception");
 298:           }
 299:       }
 300:     try
 301:       {
 302:         return new CompositeDataSupport(cType,
 303:                                         (String[])
 304:                                         names.toArray(new String[names.size()]),
 305:                                         values.toArray());
 306:       }
 307:     catch (OpenDataException e)
 308:       {
 309:         throw (InternalError) (new InternalError("A problem occurred " +
 310:                                                  "converting the value " +
 311:                                                  "to a composite data " +
 312:                                                  "structure.").initCause(e));
 313:       }
 314:   }
 315: 
 316:   protected MBeanInfo getCachedMBeanInfo()
 317:   {
 318:     return (MBeanInfo) openInfo;
 319:   }
 320: 
 321:   /**
 322:    * Override this method so as to prevent the description of a constructor's
 323:    * parameter being @code{null}.  Open MBeans can not have @code{null} descriptions,
 324:    * but one will occur as the names of parameters aren't stored for reflection.
 325:    *
 326:    * @param constructor the constructor whose parameter needs describing.
 327:    * @param parameter the parameter to be described.
 328:    * @param sequenceNo the number of the parameter to describe.
 329:    * @return a description of the constructor's parameter.
 330:    */
 331:   protected String getDescription(MBeanConstructorInfo constructor,
 332:                                   MBeanParameterInfo parameter,
 333:                                   int sequenceNo)
 334:   {
 335:     String desc = parameter.getDescription();
 336:     if (desc == null)
 337:       return "param" + sequenceNo;
 338:     else
 339:       return desc;
 340:   }
 341: 
 342:   /**
 343:    * Override this method so as to prevent the description of an operation's
 344:    * parameter being @code{null}.  Open MBeans can not have @code{null} descriptions,
 345:    * but one will occur as the names of parameters aren't stored for reflection.
 346:    *
 347:    * @param operation the operation whose parameter needs describing.
 348:    * @param parameter the parameter to be described.
 349:    * @param sequenceNo the number of the parameter to describe.
 350:    * @return a description of the operation's parameter.
 351:    */
 352:   protected String getDescription(MBeanOperationInfo operation,
 353:                                   MBeanParameterInfo parameter,
 354:                                   int sequenceNo)
 355:   {
 356:     String desc = parameter.getDescription();
 357:     if (desc == null)
 358:       return "param" + sequenceNo;
 359:     else
 360:       return desc;
 361:   }
 362: 
 363:   /**
 364:    * Override this method so as to prevent the name of a constructor's
 365:    * parameter being @code{null}.  Open MBeans can not have @code{null} names,
 366:    * but one will occur as the names of parameters aren't stored for reflection.
 367:    *
 368:    * @param constructor the constructor whose parameter needs a name.
 369:    * @param parameter the parameter to be named.
 370:    * @param sequenceNo the number of the parameter to name.
 371:    * @return a description of the constructor's parameter.
 372:    */
 373:   protected String getParameterName(MBeanConstructorInfo constructor,
 374:                                     MBeanParameterInfo parameter,
 375:                                     int sequenceNo)
 376:   {
 377:     String name = parameter.getName();
 378:     if (name == null)
 379:       return "param" + sequenceNo;
 380:     else
 381:       return name;
 382:   }
 383: 
 384:   /**
 385:    * Override this method so as to prevent the name of an operation's
 386:    * parameter being @code{null}.  Open MBeans can not have @code{null} names,
 387:    * but one will occur as the names of parameters aren't stored for reflection.
 388:    *
 389:    * @param operation the operation whose parameter needs a name.
 390:    * @param parameter the parameter to be named.
 391:    * @param sequenceNo the number of the parameter to name.
 392:    * @return a description of the operation's parameter.
 393:    */
 394:   protected String getParameterName(MBeanOperationInfo operation,
 395:                                     MBeanParameterInfo parameter,
 396:                                     int sequenceNo)
 397:   {
 398:     String name = parameter.getName();
 399:     if (name == null)
 400:       return "param" + sequenceNo;
 401:     else
 402:       return name;
 403:   }
 404: 
 405:   public MBeanInfo getMBeanInfo()
 406:   {
 407:     super.getMBeanInfo();
 408:     return getCachedMBeanInfo();
 409:   }
 410: 
 411:   private OpenMBeanParameterInfo[] translateSignature(MBeanParameterInfo[] oldS)
 412:     throws OpenDataException
 413:   {
 414:     OpenMBeanParameterInfo[] sig = new OpenMBeanParameterInfoSupport[oldS.length];
 415:     for (int a = 0; a < oldS.length; ++a)
 416:       {
 417:         OpenMBeanParameterInfo param = Translator.translate(oldS[a].getType());
 418:         if (param.getMinValue() == null)
 419:           {
 420:             Object[] lv;
 421:             if (param.getLegalValues() == null)
 422:               lv = null;
 423:             else
 424:               lv = param.getLegalValues().toArray();
 425:             sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(),
 426:                                                        oldS[a].getDescription(),
 427:                                                        ((OpenType<Object>)
 428:                                                         param.getOpenType()),
 429:                                                        param.getDefaultValue(),
 430:                                                        lv);
 431:           }
 432:         else
 433:           sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(),
 434:                                                      oldS[a].getDescription(),
 435:                                                      ((OpenType<Object>)
 436:                                                       param.getOpenType()),
 437:                                                      param.getDefaultValue(),
 438:                                                      ((Comparable<Object>)
 439:                                                       param.getMinValue()),
 440:                                                      ((Comparable<Object>)
 441:                                                       param.getMaxValue()));
 442:       }
 443:     return sig;
 444:   }
 445: 
 446: 
 447: }