View Javadoc

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