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    }