0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.commons.modeler;
0019:
0020: import java.io.File;
0021: import java.io.FileInputStream;
0022: import java.io.InputStream;
0023: import java.net.URL;
0024: import java.util.ArrayList;
0025: import java.util.Enumeration;
0026: import java.util.HashMap;
0027: import java.util.Hashtable;
0028: import java.util.Iterator;
0029: import java.util.List;
0030: import java.util.Collections;
0031: import java.util.Map;
0032:
0033: import javax.management.DynamicMBean;
0034: import javax.management.MBeanAttributeInfo;
0035: import javax.management.MBeanInfo;
0036: import javax.management.MBeanOperationInfo;
0037: import javax.management.MBeanRegistration;
0038: import javax.management.MBeanServer;
0039: import javax.management.MBeanServerFactory;
0040: import javax.management.MalformedObjectNameException;
0041: import javax.management.ObjectName;
0042: import javax.management.modelmbean.ModelMBean;
0043:
0044: import org.apache.commons.logging.Log;
0045: import org.apache.commons.logging.LogFactory;
0046: import org.apache.commons.modeler.modules.ModelerSource;
0047:
0048: /*
0049: Issues:
0050: - exceptions - too many "throws Exception"
0051: - double check the interfaces
0052: - start removing the use of the experimental methods in tomcat, then remove
0053: the methods ( before 1.1 final )
0054: - is the security enough to prevent Registry beeing used to avoid the permission
0055: checks in the mbean server ?
0056: */
0057:
0058: /**
0059: * Registry for modeler MBeans.
0060: *
0061: * This is the main entry point into modeler. It provides methods to create
0062: * and manipulate model mbeans and simplify their use.
0063: *
0064: * Starting with version 1.1, this is no longer a singleton and the static
0065: * methods are strongly deprecated. In a container environment we can expect
0066: * different applications to use different registries.
0067: *
0068: * This class is itself an mbean.
0069: *
0070: * IMPORTANT: public methods not marked with @since x.x are experimental or
0071: * internal. Should not be used.
0072: *
0073: * @author Craig R. McClanahan
0074: * @author Costin Manolache
0075: */
0076: public class Registry implements RegistryMBean, MBeanRegistration {
0077: /** Experimental support for manifest-based discovery.
0078: */
0079: public static String MODELER_MANIFEST = "/META-INF/mbeans-descriptors.xml";
0080:
0081: /**
0082: * The Log instance to which we will write our log messages.
0083: */
0084: private static Log log = LogFactory.getLog(Registry.class);
0085:
0086: // Support for the factory methods
0087:
0088: /** Will be used to isolate different apps and enhance security
0089: */
0090: private static HashMap perLoaderRegistries = null;
0091:
0092: /**
0093: * The registry instance created by our factory method the first time
0094: * it is called.
0095: */
0096: private static Registry registry = null;
0097:
0098: // Per registy fields
0099:
0100: /**
0101: * The <code>MBeanServer</code> instance that we will use to register
0102: * management beans.
0103: */
0104: private MBeanServer server = null;
0105:
0106: /**
0107: * The set of ManagedBean instances for the beans this registry
0108: * knows about, keyed by name.
0109: */
0110: private final HashMap descriptors = new HashMap();
0111:
0112: /** List of managed byeans, keyed by class name
0113: */
0114: private final HashMap descriptorsByClass = new HashMap();
0115:
0116: // map to avoid duplicated searching or loading descriptors
0117: private final Map searchedPaths = Collections
0118: .synchronizedMap(new HashMap());
0119:
0120: private Object guard;
0121:
0122: // Id - small ints to use array access. No reset on stop()
0123: private Hashtable idDomains = new Hashtable();
0124: private Hashtable ids = new Hashtable();
0125:
0126: // ----------------------------------------------------------- Constructors
0127:
0128: /**
0129: */
0130: public Registry() {
0131: super ();
0132: }
0133:
0134: // -------------------- Static methods --------------------
0135: // Factories
0136:
0137: /**
0138: * Factory method to create (if necessary) and return our
0139: * <code>Registry</code> instance.
0140: *
0141: * Use this method to obtain a Registry - all other static methods
0142: * are deprecated and shouldn't be used.
0143: *
0144: * The current version uses a static - future versions could use
0145: * the thread class loader.
0146: *
0147: * @param key Support for application isolation. If null, the context class
0148: * loader will be used ( if setUseContextClassLoader is called ) or the
0149: * default registry is returned.
0150: * @param guard Prevent access to the registry by untrusted components
0151: *
0152: * @since 1.1
0153: */
0154: public synchronized static Registry getRegistry(Object key,
0155: Object guard) {
0156: Registry localRegistry;
0157: if (perLoaderRegistries != null) {
0158: if (key == null)
0159: key = Thread.currentThread().getContextClassLoader();
0160: if (key != null) {
0161: localRegistry = (Registry) perLoaderRegistries.get(key);
0162: if (localRegistry == null) {
0163: localRegistry = new Registry();
0164: localRegistry.guard = guard;
0165: perLoaderRegistries.put(key, localRegistry);
0166: return localRegistry;
0167: }
0168: if (localRegistry.guard != null
0169: && localRegistry.guard != guard) {
0170: return null; // XXX Should I throw a permission ex ?
0171: }
0172: return localRegistry;
0173: }
0174: }
0175:
0176: // static
0177: if (registry == null) {
0178: registry = new Registry();
0179: }
0180: if (registry.guard != null && registry.guard != guard) {
0181: return null;
0182: }
0183: return (registry);
0184: }
0185:
0186: /** Allow containers to isolate apps. Can be called only once.
0187: * It is highly recommended you call this method if using Registry in
0188: * a container environment. The default is false for backward compatibility
0189: *
0190: * @param enable
0191: * @since 1.1
0192: */
0193: public static void setUseContextClassLoader(boolean enable) {
0194: if (enable) {
0195: perLoaderRegistries = new HashMap();
0196: }
0197: }
0198:
0199: // -------------------- Generic methods --------------------
0200:
0201: /** Set a guard object that will prevent access to this registry
0202: * by unauthorized components
0203: *
0204: * @param guard
0205: *
0206: * @since 1.1
0207: */
0208: public void setGuard(Object guard) {
0209: if (this .guard != null) {
0210: return; // already set, only once
0211: }
0212: this .guard = guard;
0213: }
0214:
0215: /** Lifecycle method - clean up the registry metadata.
0216: *
0217: * @since 1.1
0218: */
0219: public void stop() {
0220: synchronized (descriptors) {
0221: descriptorsByClass.clear();
0222: descriptors.clear();
0223: searchedPaths.clear();
0224: }
0225: }
0226:
0227: /**
0228: * Load an extended mlet file. The source can be an URL, File or
0229: * InputStream.
0230: *
0231: * All mbeans will be instantiated, registered and the attributes will be
0232: * set. The result is a list of ObjectNames.
0233: *
0234: * @param source InputStream or URL of the file
0235: * @param cl ClassLoader to be used to load the mbeans, or null to use the
0236: * default JMX mechanism ( i.e. all registered loaders )
0237: * @return List of ObjectName for the loaded mbeans
0238: * @throws Exception
0239: *
0240: * @since 1.1
0241: */
0242: public List loadMBeans(Object source, ClassLoader cl)
0243: throws Exception {
0244: return load("MbeansSource", source, null);
0245: }
0246:
0247: /** Load descriptors. The source can be a File or URL or InputStream for the
0248: * descriptors file. In the case of File and URL, if the extension is ".ser"
0249: * a serialized version will be loaded.
0250: *
0251: * Also ( experimental for now ) a ClassLoader - in which case META-INF/ will
0252: * be used.
0253: *
0254: * This method should be used to explicitely load metadata - but this is not
0255: * required in most cases. The registerComponent() method will find metadata
0256: * in the same pacakge.
0257: *
0258: * @param source
0259: */
0260: public void loadMetadata(Object source) throws Exception {
0261: if (source instanceof ClassLoader) {
0262: loadMetaInfDescriptors((ClassLoader) source);
0263: } else {
0264: loadDescriptors(null, source, null);
0265: }
0266:
0267: }
0268:
0269: /** Register a bean by creating a modeler mbean and adding it to the
0270: * MBeanServer.
0271: *
0272: * If metadata is not loaded, we'll look up and read a file named
0273: * "mbeans-descriptors.ser" or "mbeans-descriptors.xml" in the same package
0274: * or parent.
0275: *
0276: * If the bean is an instance of DynamicMBean. it's metadata will be converted
0277: * to a model mbean and we'll wrap it - so modeler services will be supported
0278: *
0279: * If the metadata is still not found, introspection will be used to extract
0280: * it automatically.
0281: *
0282: * If an mbean is already registered under this name, it'll be first
0283: * unregistered.
0284: *
0285: * If the component implements MBeanRegistration, the methods will be called.
0286: * If the method has a method "setRegistry" that takes a RegistryMBean as
0287: * parameter, it'll be called with the current registry.
0288: *
0289: *
0290: * @param bean Object to be registered
0291: * @param oname Name used for registration
0292: * @param type The type of the mbean, as declared in mbeans-descriptors. If
0293: * null, the name of the class will be used. This can be used as a hint or
0294: * by subclasses.
0295: *
0296: * @since 1.1
0297: */
0298: public void registerComponent(Object bean, String oname, String type)
0299: throws Exception {
0300: registerComponent(bean, new ObjectName(oname), type);
0301: }
0302:
0303: /** Unregister a component. We'll first check if it is registered,
0304: * and mask all errors. This is mostly a helper.
0305: *
0306: * @param oname
0307: *
0308: * @since 1.1
0309: */
0310: public void unregisterComponent(String oname) {
0311: try {
0312: unregisterComponent(new ObjectName(oname));
0313: } catch (MalformedObjectNameException e) {
0314: log.info("Error creating object name " + e);
0315: }
0316: }
0317:
0318: /** Invoke a operation on a list of mbeans. Can be used to implement
0319: * lifecycle operations.
0320: *
0321: * @param mbeans list of ObjectName on which we'll invoke the operations
0322: * @param operation Name of the operation ( init, start, stop, etc)
0323: * @param failFirst If false, exceptions will be ignored
0324: * @throws Exception
0325: * @since 1.1
0326: */
0327: public void invoke(List mbeans, String operation, boolean failFirst)
0328: throws Exception {
0329: if (mbeans == null) {
0330: return;
0331: }
0332: Iterator itr = mbeans.iterator();
0333: while (itr.hasNext()) {
0334: Object current = itr.next();
0335: ObjectName oN = null;
0336: try {
0337: if (current instanceof ObjectName) {
0338: oN = (ObjectName) current;
0339: }
0340: if (current instanceof String) {
0341: oN = new ObjectName((String) current);
0342: }
0343: if (oN == null) {
0344: continue;
0345: }
0346: if (getMethodInfo(oN, operation) == null) {
0347: continue;
0348: }
0349: getMBeanServer().invoke(oN, operation, new Object[] {},
0350: new String[] {});
0351:
0352: } catch (Exception t) {
0353: if (failFirst)
0354: throw t;
0355: log.info("Error initializing " + current + " "
0356: + t.toString());
0357: }
0358: }
0359: }
0360:
0361: // -------------------- ID registry --------------------
0362:
0363: /** Return an int ID for faster access. Will be used for notifications
0364: * and for other operations we want to optimize.
0365: *
0366: * @param domain Namespace
0367: * @param name Type of the notification
0368: * @return An unique id for the domain:name combination
0369: * @since 1.1
0370: */
0371: public synchronized int getId(String domain, String name) {
0372: if (domain == null) {
0373: domain = "";
0374: }
0375: Hashtable domainTable = (Hashtable) idDomains.get(domain);
0376: if (domainTable == null) {
0377: domainTable = new Hashtable();
0378: idDomains.put(domain, domainTable);
0379: }
0380: if (name == null) {
0381: name = "";
0382: }
0383: Integer i = (Integer) domainTable.get(name);
0384:
0385: if (i != null) {
0386: return i.intValue();
0387: }
0388:
0389: int id[] = (int[]) ids.get(domain);
0390: if (id == null) {
0391: id = new int[1];
0392: ids.put(domain, id);
0393: }
0394: int code = id[0]++;
0395: domainTable.put(name, new Integer(code));
0396: return code;
0397: }
0398:
0399: // -------------------- Metadata --------------------
0400: // methods from 1.0
0401:
0402: /**
0403: * Add a new bean metadata to the set of beans known to this registry.
0404: * This is used by internal components.
0405: *
0406: * @param bean The managed bean to be added
0407: * @since 1.0
0408: */
0409: public void addManagedBean(ManagedBean bean) {
0410: // XXX Use group + name
0411: synchronized (descriptors) {
0412: descriptors.put(bean.getName(), bean);
0413: if (bean.getType() != null) {
0414: descriptorsByClass.put(bean.getType(), bean);
0415: }
0416: }
0417: }
0418:
0419: /**
0420: * Find and return the managed bean definition for the specified
0421: * bean name, if any; otherwise return <code>null</code>.
0422: *
0423: * @param name Name of the managed bean to be returned. Since 1.1, both
0424: * short names or the full name of the class can be used.
0425: * @since 1.0
0426: */
0427: public ManagedBean findManagedBean(String name) {
0428: // XXX Group ?? Use Group + Type
0429: synchronized (descriptors) {
0430: ManagedBean mb = ((ManagedBean) descriptors.get(name));
0431: if (mb == null)
0432: mb = (ManagedBean) descriptorsByClass.get(name);
0433: return mb;
0434: }
0435: }
0436:
0437: /**
0438: * Return the set of bean names for all managed beans known to
0439: * this registry.
0440: *
0441: * @since 1.0
0442: */
0443: public String[] findManagedBeans() {
0444: synchronized (descriptors) {
0445: return ((String[]) descriptors.keySet().toArray(
0446: new String[0]));
0447: }
0448: }
0449:
0450: /**
0451: * Return the set of bean names for all managed beans known to
0452: * this registry that belong to the specified group.
0453: *
0454: * @param group Name of the group of interest, or <code>null</code>
0455: * to select beans that do <em>not</em> belong to a group
0456: * @since 1.0
0457: */
0458: public String[] findManagedBeans(String group) {
0459:
0460: ArrayList results = new ArrayList();
0461: synchronized (descriptors) {
0462: for (Iterator items = descriptors.values().iterator(); items
0463: .hasNext();) {
0464: ManagedBean item = (ManagedBean) items.next();
0465: if (group == null) {
0466: if (item.getGroup() == null) {
0467: results.add(item.getName());
0468: }
0469: } else if (group.equals(item.getGroup())) {
0470: results.add(item.getName());
0471: }
0472: }
0473: }
0474: String values[] = new String[results.size()];
0475: return ((String[]) results.toArray(values));
0476:
0477: }
0478:
0479: /**
0480: * Remove an existing bean from the set of beans known to this registry.
0481: *
0482: * @param bean The managed bean to be removed
0483: * @since 1.0
0484: */
0485: public void removeManagedBean(ManagedBean bean) {
0486: // TODO: change this to use group/name
0487: synchronized (descriptors) {
0488: descriptors.remove(bean.getName());
0489: descriptorsByClass.remove(bean.getType());
0490: }
0491: }
0492:
0493: // -------------------- Deprecated 1.0 methods --------------------
0494:
0495: /**
0496: * Factory method to create (if necessary) and return our
0497: * <code>MBeanServer</code> instance.
0498: *
0499: * @since 1.0
0500: * @deprecated Use the instance method
0501: */
0502: public static MBeanServer getServer() {
0503: return Registry.getRegistry().getMBeanServer();
0504: }
0505:
0506: /**
0507: * Set the <code>MBeanServer</code> to be utilized for our
0508: * registered management beans.
0509: *
0510: * @param mbeanServer The new <code>MBeanServer</code> instance
0511: * @since 1.0
0512: * @deprecated Use the instance method
0513: */
0514: public static void setServer(MBeanServer mbeanServer) {
0515: Registry.getRegistry().setMBeanServer(mbeanServer);
0516: }
0517:
0518: /**
0519: * Load the registry from the XML input found in the specified input
0520: * stream.
0521: *
0522: * @param stream InputStream containing the registry configuration
0523: * information
0524: *
0525: * @exception Exception if any parsing or processing error occurs
0526: * @deprecated use normal class method instead
0527: * @since 1.0
0528: */
0529: public static void loadRegistry(InputStream stream)
0530: throws Exception {
0531: Registry registry = getRegistry();
0532: registry.loadMetadata(stream);
0533: }
0534:
0535: /** Get a "singelton" registry, or one per thread if setUseContextLoader
0536: * was called
0537: *
0538: * @deprecated Not enough info - use the method that takes CL and domain
0539: * @since 1.0
0540: */
0541: public synchronized static Registry getRegistry() {
0542: return getRegistry(null, null);
0543: }
0544:
0545: // -------------------- Helpers --------------------
0546:
0547: /** Get the type of an attribute of the object, from the metadata.
0548: *
0549: * @param oname
0550: * @param attName
0551: * @return null if metadata about the attribute is not found
0552: * @since 1.1
0553: */
0554: public String getType(ObjectName oname, String attName) {
0555: String type = null;
0556: MBeanInfo info;
0557: try {
0558: info = server.getMBeanInfo(oname);
0559: } catch (Exception e) {
0560: log.info("Can't find metadata for object" + oname);
0561: return null;
0562: }
0563:
0564: MBeanAttributeInfo attInfo[] = info.getAttributes();
0565: for (int i = 0; i < attInfo.length; i++) {
0566: if (attName.equals(attInfo[i].getName())) {
0567: type = attInfo[i].getType();
0568: return type;
0569: }
0570: }
0571: return null;
0572: }
0573:
0574: /** Find the operation info for a method
0575: *
0576: * @param oname
0577: * @param opName
0578: * @return the operation info for the specified operation
0579: */
0580: public MBeanOperationInfo getMethodInfo(ObjectName oname,
0581: String opName) {
0582: String type = null;
0583: MBeanInfo info;
0584: try {
0585: info = server.getMBeanInfo(oname);
0586: } catch (Exception e) {
0587: log.info("Can't find metadata " + oname);
0588: return null;
0589: }
0590: MBeanOperationInfo attInfo[] = info.getOperations();
0591: for (int i = 0; i < attInfo.length; i++) {
0592: if (opName.equals(attInfo[i].getName())) {
0593: return attInfo[i];
0594: }
0595: }
0596: return null;
0597: }
0598:
0599: /** Unregister a component. This is just a helper that
0600: * avoids exceptions by checking if the mbean is already registered
0601: *
0602: * @param oname
0603: */
0604: public void unregisterComponent(ObjectName oname) {
0605: try {
0606: if (getMBeanServer().isRegistered(oname)) {
0607: getMBeanServer().unregisterMBean(oname);
0608: }
0609: } catch (Throwable t) {
0610: log.error("Error unregistering mbean ", t);
0611: }
0612: }
0613:
0614: /**
0615: * Factory method to create (if necessary) and return our
0616: * <code>MBeanServer</code> instance.
0617: *
0618: */
0619: public synchronized MBeanServer getMBeanServer() {
0620: long t1 = System.currentTimeMillis();
0621:
0622: if (server == null) {
0623: if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
0624: server = (MBeanServer) MBeanServerFactory
0625: .findMBeanServer(null).get(0);
0626: if (log.isDebugEnabled()) {
0627: log.debug("Using existing MBeanServer "
0628: + (System.currentTimeMillis() - t1));
0629: }
0630: } else {
0631: server = MBeanServerFactory.createMBeanServer();
0632: if (log.isDebugEnabled()) {
0633: log.debug("Creating MBeanServer"
0634: + (System.currentTimeMillis() - t1));
0635: }
0636: }
0637: }
0638: return (server);
0639: }
0640:
0641: /** Find or load metadata.
0642: */
0643: public ManagedBean findManagedBean(Object bean, Class beanClass,
0644: String type) throws Exception {
0645: if (bean != null && beanClass == null) {
0646: beanClass = bean.getClass();
0647: }
0648:
0649: if (type == null) {
0650: type = beanClass.getName();
0651: }
0652:
0653: // first look for existing descriptor
0654: ManagedBean managed = findManagedBean(type);
0655:
0656: // Search for a descriptor in the same package
0657: if (managed == null) {
0658: // check package and parent packages
0659: if (log.isDebugEnabled()) {
0660: log.debug("Looking for descriptor ");
0661: }
0662: findDescriptor(beanClass, type);
0663:
0664: managed = findManagedBean(type);
0665: }
0666:
0667: if (bean instanceof DynamicMBean) {
0668: if (log.isDebugEnabled()) {
0669: log.debug("Dynamic mbean support ");
0670: }
0671: // Dynamic mbean
0672: loadDescriptors("MbeansDescriptorsDynamicMBeanSource",
0673: bean, type);
0674:
0675: managed = findManagedBean(type);
0676: }
0677:
0678: // Still not found - use introspection
0679: if (managed == null) {
0680: if (log.isDebugEnabled()) {
0681: log.debug("Introspecting ");
0682: }
0683:
0684: // introspection
0685: loadDescriptors("MbeansDescriptorsIntrospectionSource",
0686: beanClass, type);
0687:
0688: managed = findManagedBean(type);
0689: if (managed == null) {
0690: log.warn("No metadata found for " + type);
0691: return null;
0692: }
0693: managed.setName(type);
0694: addManagedBean(managed);
0695: }
0696: return managed;
0697: }
0698:
0699: /** EXPERIMENTAL Convert a string to object, based on type. Used by several
0700: * components. We could provide some pluggability. It is here to keep
0701: * things consistent and avoid duplication in other tasks
0702: *
0703: * @param type Fully qualified class name of the resulting value
0704: * @param value String value to be converted
0705: * @return Converted value
0706: */
0707: public Object convertValue(String type, String value) {
0708: Object objValue = value;
0709:
0710: if (type == null || "java.lang.String".equals(type)) {
0711: // string is default
0712: objValue = value;
0713: } else if ("javax.management.ObjectName".equals(type)
0714: || "ObjectName".equals(type)) {
0715: try {
0716: objValue = new ObjectName(value);
0717: } catch (MalformedObjectNameException e) {
0718: return null;
0719: }
0720: } else if ("java.lang.Integer".equals(type)
0721: || "int".equals(type)) {
0722: objValue = new Integer(value);
0723: } else if ("java.lang.Long".equals(type) || "long".equals(type)) {
0724: objValue = new Long(value);
0725: } else if ("java.lang.Boolean".equals(type)
0726: || "boolean".equals(type)) {
0727: objValue = Boolean.valueOf(value);
0728: }
0729: return objValue;
0730: }
0731:
0732: /** Experimental.
0733: *
0734: * @param sourceType
0735: * @param source
0736: * @param param
0737: * @return List of descriptors
0738: * @throws Exception
0739: * @deprecated bad interface, mixing of metadata and mbeans
0740: */
0741: public List load(String sourceType, Object source, String param)
0742: throws Exception {
0743: if (log.isTraceEnabled()) {
0744: log.trace("load " + source);
0745: }
0746: String location = null;
0747: String type = null;
0748: Object inputsource = null;
0749:
0750: if (source instanceof DynamicMBean) {
0751: sourceType = "MbeansDescriptorsDynamicMBeanSource";
0752: inputsource = source;
0753: } else if (source instanceof URL) {
0754: URL url = (URL) source;
0755: location = url.toString();
0756: type = param;
0757: inputsource = url.openStream();
0758: if (sourceType == null) {
0759: sourceType = sourceTypeFromExt(location);
0760: }
0761: } else if (source instanceof File) {
0762: location = ((File) source).getAbsolutePath();
0763: inputsource = new FileInputStream((File) source);
0764: type = param;
0765: if (sourceType == null) {
0766: sourceType = sourceTypeFromExt(location);
0767: }
0768: } else if (source instanceof InputStream) {
0769: type = param;
0770: inputsource = source;
0771: } else if (source instanceof Class) {
0772: location = ((Class) source).getName();
0773: type = param;
0774: inputsource = source;
0775: if (sourceType == null) {
0776: sourceType = "MbeansDescriptorsIntrospectionSource";
0777: }
0778: }
0779:
0780: if (sourceType == null) {
0781: sourceType = "MbeansDescriptorsDOMSource";
0782: }
0783: ModelerSource ds = getModelerSource(sourceType);
0784: List mbeans = ds.loadDescriptors(this , location, type,
0785: inputsource);
0786:
0787: return mbeans;
0788: }
0789:
0790: private String sourceTypeFromExt(String s) {
0791: if (s.endsWith(".ser")) {
0792: return "MbeansDescriptorsSerSource";
0793: } else if (s.endsWith(".xml")) {
0794: return "MbeansDescriptorsDOMSource";
0795: }
0796: return null;
0797: }
0798:
0799: /** Register a component
0800: * XXX make it private
0801: *
0802: * @param bean
0803: * @param oname
0804: * @param type
0805: * @throws Exception
0806: */
0807: public void registerComponent(Object bean, ObjectName oname,
0808: String type) throws Exception {
0809: if (log.isDebugEnabled()) {
0810: log.debug("Managed= " + oname);
0811: }
0812:
0813: if (bean == null) {
0814: log.error("Null component " + oname);
0815: return;
0816: }
0817:
0818: try {
0819: if (type == null) {
0820: type = bean.getClass().getName();
0821: }
0822:
0823: ManagedBean managed = findManagedBean(bean.getClass(), type);
0824:
0825: // The real mbean is created and registered
0826: ModelMBean mbean = managed.createMBean(bean);
0827:
0828: if (getMBeanServer().isRegistered(oname)) {
0829: if (log.isDebugEnabled()) {
0830: log.debug("Unregistering existing component "
0831: + oname);
0832: }
0833: getMBeanServer().unregisterMBean(oname);
0834: }
0835:
0836: getMBeanServer().registerMBean(mbean, oname);
0837: } catch (Exception ex) {
0838: log.error("Error registering " + oname, ex);
0839: throw ex;
0840: }
0841: }
0842:
0843: /** Lookup the component descriptor in the package and
0844: * in the parent packages.
0845: *
0846: * @param packageName
0847: */
0848: public synchronized void loadDescriptors(String packageName,
0849: ClassLoader classLoader) {
0850: String res = packageName.replace('.', '/');
0851:
0852: if (log.isTraceEnabled()) {
0853: log.trace("Finding descriptor " + res);
0854: }
0855:
0856: if (searchedPaths.get(packageName) != null) {
0857: return;
0858: }
0859: String descriptors = res + "/mbeans-descriptors.ser";
0860:
0861: URL dURL = classLoader.getResource(descriptors);
0862:
0863: if (dURL == null) {
0864: descriptors = res + "/mbeans-descriptors.xml";
0865: dURL = classLoader.getResource(descriptors);
0866: }
0867: if (dURL == null) {
0868: return;
0869: }
0870:
0871: log.debug("Found " + dURL);
0872: searchedPaths.put(packageName, dURL);
0873: try {
0874: if (descriptors.endsWith(".xml"))
0875: loadDescriptors("MbeansDescriptorsDOMSource", dURL,
0876: null);
0877: else
0878: loadDescriptors("MbeansDescriptorsSerSource", dURL,
0879: null);
0880: } catch (Exception ex) {
0881: log.error("Error loading " + dURL);
0882: }
0883: }
0884:
0885: /** Experimental. Will become private, some code may still use it
0886: *
0887: * @param sourceType
0888: * @param source
0889: * @param param
0890: * @throws Exception
0891: * @deprecated
0892: */
0893: public void loadDescriptors(String sourceType, Object source,
0894: String param) throws Exception {
0895: List mbeans = load(sourceType, source, param);
0896: if (mbeans == null)
0897: return;
0898:
0899: Iterator itr = mbeans.iterator();
0900: while (itr.hasNext()) {
0901: Object mb = itr.next();
0902: if (mb instanceof ManagedBean) {
0903: addManagedBean((ManagedBean) mb);
0904: }
0905: }
0906: }
0907:
0908: /** Discover all META-INF/modeler.xml files in classpath and register
0909: * the components
0910: *
0911: * @since EXPERIMENTAL
0912: */
0913: private void loadMetaInfDescriptors(ClassLoader cl) {
0914: try {
0915: Enumeration en = cl.getResources(MODELER_MANIFEST);
0916: while (en.hasMoreElements()) {
0917: URL url = (URL) en.nextElement();
0918: InputStream is = url.openStream();
0919: if (log.isDebugEnabled())
0920: log.debug("Loading " + url);
0921: loadDescriptors("MBeansDescriptorDOMSource", is, null);
0922: }
0923: } catch (Exception ex) {
0924: ex.printStackTrace();
0925: }
0926: }
0927:
0928: /** Lookup the component descriptor in the package and
0929: * in the parent packages.
0930: *
0931: * @param beanClass
0932: * @param type
0933: */
0934: private void findDescriptor(Class beanClass, String type) {
0935: if (type == null) {
0936: type = beanClass.getName();
0937: }
0938: ClassLoader classLoader = null;
0939: if (beanClass != null) {
0940: classLoader = beanClass.getClassLoader();
0941: }
0942: if (classLoader == null) {
0943: classLoader = Thread.currentThread()
0944: .getContextClassLoader();
0945: }
0946: if (classLoader == null) {
0947: classLoader = this .getClass().getClassLoader();
0948: }
0949:
0950: String pkg = type;
0951: while (pkg.indexOf(".") > 0) {
0952: int lastComp = pkg.lastIndexOf(".");
0953: if (lastComp <= 0)
0954: return;
0955: pkg = pkg.substring(0, lastComp);
0956: if (searchedPaths.get(pkg) != null) {
0957: return;
0958: }
0959: loadDescriptors(pkg, classLoader);
0960: }
0961: }
0962:
0963: private ModelerSource getModelerSource(String type)
0964: throws Exception {
0965: if (type == null)
0966: type = "MbeansDescriptorsDOMSource";
0967: if (type.indexOf(".") < 0) {
0968: type = "org.apache.commons.modeler.modules." + type;
0969: }
0970:
0971: Class c = Class.forName(type);
0972: ModelerSource ds = (ModelerSource) c.newInstance();
0973: return ds;
0974: }
0975:
0976: // -------------------- Registration --------------------
0977:
0978: public ObjectName preRegister(MBeanServer server, ObjectName name)
0979: throws Exception {
0980: this .server = server;
0981: return name;
0982: }
0983:
0984: public void postRegister(Boolean registrationDone) {
0985: }
0986:
0987: public void preDeregister() throws Exception {
0988: }
0989:
0990: public void postDeregister() {
0991: }
0992:
0993: // -------------------- DEPRECATED METHODS --------------------
0994: // May still be used in tomcat
0995: // Never part of an official release
0996:
0997: /** Called by a registry or by the container to unload a loader
0998: * @param loader
0999: */
1000: public void unregisterRegistry(ClassLoader loader) {
1001: // XXX Cleanup ?
1002: perLoaderRegistries.remove(loader);
1003: }
1004:
1005: public ManagedBean findManagedBean(Class beanClass, String type)
1006: throws Exception {
1007: return findManagedBean(null, beanClass, type);
1008: }
1009:
1010: /**
1011: * Set the <code>MBeanServer</code> to be utilized for our
1012: * registered management beans.
1013: *
1014: * @param server The new <code>MBeanServer</code> instance
1015: */
1016: public void setMBeanServer(MBeanServer server) {
1017: this .server = server;
1018: }
1019:
1020: public void resetMetadata() {
1021: stop();
1022: }
1023:
1024: /**
1025: * Load the registry from the XML input found in the specified input
1026: * stream.
1027: *
1028: * @param source Source to be used to load. Can be an InputStream or URL.
1029: *
1030: * @exception Exception if any parsing or processing error occurs
1031: */
1032: public void loadDescriptors(Object source) throws Exception {
1033: loadDescriptors("MbeansDescriptorsDOMSource", source, null);
1034: }
1035:
1036: /** @deprecated - may still be used in code using pre-1.1 builds
1037: */
1038: public void registerComponent(Object bean, String domain,
1039: String type, String name) throws Exception {
1040: StringBuffer sb = new StringBuffer();
1041: sb.append(domain).append(":");
1042: sb.append(name);
1043: String nameStr = sb.toString();
1044: ObjectName oname = new ObjectName(nameStr);
1045: registerComponent(bean, oname, type);
1046: }
1047:
1048: // should be removed
1049: public void unregisterComponent(String domain, String name) {
1050: try {
1051: ObjectName oname = new ObjectName(domain + ":" + name);
1052:
1053: // XXX remove from our tables.
1054: getMBeanServer().unregisterMBean(oname);
1055: } catch (Throwable t) {
1056: log.error("Error unregistering mbean ", t);
1057: }
1058: }
1059:
1060: public List loadMBeans(Object source) throws Exception {
1061: return loadMBeans(source, null);
1062: }
1063:
1064: /**
1065: * Load the registry from a cached .ser file. This is typically 2-3 times
1066: * faster than parsing the XML.
1067: *
1068: * @param source Source to be used to load. Can be an InputStream or URL.
1069: *
1070: * @exception Exception if any parsing or processing error occurs
1071: * @deprecated Loaded automatically or using a File or Url ending in .ser
1072: */
1073: public void loadCachedDescriptors(Object source) throws Exception {
1074: loadDescriptors("MbeansDescriptorsSerSource", source, null);
1075: }
1076: }
|