KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mx4j > tools > i18n > I18NStandardMBean


1 /*
2  * Copyright (C) The MX4J Contributors.
3  * All rights reserved.
4  *
5  * This software is distributed under the terms of the MX4J License version 1.0.
6  * See the terms of the MX4J License in the documentation provided with this software.
7  */

8
9 package mx4j.tools.i18n;
10
11 import java.util.Collection JavaDoc;
12 import java.util.Collections JavaDoc;
13 import java.util.Enumeration JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Locale JavaDoc;
17 import java.util.Map JavaDoc;
18 import java.util.MissingResourceException JavaDoc;
19 import java.util.ResourceBundle JavaDoc;
20 import java.util.Set JavaDoc;
21 import java.util.StringTokenizer JavaDoc;
22 import javax.management.MBeanAttributeInfo JavaDoc;
23 import javax.management.MBeanConstructorInfo JavaDoc;
24 import javax.management.MBeanInfo JavaDoc;
25 import javax.management.MBeanOperationInfo JavaDoc;
26 import javax.management.MBeanParameterInfo JavaDoc;
27 import javax.management.NotCompliantMBeanException JavaDoc;
28 import javax.management.StandardMBean JavaDoc;
29
30 /**
31  * An extension of StandardMBean to support internationalization. <p>
32  * <p/>
33  * The I18N information is taken from a property bundle named MyImplMBeanResources
34  * where "MyImpl" is the fully qualified class implementing the MBean. <p>
35  * These bundles are nested following the class hierachy of the <b>implementation</b>
36  * class. This means that a superclass of the real implementing class can
37  * define the resource bundle for the common attributes and operations.
38  * <p/>
39  * The resource bundle naming rules defined by {@link java.util.ResourceBundle}
40  * are used; in particular : <UL>
41  * <LI>If a <b>class</b> called MyPackage.MyImplMBeanResources_localInfo exists it is used (programmatic methd)
42  * <LI>Otherwise the <b>file</b> called MyPackage.MyImplMBeanResources_localInfo.properties is used.
43  * </UL>
44  * <p/>
45  * localInfo consists of one or more sections of "language_country_variant" (eg en_GB or fr_FR).
46  * <p/>
47  * The locale to be used is determined by one of the following mechanisms (in this order) <UL>
48  * <LI>The locale object explicitly passed to the constructor (if not null)
49  * <LI>The static method {@link #setDefaultLocale}
50  * <LI>The system property "mx4j.descriptionLocale"
51  * <LI>The current system default locale
52  * </UL>
53  * <p/>
54  * The bundle should contain keys as described below :
55  * <H2>Global bean description</H2>
56  * The global bean description is given by the single key "descr": <pre>
57  * descr=The MBean Description
58  * </pre>
59  * <p/>
60  * <H2>Attributes</H2>
61  * Attribute desciptions are given by keys of form "attr.Name" where Name
62  * is the attribute name (the method name minus the get/set prefix) : <pre>
63  * attr.Counter=The counter
64  * </pre>
65  * <p/>
66  * <H2>Constructors</H2>
67  * <H3>Non ambiguous case</H3>
68  * All constructors having a different <b>number</b> of arguments may be described in this way: <pre>
69  * cons.N=desciption of constructor N
70  * cons.N.param.1=Description of first parameter of constructor N
71  * cons.N.paramName.1=paramName1
72  * cons.N.param.2=Description of first parameter of constructor N
73  * cons.N.paramName.2=paramName2
74  * </pre>
75  * Where N is a sequential number starting at one.
76  * <p/>
77  * <H3>Ambiguous case</H3>
78  * Where several constructors exist with the same number of arguments an explicit
79  * signature must be given. The signature is a comma separated list of class descriptions
80  * (as returned by {@link java.lang.Class#getName} and has the key cons.N.sig : <pre>
81  * cons.N.sig=int,java.lang.Object
82  * cons.N.param.1=The int parameter
83  * cons.N.param.2=The Object parameter
84  * </pre>
85  * <p/>
86  * <H2>Operations</H2>
87  * <H3>No overloading</H3>
88  * When no overloaded versions of an operation exist (same method name but different parameters)
89  * the simplest case shown below can be used : <pre>
90  * op.<I>operationName</I>=The description
91  * op.<I>operationName</I>.param.1=The first parameter
92  * op.<I>operationName</I>.paramName.1=param1
93  * </pre>
94  * <p/>
95  * <H3>Non ambiguous overloading case</H3>
96  * When operation overloading is used but the overloaded versions differ in the number
97  * of parameters the format below can be used : <pre>
98  * op.<I>operationName</I>.1=The first version of operationName
99  * op.<I>operationName</I>.1.param.1=parameter for first version
100  * op.<I>operationName</I>.1.paramName.1=param1
101  * op.<I>operationName</I>.2=The second version of operationName
102  * op.<I>operationName</I>.2.paramName.1=param1
103  * op.<I>operationName</I>.2.param.1=first parameter for second version
104  * op.<I>operationName</I>.2.param.2=second parameter for second version
105  * op.<I>operationName</I>.2.paramName.2=param2
106  * </pre>
107  * <p/>
108  * <H3>Ambiguous overloading case</H3>
109  * When operations with the same name have the same number of arguments an explicit
110  * signature must be used : <pre>
111  * op.<I>operationName</I>.1.sig=int
112  * op.<I>operationName</I>.1=The first version of operationName (takes int)
113  * op.<I>operationName</I>.1.param.1=parameter for first version
114  * op.<I>operationName</I>.1.paramName.1=param1
115  * op.<I>operationName</I>.2.sig=java.lang.Object
116  * op.<I>operationName</I>.2=The second version of operationName (take Object)
117  * op.<I>operationName</I>.2.paramName.1=param1
118  * op.<I>operationName</I>.2.param.1=first parameter for second version
119  * </pre>
120  * <p/>
121  * <H2>Restrictions</H2>
122  * Parameter names must only contain characters allowed in a Java identifier
123  * (in particular spaces are <b>not</b> allowed). This is required by the JMX specifications.
124  * No such restrictions exist for the other descriptions.
125  * <p/>
126  * <H2>Behaviour with missing data</H2>
127  * If no resource bunde exists for the MBean a java.util.MissingResourceException
128  * will be thrown by the constructor. <p>
129  * <p/>
130  * If the resouce bundle is found but the bean description, constructor description or
131  * parameter name is missing the String "??(key)" will be returned instead (eg
132  * "??(op.myOperation)". <p>
133  * <p/>
134  * If a paramName key is missing (for constructor or operation) the version normally
135  * given by StandardMBean is used (generally "pN").<p>
136  * <p/>
137  * If a non ambiguous description cannot be determined the fixed (non translatable)
138  * descriptions "ambiguous constructor", "parameter for ambiguous constructor",
139  * "ambiguous operation", "parameter for ambiguous operation" are returned.
140  */

