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