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