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 */ BeanImpl(Class iface)107 protected BeanImpl(Class iface) 108 throws NotCompliantMBeanException 109 { 110 super(iface); 111 } 112 cacheMBeanInfo(MBeanInfo info)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 checkMonitorPermissions()182 protected void checkMonitorPermissions() 183 { 184 SecurityManager sm = System.getSecurityManager(); 185 if (sm != null) 186 sm.checkPermission(new ManagementPermission("monitor")); 187 } 188 checkControlPermissions()189 protected void checkControlPermissions() 190 { 191 SecurityManager sm = System.getSecurityManager(); 192 if (sm != null) 193 sm.checkPermission(new ManagementPermission("control")); 194 } 195 getAttribute(String attribute)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 getCachedMBeanInfo()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 */ getDescription(MBeanConstructorInfo constructor, MBeanParameterInfo parameter, int sequenceNo)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 */ getDescription(MBeanOperationInfo operation, MBeanParameterInfo parameter, int sequenceNo)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 */ getParameterName(MBeanConstructorInfo constructor, MBeanParameterInfo parameter, int sequenceNo)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 */ getParameterName(MBeanOperationInfo operation, MBeanParameterInfo parameter, int sequenceNo)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 getMBeanInfo()405 public MBeanInfo getMBeanInfo() 406 { 407 super.getMBeanInfo(); 408 return getCachedMBeanInfo(); 409 } 410 translateSignature(MBeanParameterInfo[] oldS)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 } 448