View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  
19  package org.apache.commons.modeler;
20  
21  
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.InputStream;
25  import java.net.URL;
26  import java.util.ArrayList;
27  import java.util.Enumeration;
28  import java.util.HashMap;
29  import java.util.Hashtable;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.Collections;
33  import java.util.Map;
34  
35  import javax.management.DynamicMBean;
36  import javax.management.MBeanAttributeInfo;
37  import javax.management.MBeanInfo;
38  import javax.management.MBeanOperationInfo;
39  import javax.management.MBeanRegistration;
40  import javax.management.MBeanServer;
41  import javax.management.MBeanServerFactory;
42  import javax.management.MalformedObjectNameException;
43  import javax.management.ObjectName;
44  import javax.management.modelmbean.ModelMBean;
45  
46  import org.apache.commons.logging.Log;
47  import org.apache.commons.logging.LogFactory;
48  import org.apache.commons.modeler.modules.ModelerSource;
49  
50  /*
51     Issues:
52     - exceptions - too many "throws Exception"
53     - double check the interfaces 
54     - start removing the use of the experimental methods in tomcat, then remove
55       the methods ( before 1.1 final )
56     - is the security enough to prevent Registry beeing used to avoid the permission
57      checks in the mbean server ?
58  */ 
59  
60  /***
61   * Registry for modeler MBeans. 
62   *
63   * This is the main entry point into modeler. It provides methods to create
64   * and manipulate model mbeans and simplify their use.
65   *
66   * Starting with version 1.1, this is no longer a singleton and the static
67   * methods are strongly deprecated. In a container environment we can expect
68   * different applications to use different registries.
69   * 
70   * This class is itself an mbean.
71   * 
72   * IMPORTANT: public methods not marked with @since x.x are experimental or 
73   * internal. Should not be used.  
74   * 
75   * @author Craig R. McClanahan
76   * @author Costin Manolache
77   */
78  public class Registry implements RegistryMBean, MBeanRegistration  {
79      /*** Experimental support for manifest-based discovery.
80       */
81      public static String MODELER_MANIFEST="/META-INF/mbeans-descriptors.xml";
82  
83      /***
84       * The Log instance to which we will write our log messages.
85       */
86      private static Log log = LogFactory.getLog(Registry.class);
87  
88      // Support for the factory methods
89      
90      /*** Will be used to isolate different apps and enhance security
91       */
92      private static HashMap perLoaderRegistries=null;
93  
94      /***
95       * The registry instance created by our factory method the first time
96       * it is called.
97       */
98      private static Registry registry = null;
99  
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     publicong> 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 ) {/package-summary.html">strong>( 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 }