001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 019 package org.apache.commons.modeler; 020 021 022 import java.io.File; 023 import java.io.FileInputStream; 024 import java.io.InputStream; 025 import java.net.URL; 026 import java.util.ArrayList; 027 import java.util.Enumeration; 028 import java.util.HashMap; 029 import java.util.Hashtable; 030 import java.util.Iterator; 031 import java.util.List; 032 import java.util.Collections; 033 import java.util.Map; 034 035 import javax.management.DynamicMBean; 036 import javax.management.MBeanAttributeInfo; 037 import javax.management.MBeanInfo; 038 import javax.management.MBeanOperationInfo; 039 import javax.management.MBeanRegistration; 040 import javax.management.MBeanServer; 041 import javax.management.MBeanServerFactory; 042 import javax.management.MalformedObjectNameException; 043 import javax.management.ObjectName; 044 import javax.management.modelmbean.ModelMBean; 045 046 import org.apache.commons.logging.Log; 047 import org.apache.commons.logging.LogFactory; 048 import org.apache.commons.modeler.modules.ModelerSource; 049 050 /* 051 Issues: 052 - exceptions - too many "throws Exception" 053 - double check the interfaces 054 - start removing the use of the experimental methods in tomcat, then remove 055 the methods ( before 1.1 final ) 056 - is the security enough to prevent Registry beeing used to avoid the permission 057 checks in the mbean server ? 058 */ 059 060 /** 061 * Registry for modeler MBeans. 062 * 063 * This is the main entry point into modeler. It provides methods to create 064 * and manipulate model mbeans and simplify their use. 065 * 066 * Starting with version 1.1, this is no longer a singleton and the static 067 * methods are strongly deprecated. In a container environment we can expect 068 * different applications to use different registries. 069 * 070 * This class is itself an mbean. 071 * 072 * IMPORTANT: public methods not marked with @since x.x are experimental or 073 * internal. Should not be used. 074 * 075 * @author Craig R. McClanahan 076 * @author Costin Manolache 077 */ 078 public class Registry implements RegistryMBean, MBeanRegistration { 079 /** Experimental support for manifest-based discovery. 080 */ 081 public static String MODELER_MANIFEST="/META-INF/mbeans-descriptors.xml"; 082 083 /** 084 * The Log instance to which we will write our log messages. 085 */ 086 private static Log log = LogFactory.getLog(Registry.class); 087 088 // Support for the factory methods 089 090 /** Will be used to isolate different apps and enhance security 091 */ 092 private static HashMap perLoaderRegistries=null; 093 094 /** 095 * The registry instance created by our factory method the first time 096 * it is called. 097 */ 098 private static Registry registry = null; 099 100 // Per registy fields 101 102 /** 103 * The <code>MBeanServer</code> instance that we will use to register 104 * management beans. 105 */ 106 private MBeanServer server = null; 107 108 /** 109 * The set of ManagedBean instances for the beans this registry 110 * knows about, keyed by name. 111 */ 112 private final HashMap descriptors = new HashMap(); 113 114 /** List of managed byeans, keyed by class name 115 */ 116 private final HashMap descriptorsByClass = new HashMap(); 117 118 // map to avoid duplicated searching or loading descriptors 119 private final Map searchedPaths= Collections.synchronizedMap(new HashMap()); 120 121 private Object guard; 122 123 // Id - small ints to use array access. No reset on stop() 124 private Hashtable idDomains=new Hashtable(); 125 private Hashtable ids=new Hashtable(); 126 127 128 // ----------------------------------------------------------- Constructors 129 130 /** 131 */ 132 public Registry() { 133 super(); 134 } 135 136 // -------------------- Static methods -------------------- 137 // Factories 138 139 /** 140 * Factory method to create (if necessary) and return our 141 * <code>Registry</code> instance. 142 * 143 * Use this method to obtain a Registry - all other static methods 144 * are deprecated and shouldn't be used. 145 * 146 * The current version uses a static - future versions could use 147 * the thread class loader. 148 * 149 * @param key Support for application isolation. If null, the context class 150 * loader will be used ( if setUseContextClassLoader is called ) or the 151 * default registry is returned. 152 * @param guard Prevent access to the registry by untrusted components 153 * 154 * @since 1.1 155 */ 156 public synchronized static Registry getRegistry(Object key, Object guard) { 157 Registry localRegistry; 158 if( perLoaderRegistries!=null ) { 159 if( key==null ) 160 key=Thread.currentThread().getContextClassLoader(); 161 if( key != null ) { 162 localRegistry=(Registry)perLoaderRegistries.get(key); 163 if( localRegistry == null ) { 164 localRegistry=new Registry(); 165 localRegistry.guard=guard; 166 perLoaderRegistries.put( key, localRegistry ); 167 return localRegistry; 168 } 169 if( localRegistry.guard != null && 170 localRegistry.guard != guard ) { 171 return null; // XXX Should I throw a permission ex ? 172 } 173 return localRegistry; 174 } 175 } 176 177 // static 178 if (registry == null) { 179 registry = new Registry(); 180 } 181 if( registry.guard != null && 182 registry.guard != guard ) { 183 return null; 184 } 185 return (registry); 186 } 187 188 /** Allow containers to isolate apps. Can be called only once. 189 * It is highly recommended you call this method if using Registry in 190 * a container environment. The default is false for backward compatibility 191 * 192 * @param enable 193 * @since 1.1 194 */ 195 public static void setUseContextClassLoader( boolean enable ) { 196 if( enable ) { 197 perLoaderRegistries=new HashMap(); 198 } 199 } 200 201 // -------------------- Generic methods -------------------- 202 203 /** Set a guard object that will prevent access to this registry 204 * by unauthorized components 205 * 206 * @param guard 207 * 208 * @since 1.1 209 */ 210 public void setGuard( Object guard ) { 211 if( this.guard!=null ) { 212 return; // already set, only once 213 } 214 this.guard=guard; 215 } 216 217 /** Lifecycle method - clean up the registry metadata. 218 * 219 * @since 1.1 220 */ 221 public void stop() { 222 synchronized(descriptors) { 223 descriptorsByClass.clear(); 224 descriptors.clear(); 225 searchedPaths.clear(); 226 } 227 } 228 229 /** 230 * Load an extended mlet file. The source can be an URL, File or 231 * InputStream. 232 * 233 * All mbeans will be instantiated, registered and the attributes will be 234 * set. The result is a list of ObjectNames. 235 * 236 * @param source InputStream or URL of the file 237 * @param cl ClassLoader to be used to load the mbeans, or null to use the 238 * default JMX mechanism ( i.e. all registered loaders ) 239 * @return List of ObjectName for the loaded mbeans 240 * @throws Exception 241 * 242 * @since 1.1 243 */ 244 public List loadMBeans( Object source, ClassLoader cl ) 245 throws Exception 246 { 247 return load("MbeansSource", source, null ); 248 } 249 250 251 /** Load descriptors. The source can be a File or URL or InputStream for the 252 * descriptors file. In the case of File and URL, if the extension is ".ser" 253 * a serialized version will be loaded. 254 * 255 * Also ( experimental for now ) a ClassLoader - in which case META-INF/ will 256 * be used. 257 * 258 * This method should be used to explicitely load metadata - but this is not 259 * required in most cases. The registerComponent() method will find metadata 260 * in the same pacakge. 261 * 262 * @param source 263 */ 264 public void loadMetadata(Object source ) throws Exception { 265 if( source instanceof ClassLoader ) { 266 loadMetaInfDescriptors((ClassLoader)source); 267 } else { 268 loadDescriptors( null, source, null ); 269 } 270 271 } 272 273 /** Register a bean by creating a modeler mbean and adding it to the 274 * MBeanServer. 275 * 276 * If metadata is not loaded, we'll look up and read a file named 277 * "mbeans-descriptors.ser" or "mbeans-descriptors.xml" in the same package 278 * or parent. 279 * 280 * If the bean is an instance of DynamicMBean. it's metadata will be converted 281 * to a model mbean and we'll wrap it - so modeler services will be supported 282 * 283 * If the metadata is still not found, introspection will be used to extract 284 * it automatically. 285 * 286 * If an mbean is already registered under this name, it'll be first 287 * unregistered. 288 * 289 * If the component implements MBeanRegistration, the methods will be called. 290 * If the method has a method "setRegistry" that takes a RegistryMBean as 291 * parameter, it'll be called with the current registry. 292 * 293 * 294 * @param bean Object to be registered 295 * @param oname Name used for registration 296 * @param type The type of the mbean, as declared in mbeans-descriptors. If 297 * null, the name of the class will be used. This can be used as a hint or 298 * by subclasses. 299 * 300 * @since 1.1 301 */ 302 public void registerComponent(Object bean, String oname, String type) 303 throws Exception 304 { 305 registerComponent(bean, new ObjectName(oname), type); 306 } 307 308 /** Unregister a component. We'll first check if it is registered, 309 * and mask all errors. This is mostly a helper. 310 * 311 * @param oname 312 * 313 * @since 1.1 314 */ 315 public void unregisterComponent( String oname ) { 316 try { 317 unregisterComponent(new ObjectName(oname)); 318 } catch (MalformedObjectNameException e) { 319 log.info("Error creating object name " + e ); 320 } 321 } 322 323 324 /** Invoke a operation on a list of mbeans. Can be used to implement 325 * lifecycle operations. 326 * 327 * @param mbeans list of ObjectName on which we'll invoke the operations 328 * @param operation Name of the operation ( init, start, stop, etc) 329 * @param failFirst If false, exceptions will be ignored 330 * @throws Exception 331 * @since 1.1 332 */ 333 public void invoke( List mbeans, String operation, boolean failFirst ) 334 throws Exception 335 { 336 if( mbeans==null ) { 337 return; 338 } 339 Iterator itr=mbeans.iterator(); 340 while(itr.hasNext()) { 341 Object current=itr.next(); 342 ObjectName oN=null; 343 try { 344 if( current instanceof ObjectName) { 345 oN=(ObjectName)current; 346 } 347 if( current instanceof String ) { 348 oN=new ObjectName( (String)current ); 349 } 350 if( oN==null ) { 351 continue; 352 } 353 if( getMethodInfo(oN, operation) == null) { 354 continue; 355 } 356 getMBeanServer().invoke(oN, operation, 357 new Object[] {}, new String[] {}); 358 359 } catch( Exception t ) { 360 if( failFirst ) throw t; 361 log.info("Error initializing " + current + " " + t.toString()); 362 } 363 } 364 } 365 366 // -------------------- ID registry -------------------- 367 368 /** Return an int ID for faster access. Will be used for notifications 369 * and for other operations we want to optimize. 370 * 371 * @param domain Namespace 372 * @param name Type of the notification 373 * @return An unique id for the domain:name combination 374 * @since 1.1 375 */ 376 public synchronized int getId( String domain, String name) { 377 if( domain==null) { 378 domain=""; 379 } 380 Hashtable domainTable=(Hashtable)idDomains.get( domain ); 381 if( domainTable == null ) { 382 domainTable=new Hashtable(); 383 idDomains.put( domain, domainTable); 384 } 385 if( name==null ) { 386 name=""; 387 } 388 Integer i=(Integer)domainTable.get(name); 389 390 if( i!= null ) { 391 return i.intValue(); 392 } 393 394 int id[]=(int [])ids.get( domain ); 395 if( id == null ) { 396 id=new int[1]; 397 ids.put( domain, id); 398 } 399 int code=id[0]++; 400 domainTable.put( name, new Integer( code )); 401 return code; 402 } 403 404 // -------------------- Metadata -------------------- 405 // methods from 1.0 406 407 /** 408 * Add a new bean metadata to the set of beans known to this registry. 409 * This is used by internal components. 410 * 411 * @param bean The managed bean to be added 412 * @since 1.0 413 */ 414 public void addManagedBean(ManagedBean bean) { 415 // XXX Use group + name 416 synchronized(descriptors) { 417 descriptors.put(bean.getName(), bean); 418 if( bean.getType() != null ) { 419 descriptorsByClass.put( bean.getType(), bean ); 420 } 421 } 422 } 423 424 425 /** 426 * Find and return the managed bean definition for the specified 427 * bean name, if any; otherwise return <code>null</code>. 428 * 429 * @param name Name of the managed bean to be returned. Since 1.1, both 430 * short names or the full name of the class can be used. 431 * @since 1.0 432 */ 433 public ManagedBean findManagedBean(String name) { 434 // XXX Group ?? Use Group + Type 435 synchronized(descriptors) { 436 ManagedBean mb=((ManagedBean) descriptors.get(name)); 437 if( mb==null ) 438 mb=(ManagedBean)descriptorsByClass.get(name); 439 return mb; 440 } 441 } 442 443 /** 444 * Return the set of bean names for all managed beans known to 445 * this registry. 446 * 447 * @since 1.0 448 */ 449 public String[] findManagedBeans() { 450 synchronized(descriptors) { 451 return ((String[]) descriptors.keySet().toArray(new String[0])); 452 } 453 } 454 455 456 /** 457 * Return the set of bean names for all managed beans known to 458 * this registry that belong to the specified group. 459 * 460 * @param group Name of the group of interest, or <code>null</code> 461 * to select beans that do <em>not</em> belong to a group 462 * @since 1.0 463 */ 464 public String[] findManagedBeans(String group) { 465 466 ArrayList results = new ArrayList(); 467 synchronized (descriptors) { 468 for (Iterator items = descriptors.values().iterator(); items.hasNext(); ) { 469 ManagedBean item = (ManagedBean) items.next(); 470 if (group == null) { 471 if (item.getGroup() == null) { 472 results.add(item.getName()); 473 } 474 } else if (group.equals(item.getGroup())) { 475 results.add(item.getName()); 476 } 477 } 478 } 479 String values[] = new String[results.size()]; 480 return ((String[]) results.toArray(values)); 481 482 } 483 484 485 /** 486 * Remove an existing bean from the set of beans known to this registry. 487 * 488 * @param bean The managed bean to be removed 489 * @since 1.0 490 */ 491 public void removeManagedBean(ManagedBean bean) { 492 // TODO: change this to use group/name 493 synchronized (descriptors) { 494 descriptors.remove(bean.getName()); 495 descriptorsByClass.remove( bean.getType()); 496 } 497 } 498 499 // -------------------- Deprecated 1.0 methods -------------------- 500 501 /** 502 * Factory method to create (if necessary) and return our 503 * <code>MBeanServer</code> instance. 504 * 505 * @since 1.0 506 * @deprecated Use the instance method 507 */ 508 public static MBeanServer getServer() { 509 return Registry.getRegistry().getMBeanServer(); 510 } 511 512 /** 513 * Set the <code>MBeanServer</code> to be utilized for our 514 * registered management beans. 515 * 516 * @param mbeanServer The new <code>MBeanServer</code> instance 517 * @since 1.0 518 * @deprecated Use the instance method 519 */ 520 public static void setServer(MBeanServer mbeanServer) { 521 Registry.getRegistry().setMBeanServer(mbeanServer); 522 } 523 524 /** 525 * Load the registry from the XML input found in the specified input 526 * stream. 527 * 528 * @param stream InputStream containing the registry configuration 529 * information 530 * 531 * @exception Exception if any parsing or processing error occurs 532 * @deprecated use normal class method instead 533 * @since 1.0 534 */ 535 public static void loadRegistry(InputStream stream) throws Exception { 536 Registry registry = getRegistry(); 537 registry.loadMetadata(stream); 538 } 539 540 /** Get a "singelton" registry, or one per thread if setUseContextLoader 541 * was called 542 * 543 * @deprecated Not enough info - use the method that takes CL and domain 544 * @since 1.0 545 */ 546 public synchronized static Registry getRegistry() { 547 return getRegistry(null, null); 548 } 549 550 // -------------------- Helpers -------------------- 551 552 /** Get the type of an attribute of the object, from the metadata. 553 * 554 * @param oname 555 * @param attName 556 * @return null if metadata about the attribute is not found 557 * @since 1.1 558 */ 559 public String getType( ObjectName oname, String attName ) 560 { 561 String type=null; 562 MBeanInfo info; 563 try { 564 info=server.getMBeanInfo(oname); 565 } catch (Exception e) { 566 log.info( "Can't find metadata for object" + oname ); 567 return null; 568 } 569 570 MBeanAttributeInfo attInfo[]=info.getAttributes(); 571 for( int i=0; i<attInfo.length; i++ ) { 572 if( attName.equals(attInfo[i].getName())) { 573 type=attInfo[i].getType(); 574 return type; 575 } 576 } 577 return null; 578 } 579 580 /** Find the operation info for a method 581 * 582 * @param oname 583 * @param opName 584 * @return the operation info for the specified operation 585 */ 586 public MBeanOperationInfo getMethodInfo( ObjectName oname, String opName ) 587 { 588 String type=null; 589 MBeanInfo info; 590 try { 591 info=server.getMBeanInfo(oname); 592 } catch (Exception e) { 593 log.info( "Can't find metadata " + oname ); 594 return null; 595 } 596 MBeanOperationInfo attInfo[]=info.getOperations(); 597 for( int i=0; i<attInfo.length; i++ ) { 598 if( opName.equals(attInfo[i].getName())) { 599 return attInfo[i]; 600 } 601 } 602 return null; 603 } 604 605 /** Unregister a component. This is just a helper that 606 * avoids exceptions by checking if the mbean is already registered 607 * 608 * @param oname 609 */ 610 public void unregisterComponent( ObjectName oname ) { 611 try { 612 if( getMBeanServer().isRegistered(oname)) { 613 getMBeanServer().unregisterMBean(oname); 614 } 615 } catch( Throwable t ) { 616 log.error( "Error unregistering mbean ", t); 617 } 618 } 619 620 /** 621 * Factory method to create (if necessary) and return our 622 * <code>MBeanServer</code> instance. 623 * 624 */ 625 public synchronized MBeanServer getMBeanServer() { 626 long t1=System.currentTimeMillis(); 627 628 if (server == null) { 629 if( MBeanServerFactory.findMBeanServer(null).size() > 0 ) { 630 server=(MBeanServer)MBeanServerFactory.findMBeanServer(null).get(0); 631 if( log.isDebugEnabled() ) { 632 log.debug("Using existing MBeanServer " + (System.currentTimeMillis() - t1 )); 633 } 634 } else { 635 server=MBeanServerFactory.createMBeanServer(); 636 if( log.isDebugEnabled() ) { 637 log.debug("Creating MBeanServer"+ (System.currentTimeMillis() - t1 )); 638 } 639 } 640 } 641 return (server); 642 } 643 644 /** Find or load metadata. 645 */ 646 public ManagedBean findManagedBean(Object bean, Class beanClass, String type) 647 throws Exception 648 { 649 if( bean!=null && beanClass==null ) { 650 beanClass=bean.getClass(); 651 } 652 653 if( type==null ) { 654 type=beanClass.getName(); 655 } 656 657 // first look for existing descriptor 658 ManagedBean managed = findManagedBean(type); 659 660 // Search for a descriptor in the same package 661 if( managed==null ) { 662 // check package and parent packages 663 if( log.isDebugEnabled() ) { 664 log.debug( "Looking for descriptor "); 665 } 666 findDescriptor( beanClass, type ); 667 668 managed=findManagedBean(type); 669 } 670 671 if( bean instanceof DynamicMBean ) { 672 if( log.isDebugEnabled() ) { 673 log.debug( "Dynamic mbean support "); 674 } 675 // Dynamic mbean 676 loadDescriptors("MbeansDescriptorsDynamicMBeanSource", 677 bean, type); 678 679 managed=findManagedBean(type); 680 } 681 682 // Still not found - use introspection 683 if( managed==null ) { 684 if( log.isDebugEnabled() ) { 685 log.debug( "Introspecting "); 686 } 687 688 // introspection 689 loadDescriptors("MbeansDescriptorsIntrospectionSource", 690 beanClass, type); 691 692 managed=findManagedBean(type); 693 if( managed==null ) { 694 log.warn( "No metadata found for " + type ); 695 return null; 696 } 697 managed.setName( type ); 698 addManagedBean(managed); 699 } 700 return managed; 701 } 702 703 704 /** EXPERIMENTAL Convert a string to object, based on type. Used by several 705 * components. We could provide some pluggability. It is here to keep 706 * things consistent and avoid duplication in other tasks 707 * 708 * @param type Fully qualified class name of the resulting value 709 * @param value String value to be converted 710 * @return Converted value 711 */ 712 public Object convertValue(String type, String value) 713 { 714 Object objValue=value; 715 716 if( type==null || "java.lang.String".equals( type )) { 717 // string is default 718 objValue=value; 719 } else if( "javax.management.ObjectName".equals( type ) || 720 "ObjectName".equals( type )) { 721 try { 722 objValue=new ObjectName( value ); 723 } catch (MalformedObjectNameException e) { 724 return null; 725 } 726 } else if( "java.lang.Integer".equals( type ) || 727 "int".equals( type )) { 728 objValue=new Integer( value ); 729 } else if("java.lang.Long".equals( type ) || 730 "long".equals( type )) { 731 objValue = new Long( value ); 732 } else if( "java.lang.Boolean".equals( type ) || 733 "boolean".equals( type )) { 734 objValue=Boolean.valueOf( value ); 735 } 736 return objValue; 737 } 738 739 /** Experimental. 740 * 741 * @param sourceType 742 * @param source 743 * @param param 744 * @return List of descriptors 745 * @throws Exception 746 * @deprecated bad interface, mixing of metadata and mbeans 747 */ 748 public List load( String sourceType, Object source, String param) 749 throws Exception 750 { 751 if( log.isTraceEnabled()) { 752 log.trace("load " + source ); 753 } 754 String location=null; 755 String type=null; 756 Object inputsource=null; 757 758 if( source instanceof DynamicMBean ) { 759 sourceType="MbeansDescriptorsDynamicMBeanSource"; 760 inputsource=source; 761 } else if( source instanceof URL ) { 762 URL url=(URL)source; 763 location=url.toString(); 764 type=param; 765 inputsource=url.openStream(); 766 if( sourceType == null ) { 767 sourceType = sourceTypeFromExt(location); 768 } 769 } else if( source instanceof File ) { 770 location=((File)source).getAbsolutePath(); 771 inputsource=new FileInputStream((File)source); 772 type=param; 773 if( sourceType == null ) { 774 sourceType = sourceTypeFromExt(location); 775 } 776 } else if( source instanceof InputStream ) { 777 type=param; 778 inputsource=source; 779 } else if( source instanceof Class ) { 780 location=((Class)source).getName(); 781 type=param; 782 inputsource=source; 783 if( sourceType== null ) { 784 sourceType="MbeansDescriptorsIntrospectionSource"; 785 } 786 } 787 788 if( sourceType==null ) { 789 sourceType="MbeansDescriptorsDOMSource"; 790 } 791 ModelerSource ds=getModelerSource(sourceType); 792 List mbeans=ds.loadDescriptors(this, location, type, inputsource); 793 794 return mbeans; 795 } 796 797 private String sourceTypeFromExt( String s ) { 798 if( s.endsWith( ".ser")) { 799 return "MbeansDescriptorsSerSource"; 800 } 801 else if( s.endsWith(".xml")) { 802 return "MbeansDescriptorsDOMSource"; 803 } 804 return null; 805 } 806 807 /** Register a component 808 * XXX make it private 809 * 810 * @param bean 811 * @param oname 812 * @param type 813 * @throws Exception 814 */ 815 public void registerComponent(Object bean, ObjectName oname, String type) 816 throws Exception 817 { 818 if( log.isDebugEnabled() ) { 819 log.debug( "Managed= "+ oname); 820 } 821 822 if( bean ==null ) { 823 log.error("Null component " + oname ); 824 return; 825 } 826 827 try { 828 if( type==null ) { 829 type=bean.getClass().getName(); 830 } 831 832 ManagedBean managed = findManagedBean(bean.getClass(), type); 833 834 // The real mbean is created and registered 835 ModelMBean mbean = managed.createMBean(bean); 836 837 if( getMBeanServer().isRegistered( oname )) { 838 if( log.isDebugEnabled()) { 839 log.debug("Unregistering existing component " + oname ); 840 } 841 getMBeanServer().unregisterMBean( oname ); 842 } 843 844 getMBeanServer().registerMBean( mbean, oname); 845 } catch( Exception ex) { 846 log.error("Error registering " + oname, ex ); 847 throw ex; 848 } 849 } 850 851 /** Lookup the component descriptor in the package and 852 * in the parent packages. 853 * 854 * @param packageName 855 */ 856 public synchronized void loadDescriptors( String packageName, ClassLoader classLoader ) { 857 String res=packageName.replace( '.', '/'); 858 859 if( log.isTraceEnabled() ) { 860 log.trace("Finding descriptor " + res ); 861 } 862 863 if( searchedPaths.get( packageName ) != null ) { 864 return; 865 } 866 String descriptors=res + "/mbeans-descriptors.ser"; 867 868 URL dURL=classLoader.getResource( descriptors ); 869 870 if( dURL == null ) { 871 descriptors=res + "/mbeans-descriptors.xml"; 872 dURL=classLoader.getResource( descriptors ); 873 } 874 if( dURL == null ) { 875 return; 876 } 877 878 log.debug( "Found " + dURL); 879 searchedPaths.put( packageName, dURL ); 880 try { 881 if( descriptors.endsWith(".xml" )) 882 loadDescriptors("MbeansDescriptorsDOMSource", dURL, null); 883 else 884 loadDescriptors("MbeansDescriptorsSerSource", dURL, null); 885 } catch(Exception ex ) { 886 log.error("Error loading " + dURL); 887 } 888 } 889 890 /** Experimental. Will become private, some code may still use it 891 * 892 * @param sourceType 893 * @param source 894 * @param param 895 * @throws Exception 896 * @deprecated 897 */ 898 public void loadDescriptors( String sourceType, Object source, String param) 899 throws Exception 900 { 901 List mbeans=load( sourceType, source, param ); 902 if( mbeans == null) return; 903 904 Iterator itr=mbeans.iterator(); 905 while( itr.hasNext() ) { 906 Object mb=itr.next(); 907 if( mb instanceof ManagedBean) { 908 addManagedBean((ManagedBean)mb); 909 } 910 } 911 } 912 913 /** Discover all META-INF/modeler.xml files in classpath and register 914 * the components 915 * 916 * @since EXPERIMENTAL 917 */ 918 private void loadMetaInfDescriptors(ClassLoader cl) { 919 try { 920 Enumeration en=cl.getResources(MODELER_MANIFEST); 921 while( en.hasMoreElements() ) { 922 URL url=(URL)en.nextElement(); 923 InputStream is=url.openStream(); 924 if( log.isDebugEnabled()) log.debug("Loading " + url); 925 loadDescriptors("MBeansDescriptorDOMSource", is, null ); 926 } 927 } catch( Exception ex ) { 928 ex.printStackTrace(); 929 } 930 } 931 932 /** Lookup the component descriptor in the package and 933 * in the parent packages. 934 * 935 * @param beanClass 936 * @param type 937 */ 938 private void findDescriptor( Class beanClass, String type ) { 939 if( type==null ) { 940 type=beanClass.getName(); 941 } 942 ClassLoader classLoader=null; 943 if( beanClass!=null ) { 944 classLoader=beanClass.getClassLoader(); 945 } 946 if( classLoader==null ) { 947 classLoader=Thread.currentThread().getContextClassLoader(); 948 } 949 if( classLoader==null ) { 950 classLoader=this.getClass().getClassLoader(); 951 } 952 953 String pkg=type; 954 while( pkg.indexOf( ".") > 0 ) { 955 int lastComp=pkg.lastIndexOf( "."); 956 if( lastComp <= 0 ) return; 957 pkg=pkg.substring(0, lastComp); 958 if( searchedPaths.get( pkg ) != null ) { 959 return; 960 } 961 loadDescriptors(pkg, classLoader); 962 } 963 } 964 965 private ModelerSource getModelerSource( String type ) 966 throws Exception 967 { 968 if( type==null ) type="MbeansDescriptorsDOMSource"; 969 if( type.indexOf( ".") < 0 ) { 970 type="org.apache.commons.modeler.modules." + type; 971 } 972 973 Class c=Class.forName( type ); 974 ModelerSource ds=(ModelerSource)c.newInstance(); 975 return ds; 976 } 977 978 979 // -------------------- Registration -------------------- 980 981 public ObjectName preRegister(MBeanServer server, 982 ObjectName name) throws Exception 983 { 984 this.server=server; 985 return name; 986 } 987 988 public void postRegister(Boolean registrationDone) { 989 } 990 991 public void preDeregister() throws Exception { 992 } 993 994 public void postDeregister() { 995 } 996 997 998 999 1000 // -------------------- DEPRECATED METHODS -------------------- 1001 // May still be used in tomcat 1002 // Never part of an official release 1003 1004 /** Called by a registry or by the container to unload a loader 1005 * @param loader 1006 */ 1007 public void unregisterRegistry(ClassLoader loader ) { 1008 // XXX Cleanup ? 1009 perLoaderRegistries.remove(loader); 1010 } 1011 1012 public ManagedBean findManagedBean(Class beanClass, String type) 1013 throws Exception 1014 { 1015 return findManagedBean(null, beanClass, type); 1016 } 1017 1018 /** 1019 * Set the <code>MBeanServer</code> to be utilized for our 1020 * registered management beans. 1021 * 1022 * @param server The new <code>MBeanServer</code> instance 1023 */ 1024 public void setMBeanServer( MBeanServer server ) { 1025 this.server=server; 1026 } 1027 1028 public void resetMetadata() { 1029 stop(); 1030 } 1031 /** 1032 * Load the registry from the XML input found in the specified input 1033 * stream. 1034 * 1035 * @param source Source to be used to load. Can be an InputStream or URL. 1036 * 1037 * @exception Exception if any parsing or processing error occurs 1038 */ 1039 public void loadDescriptors( Object source ) 1040 throws Exception 1041 { 1042 loadDescriptors("MbeansDescriptorsDOMSource", source, null ); 1043 } 1044 1045 /** @deprecated - may still be used in code using pre-1.1 builds 1046 */ 1047 public void registerComponent(Object bean, String domain, String type, 1048 String name) 1049 throws Exception 1050 { 1051 StringBuffer sb=new StringBuffer(); 1052 sb.append( domain ).append(":"); 1053 sb.append( name ); 1054 String nameStr=sb.toString(); 1055 ObjectName oname=new ObjectName( nameStr ); 1056 registerComponent(bean, oname, type ); 1057 } 1058 1059 1060 1061 // should be removed 1062 public void unregisterComponent( String domain, String name ) { 1063 try { 1064 ObjectName oname=new ObjectName( domain + ":" + name ); 1065 1066 // XXX remove from our tables. 1067 getMBeanServer().unregisterMBean( oname ); 1068 } catch( Throwable t ) { 1069 log.error( "Error unregistering mbean ", t ); 1070 } 1071 } 1072 1073 public List loadMBeans( Object source ) 1074 throws Exception 1075 { 1076 return loadMBeans( source, null ); 1077 } 1078 1079 1080 /** 1081 * Load the registry from a cached .ser file. This is typically 2-3 times 1082 * faster than parsing the XML. 1083 * 1084 * @param source Source to be used to load. Can be an InputStream or URL. 1085 * 1086 * @exception Exception if any parsing or processing error occurs 1087 * @deprecated Loaded automatically or using a File or Url ending in .ser 1088 */ 1089 public void loadCachedDescriptors( Object source ) 1090 throws Exception 1091 { 1092 loadDescriptors("MbeansDescriptorsSerSource", source, null ); 1093 } 1094 }