141 public class I18NStandardMBean extends StandardMBean JavaDoc
142 {
143    private static final String JavaDoc IDPROP_DEFAULT_LOCALE =
144            "mx4j.descriptionLocale";
145    private static final String JavaDoc RESOURCE_SUFFIX = "MBeanResources";
146    private static final String JavaDoc KEY_DESCR = "descr";
147    private static final String JavaDoc KEY_CONS = "cons";
148    private static final String JavaDoc KEY_ATTR = "attr";
149    private static final String JavaDoc KEY_OP = "op";
150    private static final String JavaDoc KEY_PARAM = "param";
151    private static final String JavaDoc KEY_PARAM_NAME = "paramName";
152    private static final String JavaDoc KEY_SIG = "sig";
153
154    private static Locale JavaDoc g_defaultLocale = null;
155
156    private NestedResourceBundle m_bundle;
157    private Map JavaDoc m_mapConstructorSignatureToResourceIndex;
158    private Map JavaDoc m_mapConstructorParamCountToResourceIndex;
159    private Map JavaDoc m_mapConstructorToResourceIndex = new HashMap JavaDoc();
160    private Map JavaDoc m_mapOperationNameToSignatures = new HashMap JavaDoc();
161    private Map JavaDoc m_mapOperationNameToParamCounts = new HashMap JavaDoc();
162    private Set JavaDoc m_setAmbiguousConstructors = new HashSet JavaDoc();
163    private Set JavaDoc m_setAmbiguousOperations = new HashSet JavaDoc();
164
165    /**
166     * Makes an I18NStandardMBean for the default locale with a separate implementation class.
167     *
168     * @see javax.management.StandardMBean#StandardMBean(java.lang.Object, java.lang.Class)
169     */

170    public I18NStandardMBean(Object JavaDoc implementation, Class JavaDoc mbeanInterface)
171            throws NotCompliantMBeanException JavaDoc
172    {
173       this(implementation, mbeanInterface, null);
174    }
175
176    /**
177     * Makes an I18NStandardMBean for the given locale with a separate implementation class.
178     *
179     * @see javax.management.StandardMBean#StandardMBean(java.lang.Object, java.lang.Class)
180     */

181    public I18NStandardMBean(Object JavaDoc implementation,
182                             Class JavaDoc mbeanInterface,
183                             Locale JavaDoc locale)
184            throws NotCompliantMBeanException JavaDoc
185    {
186       super(implementation, mbeanInterface);
187       setupBundle(implementation, locale);
188    }
189
190    /**
191     * Makes a I18NStandardMBean for the default locale implemented by a subclass.
192     *
193     * @see javax.management.StandardMBean#StandardMBean(java.lang.Class)
194     */

195    protected I18NStandardMBean(Class JavaDoc mbeanInterface)
196            throws NotCompliantMBeanException JavaDoc
197    {
198       super(mbeanInterface);
199       setupBundle(this, null);
200    }
201
202    /**
203     * Makes a I18NStandardMBean for the given locale implemented by a subclass.
204     *
205     * @see javax.management.StandardMBean#StandardMBean(java.lang.Class)
206     */

207    protected I18NStandardMBean(Class JavaDoc mbeanInterface, Locale JavaDoc locale)
208            throws NotCompliantMBeanException JavaDoc
209    {
210       super(mbeanInterface);
211       setupBundle(this, locale);
212    }
213
214    private void setupBundle(Object JavaDoc implementation, Locale JavaDoc locale)
215    {
216       // calculate the effective locale:
217
if (locale == null)
218       {
219          locale = g_defaultLocale;
220       }
221       if (locale == null)
222       {
223          locale = getLocaleFromSystemProperties();
224       }
225
226       // create bundle
227
NestedResourceBundle cur = null;
228       MissingResourceException JavaDoc ex = null;
229       for (Class JavaDoc c = implementation.getClass(); c != null; c = c.getSuperclass())
230       {
231          String JavaDoc bundleName = c.getName() + RESOURCE_SUFFIX;
232          try
233          {
234             ResourceBundle JavaDoc b = ResourceBundle.getBundle(bundleName, locale);
235             NestedResourceBundle nb = new NestedResourceBundle(b);
236             if (cur == null)
237             {
238                m_bundle = nb;
239             }
240             else
241             {
242                cur.setParent(nb);
243             }
244             cur = nb;
245          }
246          catch (MissingResourceException JavaDoc e)
247          {
248             if (m_bundle == null) ex = e; // save first exception
249
}
250       }
251       if (m_bundle == null)
252       {
253          ex.fillInStackTrace();
254          throw ex;
255       }
256    }
257
258    // Obtain the default locale from system properties
259
private Locale JavaDoc getLocaleFromSystemProperties()
260    {
261       Locale JavaDoc locale = Locale.getDefault();
262       String JavaDoc stdLocale = System.getProperty(IDPROP_DEFAULT_LOCALE);
263       if (stdLocale != null && stdLocale.length() > 0)
264       {
265          StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(stdLocale, "_");
266          switch (st.countTokens())
267          {
268             case 2:
269                locale = new Locale JavaDoc(st.nextToken(), st.nextToken());
270                break;
271             case 3:
272                locale =
273                new Locale JavaDoc(st.nextToken(),
274                           st.nextToken(),
275                           st.nextToken());
276                break;
277             default :
278                throw new IllegalArgumentException JavaDoc("Invalid locale in "
279                                                   + IDPROP_DEFAULT_LOCALE
280                                                   + ":"
281                                                   + stdLocale);
282          }
283       }
284       return locale;
285    }
286
287    /**
288     * Set the locale which will be used for future I18NStandardMBeans. <p>
289     * The locale specified can be overridden on a per class basis via the
290     * constructors but overrides other means of setting the Locale (system properties). <p>
291     * <p/>
292     * Changing the locale has no effect on already constructed MBeans.
293     *
294     * @param locale the Locale for future MBeans
295     */

296    public static void setDefaultLocale(Locale JavaDoc locale)
297    {
298       g_defaultLocale = locale;
299    }
300
301    /**
302     * Initialise internal data structures. <p>
303     * This method is always called first during getMBeanInfo processing.
304     * We use this to avoid keeping all our internal Maps in memory too long.
305     *
306     * @see javax.management.StandardMBean#getCachedMBeanInfo
307     */

308    protected MBeanInfo JavaDoc getCachedMBeanInfo()
309    {
310       MBeanInfo JavaDoc info = super.getCachedMBeanInfo();
311       if (info == null)
312       {
313          // only setup if we are going to be called!
314
m_mapConstructorToResourceIndex = new HashMap JavaDoc();
315          m_mapOperationNameToSignatures = new HashMap JavaDoc();
316          m_mapOperationNameToParamCounts = new HashMap JavaDoc();
317          m_setAmbiguousConstructors = new HashSet JavaDoc();
318          m_setAmbiguousOperations = new HashSet JavaDoc();
319          m_mapConstructorSignatureToResourceIndex =
320          getSignatureMap(KEY_CONS);
321          m_mapConstructorParamCountToResourceIndex =
322          getParamCountMap(KEY_CONS);
323       }
324       return info;
325    }
326
327    /**
328     * Once the MBeanInfo has been obtained discard our caches.
329     *
330     * @see javax.management.StandardMBean#cacheMBeanInfo(javax.management.MBeanInfo)
331     */

332    protected void cacheMBeanInfo(MBeanInfo JavaDoc info)
333    {
334       super.cacheMBeanInfo(info);
335       m_mapConstructorToResourceIndex = null;
336       m_mapOperationNameToSignatures = null;
337       m_mapOperationNameToParamCounts = null;
338       m_setAmbiguousConstructors = null;
339       m_setAmbiguousOperations = null;
340       m_mapConstructorSignatureToResourceIndex = null;
341       m_mapConstructorParamCountToResourceIndex = null;
342    }
343
344    /*
345     * Initialises internal structures based on available constructors. <p>
346     * Return value is supplied by superclass.<p>
347     *
348     * For all the constructors :<ul>
349     * <li>Create a map of MBeanConstructorInfo=>resource bundle index for explicit signatures
350     * <li>Create list of "ambiguous" constructors based on number of arguments.
351     * </ul>
352     * Note we assume that this metthod will be called BEFORE the constructor related
353     * getDesciption methods. The spec does not say anything about this.
354     */

355    protected MBeanConstructorInfo JavaDoc[] getConstructors(MBeanConstructorInfo JavaDoc[] cstrs,
356                                                     Object JavaDoc impl)
357    {
358       Map JavaDoc argCountToCstr = new HashMap JavaDoc();
359       for (int i = 0; i < cstrs.length; i++)
360       {
361          MBeanConstructorInfo JavaDoc ci = cstrs[i];
362          MBeanParameterInfo JavaDoc[] params = ci.getSignature();
363
364          // update potentially ambiguous constructors (same number of arguments)
365
Integer JavaDoc count = new Integer JavaDoc(params.length);
366          Object JavaDoc first = argCountToCstr.get(count);
367          if (first != null)
368          {
369             // already have a constructor with this number of args
370
m_setAmbiguousConstructors.add(first); // Set so no duplication
371
m_setAmbiguousConstructors.add(ci);
372             // this one is ambiguous too
373
}
374          else
375          {
376             argCountToCstr.put(count, ci);
377          }
378
379          // update signature=>resource index mapping (if explicit signature provided)
380
String JavaDoc sig = makeSignatureString(params);
381          Integer JavaDoc idx =
382                  (Integer JavaDoc)m_mapConstructorSignatureToResourceIndex.get(sig);
383          if (idx != null)
384          {
385             m_mapConstructorToResourceIndex.put(ci, idx);
386          }
387       }
388       return super.getConstructors(cstrs, impl);
389    }
390
391    /**
392     * Obtain global description for MBean. <p>
393     * Taken from "descr" key in resource bundle. <p>
394     * <p/>
395     * Also performs internal initialisations requiring the MBeanInfo obtained
396     * by introspection. Therefore the superclass must call this method BEFORE
397     * the other hooks.
398     *
399     * @see javax.management.StandardMBean#getDescription(javax.management.MBeanInfo)
400     */

401    protected String JavaDoc getDescription(MBeanInfo JavaDoc info)
402    {
403       findAmbiguousOperations(info); // assume called first
404
return getValueFromBundle(KEY_DESCR);
405    }
406
407    /**
408     * Obtain the constructor description. <p>
409     * Taken from "cons.N" key in resource bundle. <p>
410     * <p/>
411     * Maybe "ambiguous constructor" if correct index cannot be determined by
412     * an explicit signature or parameter counts.
413     *
414     * @see javax.management.StandardMBean#getDescription(javax.management.MBeanConstructorInfo)
415     */

416    protected String JavaDoc getDescription(MBeanConstructorInfo JavaDoc cstr)
417    {
418       int idx = getConstructorIndex(cstr);
419       if (idx < 1)
420       {
421          return "ambiguous constructor";
422       }
423       return getValueFromBundle(KEY_CONS + "." + idx);
424    }
425
426    /**
427     * Obtain the constructor parameter description. <p>
428     * Taken from "cons.N.param.<I>seq</I>" key in resource bundle. <p>
429     * <p/>
430     * Maybe "parameter for ambiguous constructor" if correct index cannot be determined by
431     * an explicit signature or parameter counts.
432     *
433     * @see javax.management.StandardMBean#getDescription(javax.management.MBeanConstructorInfo, javax.management.MBeanParameterInfo, int)
434     */

435    protected String JavaDoc getDescription(MBeanConstructorInfo JavaDoc cstr,
436                                    MBeanParameterInfo JavaDoc param,
437                                    int seq)
438    {
439       int idx = getConstructorIndex(cstr);
440       if (idx < 1)
441       {
442          return "parameter for ambiguous constructor";
443       }
444       return getValueFromBundle(KEY_CONS + "." + idx + ".param." + (seq + 1));
445    }
446
447    /**
448     * Obtain constructor parameter name. <p>
449     * Taken from "cons.N.paramName.<I>seq</I>" key in resource bundle. <p>
450     * <p/>
451     * If this key does not exist or if the correct index N cannot be determined by
452     * an explicit signature or parameter counts the superclass method is called.
453     *
454     * @see javax.management.StandardMBean#getParameterName(javax.management.MBeanConstructorInfo, javax.management.MBeanParameterInfo, int)
455     */

456    protected String JavaDoc getParameterName(MBeanConstructorInfo JavaDoc cstr,
457                                      MBeanParameterInfo JavaDoc param,
458                                      int seq)
459    {
460       int idx = getConstructorIndex(cstr);
461       String JavaDoc name = null;
462       if (idx >= 1)
463       {
464          name =
465          getValueOrNullFromBundle(KEY_CONS + "." + idx + ".paramName." + (seq + 1));
466       }
467       if (name == null)
468       {
469          name = super.getParameterName(cstr, param, seq);
470       }
471       return name;
472    }
473
474    /**
475     * Obtain the attribute description. <p>
476     * Taken from the "attr.<I>attributeName</I>" key in resource bundle.
477     *
478     * @see javax.management.StandardMBean#getDescription(javax.management.MBeanAttributeInfo)
479     */

480    protected String JavaDoc getDescription(MBeanAttributeInfo JavaDoc attr)
481    {
482       return getValueFromBundle(KEY_ATTR + "." + attr.getName());
483    }
484
485    /**
486     * Obtain the operation description. <p>
487     * Taken from the "op.<I>operationName</I>.N" or the "op.<I>operationName</I>"
488     * key in the resource bundle. <p>
489     * May be "ambiguous operation" if the correct key cannot be determined by
490     * signature or parameter counts.
491     *
492     * @see javax.management.StandardMBean#getDescription(javax.management.MBeanOperationInfo)
493     */

494    protected String JavaDoc getDescription(MBeanOperationInfo JavaDoc op)
495    {
496       try
497       {
498          return getValueFromBundle(getOperationKey(op));
499       }
500       catch (IllegalStateException JavaDoc e)
501       {
502          return e.getMessage();
503       }
504    }
505
506    /**
507     * Obtain the operation parameter description. <p>
508     * Taken from the "op.<I>operationName</I>.N.param.M" or the "op.<I>operationName</I>.param"
509     * key in the resource bundle. <p>
510     * May be "parameter for ambiguous operation" if the correct key cannot be determined by
511     * signature or parameter counts.
512     *
513     * @see javax.management.StandardMBean#getDescription(javax.management.MBeanOperationInfo, javax.management.MBeanParameterInfo, int)
514     */

515    protected String JavaDoc getDescription(MBeanOperationInfo JavaDoc op,
516                                    MBeanParameterInfo JavaDoc param,
517                                    int seq)
518    {
519       try
520       {
521          return getValueFromBundle(getOperationKey(op) + "." + KEY_PARAM + "." + (seq + 1));
522       }
523       catch (IllegalStateException JavaDoc e)
524       {
525          return "parameter for " + e.getMessage();
526       }
527    }
528
529    /**
530     * Obtain operation parameter name. <p>
531     * Taken from the "op.<I>operationName</I>.N.paramName.M" or the "op.<I>operationName.paramName</I>.M"
532     * key in the resource bundle. <p>
533     * <p/>
534     * If this key does not exist or if the correct index N cannot be determined by
535     * an explicit signature or parameter counts the superclass method is called.
536     *
537     * @see javax.management.StandardMBean#getParameterName(javax.management.MBeanOperationInfo, javax.management.MBeanParameterInfo, int)
538     */

539    protected String JavaDoc getParameterName(MBeanOperationInfo JavaDoc op,
540                                      MBeanParameterInfo JavaDoc param,
541                                      int seq)
542    {
543       String JavaDoc name = null;
544       try
545       {
546          name =
547          getValueOrNullFromBundle(getOperationKey(op)
548                                   + "."
549                                   + KEY_PARAM_NAME
550                                   + "."
551                                   + (seq + 1));
552       }
553       catch (IllegalStateException JavaDoc e)
554       {
555       }
556
557       if (name == null)
558       {
559          name = super.getParameterName(op, param, seq);
560       }
561       return name;
562    }
563
564    /*
565     * Obtain 1 based index of constructor in resource bundle.
566     * First look for a signature match (.sig in bundle)
567     * If not found and constuctor is potentially ambiguous (another constructor with the same number of params exists) return -1
568     * If not found try a parameter number match.
569     * If parameter number match is ambiguous return -1
570     * If no match found return 0
571     */

572    private int getConstructorIndex(MBeanConstructorInfo JavaDoc cons)
573    {
574       Integer JavaDoc idx = (Integer JavaDoc)m_mapConstructorToResourceIndex.get(cons);
575       if (idx != null)
576       {
577          return idx.intValue();
578       }
579
580       // do multiple constuctors with the same arg count exist?
581
if (m_setAmbiguousConstructors.contains(cons))
582          return -1;
583
584       // no signature match - try using parameter count
585
int nbParams = cons.getSignature().length;
586       idx =
587       (Integer JavaDoc)m_mapConstructorParamCountToResourceIndex.get(new Integer JavaDoc(nbParams));
588       if (idx != null)
589       {
590          return idx.intValue();
591       }
592       return 0;
593    }
594
595    /*
596     * Obtain the root bundle key for the given operation.
597     * If a matching signature entry exists for this operation
598     * is of form : "op.operationName.N"
599     * otherwise it is of form "op.operationName"
600     * where N is the index of the matching signature.
601     * If the operation is ambiguous throw an IllegalStateException.
602     */

603    private String JavaDoc getOperationKey(MBeanOperationInfo JavaDoc op)
604    {
605       String JavaDoc operationName = op.getName();
606
607       // lookup by signature
608
Map JavaDoc sigMap = getOperationSignatureMap(operationName);
609       MBeanParameterInfo JavaDoc[] params = op.getSignature();
610       String JavaDoc sig = makeSignatureString(params);
611       Integer JavaDoc idx = (Integer JavaDoc)sigMap.get(sig);
612
613       StringBuffer JavaDoc sbRet = new StringBuffer JavaDoc(KEY_OP + ".");
614       sbRet.append(operationName);
615
616       if (idx == null)
617       {
618          if (m_setAmbiguousOperations.contains(op))
619          {
620             throw new IllegalStateException JavaDoc("ambiguous operation");
621          }
622
623          // no direct signature mapping, try matching by parameter counts
624
Map JavaDoc countMap = getOperationParamCountMap(operationName);
625          idx = (Integer JavaDoc)countMap.get(new Integer JavaDoc(params.length));
626          if (idx != null && idx.intValue() < 1)
627          {
628             throw new IllegalStateException JavaDoc("ambiguous operation");
629          }
630       }
631
632       if (idx != null)
633       {
634          sbRet.append(".");
635          sbRet.append(idx);
636       }
637       return sbRet.toString();
638    }
639
640    /*
641     * Initialise the set m_setAmbiguousOperations with those operations
642     * that have the same name and same number of parameters.
643     */

644    private void findAmbiguousOperations(MBeanInfo JavaDoc info)
645    {
646       // obtain potentially ambiguous operations (same name, same number parameters)
647
MBeanOperationInfo JavaDoc[] ops = info.getOperations();
648       Map JavaDoc mapNameToArgCountMap = new HashMap JavaDoc();
649       for (int i = 0; i < ops.length; i++)
650       {
651          MBeanOperationInfo JavaDoc op = ops[i];
652          String JavaDoc name = op.getName();
653          Map JavaDoc argCountToOp = (Map JavaDoc)mapNameToArgCountMap.get(name);
654          if (argCountToOp == null)
655          {
656             argCountToOp = new HashMap JavaDoc();
657             mapNameToArgCountMap.put(name, argCountToOp);
658          }
659
660          Integer JavaDoc count = new Integer JavaDoc(op.getSignature().length);
661          Object JavaDoc first = argCountToOp.get(count);
662          if (first != null)
663          {
664             // already have an operation with this number of args
665
m_setAmbiguousOperations.add(first); // Set so no duplication
666
m_setAmbiguousOperations.add(op); // this one is ambiguous too
667
}
668          else
669          {
670             argCountToOp.put(count, op);
671          }
672       }
673    }
674
675    /*
676     * Obtain Map of operation signature=>resource bundle index.
677     * Use lazy instantiation and caching.
678     * The entries in resource bundle have form :
679     * op.operationName.1.sig=xxx
680     * op.operationName.2.sig=yyy
681     *
682     * The above example would give xxx=>1, yyy=>2
683     */

684    private Map JavaDoc getOperationSignatureMap(String JavaDoc operationName)
685    {
686       // look up in cache
687
Map JavaDoc m = (Map JavaDoc)m_mapOperationNameToSignatures.get(operationName);
688       if (m != null)
689       {
690          return m;
691       }
692
693       // construct map
694
m = getSignatureMap(KEY_OP + "." + operationName);
695       m_mapOperationNameToSignatures.put(operationName, m); // cache
696
return m;
697    }
698
699    /*
700     * Obtain Map of parameter count =>resource bundle index for the given operation
701     * Use lazy instantiation and caching.
702     */

703    private Map JavaDoc getOperationParamCountMap(String JavaDoc operationName)
704    {
705       // look up in cache
706
Map JavaDoc m = (Map JavaDoc)m_mapOperationNameToParamCounts.get(operationName);
707       if (m != null)
708       {
709          return m;
710       }
711
712       // construct map
713
m = getParamCountMap(KEY_OP + "." + operationName);
714       m_mapOperationNameToParamCounts.put(operationName, m); // cache
715
return m;
716    }
717
718    /*
719     * Obtain a Map of parameter count => Integer index from resource bundle
720     * The entries in resource bundle have form :
721     * prefix.1.param.1=xxx
722     * prefix.1.param.2=yyy
723     * prefix.2.param.1=zzz
724     *
725     * The above example would give 2=>1, 1=>2 (index1 has 2 parameter, index 2 has 1 parameter)
726     * If there are duplicate parameter counts map to -1
727    */

728    private Map JavaDoc getParamCountMap(String JavaDoc prefix)
729    {
730       int nb;
731       Map JavaDoc m = new HashMap JavaDoc();
732
733       for (int i = 1; ; i++)
734       {
735          String JavaDoc key = prefix + "." + i;
736          String JavaDoc sig = getValueOrNullFromBundle(key);
737          if (sig == null)
738          {
739             break;
740          }
741          nb = 0;
742          for (int j = 1; ; j++)
743          {
744             key = prefix + "." + i + "." + KEY_PARAM + "." + j;
745             if (getValueOrNullFromBundle(key) != null)
746             {
747                nb = j;
748             }
749             else
750             {
751                break;
752             }
753          }
754          Integer JavaDoc nbObj = new Integer JavaDoc(nb);
755          int idx = m.containsKey(nbObj) ? -1 : i;
756          m.put(nbObj, new Integer JavaDoc(idx));
757       }
758       return m;
759    }
760
761    /*
762     * Create a map of signature string=>Integer index from resource bundle.
763     * The entries in resource bundle have form :
764     * prefix.1.sig=signature1
765     * prefix.2.sig=signature2
766     * ..
767     * The list stops at the first non existant index.
768     * The signatures are comma separated types of the form returned by
769     * Class.getName(), eg: java.lang.Object,Z,[Z;
770     */

771    private Map JavaDoc getSignatureMap(String JavaDoc prefix)
772    {
773       Map JavaDoc m = new HashMap JavaDoc();
774       for (int i = 1; ; i++)
775       {
776          String JavaDoc key = prefix + "." + i + "." + KEY_SIG;
777          String JavaDoc sig = getValueOrNullFromBundle(key);
778          if (sig == null)
779          {
780             break;
781          }
782          m.put(sig, new Integer JavaDoc(i));
783       }
784       return m;
785    }
786
787    // create a comma separated list of signatures.
788
private String JavaDoc makeSignatureString(MBeanParameterInfo JavaDoc[] params)
789    {
790       StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
791       for (int i = 0; i < params.length; i++)
792       {
793          if (i > 0)
794          {
795             sb.append(",");
796          }
797          sb.append(params[i].getType());
798       }
799       return sb.toString();
800    }
801
802    private String JavaDoc getValueFromBundle(String JavaDoc key)
803    {
804       String JavaDoc value;
805       try
806       {
807          value = m_bundle.getString(key);
808       }
809       catch (MissingResourceException JavaDoc e)
810       {
811          value = "??(" + key + ")";
812       }
813       return value;
814    }
815
816    private String JavaDoc getValueOrNullFromBundle(String JavaDoc key)
817    {
818       String JavaDoc value = null;
819       try
820       {
821          value = m_bundle.getString(key);
822       }
823       catch (MissingResourceException JavaDoc e)
824       {
825       }
826       return value;
827    }
828
829    private static class NestedResourceBundle extends ResourceBundle JavaDoc
830    {
831       private ResourceBundle JavaDoc _impl;
832
833       NestedResourceBundle(ResourceBundle JavaDoc impl)
834       {
835          _impl = impl;
836       }
837
838       void setParent(NestedResourceBundle parent)
839       {
840          super.setParent(parent);
841       }
842
843       /* (non-Javadoc)
844        * @see java.util.ResourceBundle#handleGetObject(java.lang.String)
845        */

846       protected Object JavaDoc handleGetObject(String JavaDoc key)
847       {
848          try
849          {
850             return _impl.getString(key);
851          }
852          catch (MissingResourceException JavaDoc e)
853          {
854             return null; // Resource bundle will ask parent
855
}
856       }
857
858       /* (non-Javadoc)
859        * @see java.util.ResourceBundle#getKeys()
860        */

861       public Enumeration JavaDoc getKeys()
862       {
863          // obtain union of all keys in bundle hierachy (no doublons)
864
HashSet JavaDoc hs = new HashSet JavaDoc();
865          addEnumeration(hs, _impl.getKeys());
866          if (parent != null)
867          {
868             addEnumeration(hs, parent.getKeys());
869          }
870          return Collections.enumeration(hs);
871       }
872
873       private void addEnumeration(Collection JavaDoc col, Enumeration JavaDoc e)
874       {
875          while (e.hasMoreElements())
876          {
877             col.add(e.nextElement());
878          }
879       }
880
881    }
882
883 }
884
Popular Tags