1 8 9 package mx4j.tools.i18n; 10 11 import java.util.Collection ; 12 import java.util.Collections ; 13 import java.util.Enumeration ; 14 import java.util.HashMap ; 15 import java.util.HashSet ; 16 import java.util.Locale ; 17 import java.util.Map ; 18 import java.util.MissingResourceException ; 19 import java.util.ResourceBundle ; 20 import java.util.Set ; 21 import java.util.StringTokenizer ; 22 import javax.management.MBeanAttributeInfo ; 23 import javax.management.MBeanConstructorInfo ; 24 import javax.management.MBeanInfo ; 25 import javax.management.MBeanOperationInfo ; 26 import javax.management.MBeanParameterInfo ; 27 import javax.management.NotCompliantMBeanException ; 28 import javax.management.StandardMBean ; 29 30 141 public class I18NStandardMBean extends StandardMBean 142 { 143 private static final String IDPROP_DEFAULT_LOCALE = 144 "mx4j.descriptionLocale"; 145 private static final String RESOURCE_SUFFIX = "MBeanResources"; 146 private static final String KEY_DESCR = "descr"; 147 private static final String KEY_CONS = "cons"; 148 private static final String KEY_ATTR = "attr"; 149 private static final String KEY_OP = "op"; 150 private static final String KEY_PARAM = "param"; 151 private static final String KEY_PARAM_NAME = "paramName"; 152 private static final String KEY_SIG = "sig"; 153 154 private static Locale g_defaultLocale = null; 155 156 private NestedResourceBundle m_bundle; 157 private Map m_mapConstructorSignatureToResourceIndex; 158 private Map m_mapConstructorParamCountToResourceIndex; 159 private Map m_mapConstructorToResourceIndex = new HashMap (); 160 private Map m_mapOperationNameToSignatures = new HashMap (); 161 private Map m_mapOperationNameToParamCounts = new HashMap (); 162 private Set m_setAmbiguousConstructors = new HashSet (); 163 private Set m_setAmbiguousOperations = new HashSet (); 164 165 170 public I18NStandardMBean(Object implementation, Class mbeanInterface) 171 throws NotCompliantMBeanException 172 { 173 this(implementation, mbeanInterface, null); 174 } 175 176 181 public I18NStandardMBean(Object implementation, 182 Class mbeanInterface, 183 Locale locale) 184 throws NotCompliantMBeanException 185 { 186 super(implementation, mbeanInterface); 187 setupBundle(implementation, locale); 188 } 189 190 195 protected I18NStandardMBean(Class mbeanInterface) 196 throws NotCompliantMBeanException 197 { 198 super(mbeanInterface); 199 setupBundle(this, null); 200 } 201 202 207 protected I18NStandardMBean(Class mbeanInterface, Locale locale) 208 throws NotCompliantMBeanException 209 { 210 super(mbeanInterface); 211 setupBundle(this, locale); 212 } 213 214 private void setupBundle(Object implementation, Locale locale) 215 { 216 if (locale == null) 218 { 219 locale = g_defaultLocale; 220 } 221 if (locale == null) 222 { 223 locale = getLocaleFromSystemProperties(); 224 } 225 226 NestedResourceBundle cur = null; 228 MissingResourceException ex = null; 229 for (Class c = implementation.getClass(); c != null; c = c.getSuperclass()) 230 { 231 String bundleName = c.getName() + RESOURCE_SUFFIX; 232 try 233 { 234 ResourceBundle 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 e) 247 { 248 if (m_bundle == null) ex = e; } 250 } 251 if (m_bundle == null) 252 { 253 ex.fillInStackTrace(); 254 throw ex; 255 } 256 } 257 258 private Locale getLocaleFromSystemProperties() 260 { 261 Locale locale = Locale.getDefault(); 262 String stdLocale = System.getProperty(IDPROP_DEFAULT_LOCALE); 263 if (stdLocale != null && stdLocale.length() > 0) 264 { 265 StringTokenizer st = new StringTokenizer (stdLocale, "_"); 266 switch (st.countTokens()) 267 { 268 case 2: 269 locale = new Locale (st.nextToken(), st.nextToken()); 270 break; 271 case 3: 272 locale = 273 new Locale (st.nextToken(), 274 st.nextToken(), 275 st.nextToken()); 276 break; 277 default : 278 throw new IllegalArgumentException ("Invalid locale in " 279 + IDPROP_DEFAULT_LOCALE 280 + ":" 281 + stdLocale); 282 } 283 } 284 return locale; 285 } 286 287 296 public static void setDefaultLocale(Locale locale) 297 { 298 g_defaultLocale = locale; 299 } 300 301 308 protected MBeanInfo getCachedMBeanInfo() 309 { 310 MBeanInfo info = super.getCachedMBeanInfo(); 311 if (info == null) 312 { 313 m_mapConstructorToResourceIndex = new HashMap (); 315 m_mapOperationNameToSignatures = new HashMap (); 316 m_mapOperationNameToParamCounts = new HashMap (); 317 m_setAmbiguousConstructors = new HashSet (); 318 m_setAmbiguousOperations = new HashSet (); 319 m_mapConstructorSignatureToResourceIndex = 320 getSignatureMap(KEY_CONS); 321 m_mapConstructorParamCountToResourceIndex = 322 getParamCountMap(KEY_CONS); 323 } 324 return info; 325 } 326 327 332 protected void cacheMBeanInfo(MBeanInfo 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 355 protected MBeanConstructorInfo [] getConstructors(MBeanConstructorInfo [] cstrs, 356 Object impl) 357 { 358 Map argCountToCstr = new HashMap (); 359 for (int i = 0; i < cstrs.length; i++) 360 { 361 MBeanConstructorInfo ci = cstrs[i]; 362 MBeanParameterInfo [] params = ci.getSignature(); 363 364 Integer count = new Integer (params.length); 366 Object first = argCountToCstr.get(count); 367 if (first != null) 368 { 369 m_setAmbiguousConstructors.add(first); m_setAmbiguousConstructors.add(ci); 372 } 374 else 375 { 376 argCountToCstr.put(count, ci); 377 } 378 379 String sig = makeSignatureString(params); 381 Integer idx = 382 (Integer )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 401 protected String getDescription(MBeanInfo info) 402 { 403 findAmbiguousOperations(info); return getValueFromBundle(KEY_DESCR); 405 } 406 407 416 protected String getDescription(MBeanConstructorInfo 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 435 protected String getDescription(MBeanConstructorInfo cstr, 436 MBeanParameterInfo 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 456 protected String getParameterName(MBeanConstructorInfo cstr, 457 MBeanParameterInfo param, 458 int seq) 459 { 460 int idx = getConstructorIndex(cstr); 461 String 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 480 protected String getDescription(MBeanAttributeInfo attr) 481 { 482 return getValueFromBundle(KEY_ATTR + "." + attr.getName()); 483 } 484 485 494 protected String getDescription(MBeanOperationInfo op) 495 { 496 try 497 { 498 return getValueFromBundle(getOperationKey(op)); 499 } 500 catch (IllegalStateException e) 501 { 502 return e.getMessage(); 503 } 504 } 505 506 515 protected String getDescription(MBeanOperationInfo op, 516 MBeanParameterInfo param, 517 int seq) 518 { 519 try 520 { 521 return getValueFromBundle(getOperationKey(op) + "." + KEY_PARAM + "." + (seq + 1)); 522 } 523 catch (IllegalStateException e) 524 { 525 return "parameter for " + e.getMessage(); 526 } 527 } 528 529 539 protected String getParameterName(MBeanOperationInfo op, 540 MBeanParameterInfo param, 541 int seq) 542 { 543 String name = null; 544 try 545 { 546 name = 547 getValueOrNullFromBundle(getOperationKey(op) 548 + "." 549 + KEY_PARAM_NAME 550 + "." 551 + (seq + 1)); 552 } 553 catch (IllegalStateException e) 554 { 555 } 556 557 if (name == null) 558 { 559 name = super.getParameterName(op, param, seq); 560 } 561 return name; 562 } 563 564 572 private int getConstructorIndex(MBeanConstructorInfo cons) 573 { 574 Integer idx = (Integer )m_mapConstructorToResourceIndex.get(cons); 575 if (idx != null) 576 { 577 return idx.intValue(); 578 } 579 580 if (m_setAmbiguousConstructors.contains(cons)) 582 return -1; 583 584 int nbParams = cons.getSignature().length; 586 idx = 587 (Integer )m_mapConstructorParamCountToResourceIndex.get(new Integer (nbParams)); 588 if (idx != null) 589 { 590 return idx.intValue(); 591 } 592 return 0; 593 } 594 595 603 private String getOperationKey(MBeanOperationInfo op) 604 { 605 String operationName = op.getName(); 606 607 Map sigMap = getOperationSignatureMap(operationName); 609 MBeanParameterInfo [] params = op.getSignature(); 610 String sig = makeSignatureString(params); 611 Integer idx = (Integer )sigMap.get(sig); 612 613 StringBuffer sbRet = new StringBuffer (KEY_OP + "."); 614 sbRet.append(operationName); 615 616 if (idx == null) 617 { 618 if (m_setAmbiguousOperations.contains(op)) 619 { 620 throw new IllegalStateException ("ambiguous operation"); 621 } 622 623 Map countMap = getOperationParamCountMap(operationName); 625 idx = (Integer )countMap.get(new Integer (params.length)); 626 if (idx != null && idx.intValue() < 1) 627 { 628 throw new IllegalStateException ("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 644 private void findAmbiguousOperations(MBeanInfo info) 645 { 646 MBeanOperationInfo [] ops = info.getOperations(); 648 Map mapNameToArgCountMap = new HashMap (); 649 for (int i = 0; i < ops.length; i++) 650 { 651 MBeanOperationInfo op = ops[i]; 652 String name = op.getName(); 653 Map argCountToOp = (Map )mapNameToArgCountMap.get(name); 654 if (argCountToOp == null) 655 { 656 argCountToOp = new HashMap (); 657 mapNameToArgCountMap.put(name, argCountToOp); 658 } 659 660 Integer count = new Integer (op.getSignature().length); 661 Object first = argCountToOp.get(count); 662 if (first != null) 663 { 664 m_setAmbiguousOperations.add(first); m_setAmbiguousOperations.add(op); } 668 else 669 { 670 argCountToOp.put(count, op); 671 } 672 } 673 } 674 675 684 private Map getOperationSignatureMap(String operationName) 685 { 686 Map m = (Map )m_mapOperationNameToSignatures.get(operationName); 688 if (m != null) 689 { 690 return m; 691 } 692 693 m = getSignatureMap(KEY_OP + "." + operationName); 695 m_mapOperationNameToSignatures.put(operationName, m); return m; 697 } 698 699 703 private Map getOperationParamCountMap(String operationName) 704 { 705 Map m = (Map )m_mapOperationNameToParamCounts.get(operationName); 707 if (m != null) 708 { 709 return m; 710 } 711 712 m = getParamCountMap(KEY_OP + "." + operationName); 714 m_mapOperationNameToParamCounts.put(operationName, m); return m; 716 } 717 718 728 private Map getParamCountMap(String prefix) 729 { 730 int nb; 731 Map m = new HashMap (); 732 733 for (int i = 1; ; i++) 734 { 735 String key = prefix + "." + i; 736 String 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 nbObj = new Integer (nb); 755 int idx = m.containsKey(nbObj) ? -1 : i; 756 m.put(nbObj, new Integer (idx)); 757 } 758 return m; 759 } 760 761 771 private Map getSignatureMap(String prefix) 772 { 773 Map m = new HashMap (); 774 for (int i = 1; ; i++) 775 { 776 String key = prefix + "." + i + "." + KEY_SIG; 777 String sig = getValueOrNullFromBundle(key); 778 if (sig == null) 779 { 780 break; 781 } 782 m.put(sig, new Integer (i)); 783 } 784 return m; 785 } 786 787 private String makeSignatureString(MBeanParameterInfo [] params) 789 { 790 StringBuffer sb = new StringBuffer (); 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 getValueFromBundle(String key) 803 { 804 String value; 805 try 806 { 807 value = m_bundle.getString(key); 808 } 809 catch (MissingResourceException e) 810 { 811 value = "??(" + key + ")"; 812 } 813 return value; 814 } 815 816 private String getValueOrNullFromBundle(String key) 817 { 818 String value = null; 819 try 820 { 821 value = m_bundle.getString(key); 822 } 823 catch (MissingResourceException e) 824 { 825 } 826 return value; 827 } 828 829 private static class NestedResourceBundle extends ResourceBundle 830 { 831 private ResourceBundle _impl; 832 833 NestedResourceBundle(ResourceBundle impl) 834 { 835 _impl = impl; 836 } 837 838 void setParent(NestedResourceBundle parent) 839 { 840 super.setParent(parent); 841 } 842 843 846 protected Object handleGetObject(String key) 847 { 848 try 849 { 850 return _impl.getString(key); 851 } 852 catch (MissingResourceException e) 853 { 854 return null; } 856 } 857 858 861 public Enumeration getKeys() 862 { 863 HashSet hs = new HashSet (); 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 col, Enumeration e) 874 { 875 while (e.hasMoreElements()) 876 { 877 col.add(e.nextElement()); 878 } 879 } 880 881 } 882 883 } 884 | Popular Tags |