1. /*
  2. * @(#)MLet.java 1.84 04/03/26
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.management.loading;
  8. // Java import
  9. import java.io.Externalizable;
  10. import java.io.File;
  11. import java.io.FileOutputStream;
  12. import java.io.InputStream;
  13. import java.io.IOException;
  14. import java.io.ObjectInput;
  15. import java.io.ObjectInputStream;
  16. import java.io.ObjectOutput;
  17. import java.lang.reflect.Constructor;
  18. import java.net.MalformedURLException;
  19. import java.net.URL;
  20. import java.net.URLClassLoader;
  21. import java.net.URLStreamHandlerFactory;
  22. import java.security.AccessController;
  23. import java.security.PrivilegedAction;
  24. import java.util.Arrays;
  25. import java.util.Enumeration;
  26. import java.util.HashSet;
  27. import java.util.Hashtable;
  28. import java.util.Iterator;
  29. import java.util.Map;
  30. import java.util.Set;
  31. import java.util.StringTokenizer;
  32. import java.util.Vector;
  33. import javax.management.ServiceNotFoundException;
  34. import javax.management.ObjectInstance;
  35. import javax.management.ObjectName;
  36. import javax.management.MBeanServer;
  37. import javax.management.ReflectionException;
  38. import javax.management.InstanceAlreadyExistsException;
  39. import javax.management.MBeanRegistrationException;
  40. import javax.management.MBeanException;
  41. import javax.management.NotCompliantMBeanException;
  42. import javax.management.InstanceNotFoundException;
  43. import javax.management.MBeanRegistration;
  44. import javax.management.MBeanServerFactory;
  45. import javax.management.loading.ClassLoaderRepository;
  46. import com.sun.jmx.mbeanserver.GetPropertyAction;
  47. import com.sun.jmx.defaults.ServiceName;
  48. import com.sun.jmx.defaults.JmxProperties;
  49. import com.sun.jmx.trace.Trace;
  50. /**
  51. * Allows you to instantiate and register one or several MBeans in the MBean server
  52. * coming from a remote URL. M-let is a shortcut for management applet. The m-let service does this
  53. * by loading an m-let text file, which specifies information on the MBeans to be obtained.
  54. * The information on each MBean is specified in a single instance of a tag, called the MLET tag.
  55. * The location of the m-let text file is specified by a URL.
  56. * <p>
  57. * The <CODE>MLET</CODE> tag has the following syntax:
  58. * <p>
  59. * <<CODE>MLET</CODE><BR>
  60. * <CODE>CODE = </CODE><VAR>class</VAR><CODE> | OBJECT = </CODE><VAR>serfile</VAR><BR>
  61. * <CODE>ARCHIVE = "</CODE><VAR>archiveList</VAR><CODE>"</CODE><BR>
  62. * <CODE>[CODEBASE = </CODE><VAR>codebaseURL</VAR><CODE>]</CODE><BR>
  63. * <CODE>[NAME = </CODE><VAR>mbeanname</VAR><CODE>]</CODE><BR>
  64. * <CODE>[VERSION = </CODE><VAR>version</VAR><CODE>]</CODE><BR>
  65. * ><BR>
  66. * <CODE>[</CODE><VAR>arglist</VAR><CODE>]</CODE><BR>
  67. * <<CODE>/MLET</CODE>>
  68. * <p>
  69. * where:
  70. * <DL>
  71. * <DT><CODE>CODE = </CODE><VAR>class</VAR></DT>
  72. * <DD>
  73. * This attribute specifies the full Java class name, including package name, of the MBean to be obtained.
  74. * The compiled <CODE>.class</CODE> file of the MBean must be contained in one of the <CODE>.jar</CODE> files specified by the <CODE>ARCHIVE</CODE>
  75. * attribute. Either <CODE>CODE</CODE> or <CODE>OBJECT</CODE> must be present.
  76. * </DD>
  77. * <DT><CODE>OBJECT = </CODE><VAR>serfile</VAR></DT>
  78. * <DD>
  79. * This attribute specifies the <CODE>.ser</CODE> file that contains a serialized representation of the MBean to be obtained.
  80. * This file must be contained in one of the <CODE>.jar</CODE> files specified by the <CODE>ARCHIVE</CODE> attribute. If the <CODE>.jar</CODE> file contains a directory hierarchy, specify the path of the file within this hierarchy. Otherwise a match will not be found. Either <CODE>CODE</CODE> or <CODE>OBJECT</CODE> must be present.
  81. * </DD>
  82. * <DT><CODE>ARCHIVE = "</CODE><VAR>archiveList</VAR><CODE>"</CODE></DT>
  83. * <DD>
  84. * This mandatory attribute specifies one or more <CODE>.jar</CODE> files
  85. * containing MBeans or other resources used by
  86. * the MBean to be obtained. One of the <CODE>.jar</CODE> files must contain the file specified by the <CODE>CODE</CODE> or <CODE>OBJECT</CODE> attribute.
  87. * If archivelist contains more than one file:
  88. * <UL>
  89. * <LI>Each file must be separated from the one that follows it by a comma (,).
  90. * <LI><VAR>archivelist</VAR> must be enclosed in double quote marks.
  91. * </UL>
  92. * All <CODE>.jar</CODE> files in <VAR>archivelist</VAR> must be stored in the directory specified by the code base URL.
  93. * </DD>
  94. * <DT><CODE>CODEBASE = </CODE><VAR>codebaseURL</VAR></DT>
  95. * <DD>
  96. * This optional attribute specifies the code base URL of the MBean to be obtained. It identifies the directory that contains
  97. * the <CODE>.jar</CODE> files specified by the <CODE>ARCHIVE</CODE> attribute. Specify this attribute only if the <CODE>.jar</CODE> files are not in the same
  98. * directory as the m-let text file. If this attribute is not specified, the base URL of the m-let text file is used.
  99. * </DD>
  100. * <DT><CODE>NAME = </CODE><VAR>mbeanname</VAR></DT>
  101. * <DD>
  102. * This optional attribute specifies the object name to be assigned to the
  103. * MBean instance when the m-let service registers it. If
  104. * <VAR>mbeanname</VAR> starts with the colon character (:), the domain
  105. * part of the object name is the domain of the agent. The m-let service
  106. * invokes the <CODE>getDomain()</CODE> method of the Framework class to
  107. * obtain this information.
  108. * </DD>
  109. * <DT><CODE>VERSION = </CODE><VAR>version</VAR></DT>
  110. * <DD>
  111. * This optional attribute specifies the version number of the MBean and
  112. * associated <CODE>.jar</CODE> files to be obtained. This version number can
  113. * be used to specify that the <CODE>.jar</CODE> files are loaded from the
  114. * server to update those stored locally in the cache the next time the m-let
  115. * text file is loaded. <VAR>version</VAR> must be a series of non-negative
  116. * decimal integers each separated by a period from the one that precedes it.
  117. * </DD>
  118. * <DT><VAR>arglist</VAR></DT>
  119. * <DD>
  120. * This optional attribute specifies a list of one or more parameters for the
  121. * MBean to be instantiated. This list describes the parameters to be passed the MBean's constructor.
  122. * Use the following syntax to specify each item in
  123. * <VAR>arglist</VAR>:</DD>
  124. * <DL>
  125. * <P>
  126. * <DT><<CODE>ARG TYPE=</CODE><VAR>argumentType</VAR> <CODE>VALUE=</CODE><VAR>value</VAR>></DT>
  127. * <P>
  128. * <DD>where:</DD>
  129. * <UL>
  130. * <LI><VAR>argumentType</VAR> is the type of the argument that will be passed as parameter to the MBean's constructor.</UL>
  131. * </DL>
  132. * <P>The arguments' type in the argument list should be a Java primitive type or a Java basic type
  133. * (<CODE>java.lang.Boolean, java.lang.Byte, java.lang.Short, java.lang.Long, java.lang.Integer, java.lang.Float, java.lang.Double, java.lang.String</CODE>).
  134. * </DL>
  135. *
  136. * When an m-let text file is loaded, an
  137. * instance of each MBean specified in the file is created and registered.
  138. * <P>
  139. * The m-let Service extends the <CODE>java.net.URLClassLoader</CODE> and can be used to load remote classes
  140. * and jar files in the VM of the agent.
  141. * <p><STRONG>Note - </STRONG> The <CODE>MLet</CODE> class loader uses the {@link javax.management.MBeanServerFactory#getClassLoaderRepository(javax.management.MBeanServer)}
  142. * to load classes that could not be found in the loaded jar files.
  143. *
  144. * @since 1.5
  145. */
  146. public class MLet extends java.net.URLClassLoader
  147. implements MLetMBean, MBeanRegistration, Externalizable {
  148. private static final long serialVersionUID = 3636148327800330130L;
  149. /*
  150. * ------------------------------------------
  151. * PRIVATE VARIABLES
  152. * ------------------------------------------
  153. */
  154. /**
  155. * The reference to the MBean server.
  156. * @serial
  157. */
  158. private MBeanServer server = null;
  159. /**
  160. * The list of instances of the <CODE>MLetContant</CODE>
  161. * class found at the specified URL.
  162. * @serial
  163. */
  164. private Vector mletList = new Vector();
  165. /**
  166. * The directory used for storing libraries locally before they are loaded.
  167. */
  168. private String libraryDirectory;
  169. /**
  170. * The object name of the MLet Service.
  171. * @serial
  172. */
  173. private ObjectName mletObjectName = null;
  174. /**
  175. * The URLs of the MLet Service.
  176. * @serial
  177. */
  178. private URL[] myUrls = null;
  179. /**
  180. * The name of this class to be used for trace messages
  181. */
  182. private static final String dbgTag = "MLet";
  183. /**
  184. * What ClassLoaderRepository, if any, to use if this MLet
  185. * doesn't find an asked-for class.
  186. */
  187. private transient ClassLoaderRepository currentClr;
  188. /**
  189. * True if we should consult the {@link ClassLoaderRepository}
  190. * when we do not find a class ourselves.
  191. */
  192. private transient boolean delegateToCLR;
  193. /**
  194. * objects maps from primitive classes to primitive object classes.
  195. */
  196. private Hashtable primitiveClasses = new Hashtable(8) ;
  197. {
  198. primitiveClasses.put(Boolean.TYPE.toString(), Boolean.class);
  199. primitiveClasses.put(Character.TYPE.toString(), Character.class);
  200. primitiveClasses.put(Byte.TYPE.toString(), Byte.class);
  201. primitiveClasses.put(Short.TYPE.toString(), Short.class);
  202. primitiveClasses.put(Integer.TYPE.toString(), Integer.class);
  203. primitiveClasses.put(Long.TYPE.toString(), Long.class);
  204. primitiveClasses.put(Float.TYPE.toString(), Float.class);
  205. primitiveClasses.put(Double.TYPE.toString(), Double.class);
  206. }
  207. /*
  208. * ------------------------------------------
  209. * CONSTRUCTORS
  210. * ------------------------------------------
  211. */
  212. /*
  213. * The constructor stuff would be considerably simplified if our
  214. * parent, URLClassLoader, specified that its one- and
  215. * two-argument constructors were equivalent to its
  216. * three-argument constructor with trailing null arguments. But
  217. * it doesn't, which prevents us from having all the constructors
  218. * but one call this(...args...).
  219. */
  220. /**
  221. * Constructs a new MLet using the default delegation parent ClassLoader.
  222. */
  223. public MLet() {
  224. this(new URL[0]);
  225. }
  226. /**
  227. * Constructs a new MLet for the specified URLs using the default
  228. * delegation parent ClassLoader. The URLs will be searched in
  229. * the order specified for classes and resources after first
  230. * searching in the parent class loader.
  231. *
  232. * @param urls The URLs from which to load classes and resources.
  233. *
  234. */
  235. public MLet(URL[] urls) {
  236. this(urls, true);
  237. }
  238. /**
  239. * Constructs a new MLet for the given URLs. The URLs will be
  240. * searched in the order specified for classes and resources
  241. * after first searching in the specified parent class loader.
  242. * The parent argument will be used as the parent class loader
  243. * for delegation.
  244. *
  245. * @param urls The URLs from which to load classes and resources.
  246. * @param parent The parent class loader for delegation.
  247. *
  248. */
  249. public MLet(URL[] urls, ClassLoader parent) {
  250. this(urls, parent, true);
  251. }
  252. /**
  253. * Constructs a new MLet for the specified URLs, parent class
  254. * loader, and URLStreamHandlerFactory. The parent argument will
  255. * be used as the parent class loader for delegation. The factory
  256. * argument will be used as the stream handler factory to obtain
  257. * protocol handlers when creating new URLs.
  258. *
  259. * @param urls The URLs from which to load classes and resources.
  260. * @param parent The parent class loader for delegation.
  261. * @param factory The URLStreamHandlerFactory to use when creating URLs.
  262. *
  263. */
  264. public MLet(URL[] urls,
  265. ClassLoader parent,
  266. URLStreamHandlerFactory factory) {
  267. this(urls, parent, factory, true);
  268. }
  269. /**
  270. * Constructs a new MLet for the specified URLs using the default
  271. * delegation parent ClassLoader. The URLs will be searched in
  272. * the order specified for classes and resources after first
  273. * searching in the parent class loader.
  274. *
  275. * @param urls The URLs from which to load classes and resources.
  276. * @param delegateToCLR True if, when a class is not found in
  277. * either the parent ClassLoader or the URLs, the MLet should delegate
  278. * to its containing MBeanServer's {@link ClassLoaderRepository}.
  279. *
  280. * @since.unbundled JMX 1.2
  281. */
  282. public MLet(URL[] urls, boolean delegateToCLR) {
  283. super(urls);
  284. init(delegateToCLR);
  285. }
  286. /**
  287. * Constructs a new MLet for the given URLs. The URLs will be
  288. * searched in the order specified for classes and resources
  289. * after first searching in the specified parent class loader.
  290. * The parent argument will be used as the parent class loader
  291. * for delegation.
  292. *
  293. * @param urls The URLs from which to load classes and resources.
  294. * @param parent The parent class loader for delegation.
  295. * @param delegateToCLR True if, when a class is not found in
  296. * either the parent ClassLoader or the URLs, the MLet should delegate
  297. * to its containing MBeanServer's {@link ClassLoaderRepository}.
  298. *
  299. * @since.unbundled JMX 1.2
  300. */
  301. public MLet(URL[] urls, ClassLoader parent, boolean delegateToCLR) {
  302. super(urls, parent);
  303. init(delegateToCLR);
  304. }
  305. /**
  306. * Constructs a new MLet for the specified URLs, parent class
  307. * loader, and URLStreamHandlerFactory. The parent argument will
  308. * be used as the parent class loader for delegation. The factory
  309. * argument will be used as the stream handler factory to obtain
  310. * protocol handlers when creating new URLs.
  311. *
  312. * @param urls The URLs from which to load classes and resources.
  313. * @param parent The parent class loader for delegation.
  314. * @param factory The URLStreamHandlerFactory to use when creating URLs.
  315. * @param delegateToCLR True if, when a class is not found in
  316. * either the parent ClassLoader or the URLs, the MLet should delegate
  317. * to its containing MBeanServer's {@link ClassLoaderRepository}.
  318. *
  319. * @since.unbundled JMX 1.2
  320. */
  321. public MLet(URL[] urls,
  322. ClassLoader parent,
  323. URLStreamHandlerFactory factory,
  324. boolean delegateToCLR) {
  325. super(urls, parent, factory);
  326. init(delegateToCLR);
  327. }
  328. private void init(boolean delegateToCLR) {
  329. this.delegateToCLR = delegateToCLR;
  330. try {
  331. libraryDirectory = System.getProperty(JmxProperties.MLET_LIB_DIR);
  332. if (libraryDirectory == null)
  333. libraryDirectory = getTmpDir();
  334. } catch (SecurityException e) {
  335. // OK : We don't do AccessController.doPrivileged, but we don't
  336. // stop the user from creating an MLet just because they
  337. // can't read the MLET_LIB_DIR or java.io.tmpdir properties
  338. // either.
  339. }
  340. }
  341. /*
  342. * ------------------------------------------
  343. * PUBLIC METHODS
  344. * ------------------------------------------
  345. */
  346. /**
  347. * Appends the specified URL to the list of URLs to search for classes and
  348. * resources.
  349. */
  350. public void addURL(URL url) {
  351. if (!Arrays.asList(getURLs()).contains(url))
  352. super.addURL(url);
  353. }
  354. /**
  355. * Appends the specified URL to the list of URLs to search for classes and
  356. * resources.
  357. * @exception ServiceNotFoundException The specified URL is malformed.
  358. */
  359. public void addURL(String url) throws ServiceNotFoundException {
  360. try {
  361. URL ur = new URL(url);
  362. if (!Arrays.asList(getURLs()).contains(ur))
  363. super.addURL(ur);
  364. } catch (MalformedURLException e) {
  365. debug("addURL", url + ": Malformed URL. " + e);
  366. throw new
  367. ServiceNotFoundException("The specified URL is malformed");
  368. }
  369. }
  370. /** Returns the search path of URLs for loading classes and resources.
  371. * This includes the original list of URLs specified to the constructor,
  372. * along with any URLs subsequently appended by the addURL() method.
  373. */
  374. public URL[] getURLs() {
  375. return super.getURLs();
  376. }
  377. /**
  378. * Loads a text file containing MLET tags that define the MBeans to
  379. * be added to the agent. The location of the text file is specified by
  380. * a URL. The MBeans specified in the MLET file will be instantiated and
  381. * registered by the MBean server.
  382. *
  383. * @param url The URL of the text file to be loaded as URL object.
  384. *
  385. * @return A set containing one entry per MLET tag in the m-let text file loaded.
  386. * Each entry specifies either the ObjectInstance for the created MBean, or a throwable object
  387. * (that is, an error or an exception) if the MBean could not be created.
  388. *
  389. * @exception ServiceNotFoundException One of the following errors has occurred: The m-let text file does
  390. * not contain an MLET tag, the m-let text file is not found, a mandatory
  391. * attribute of the MLET tag is not specified, the value of url is
  392. * null.
  393. * @exception IllegalStateException MLet MBean is not registered with an MBeanServer.
  394. */
  395. public Set getMBeansFromURL(URL url) throws ServiceNotFoundException {
  396. if (url == null) {
  397. throw new ServiceNotFoundException("The specified URL is null");
  398. }
  399. return getMBeansFromURL(url.toString());
  400. }
  401. /**
  402. * Loads a text file containing MLET tags that define the MBeans to
  403. * be added to the agent. The location of the text file is specified by
  404. * a URL. The MBeans specified in the MLET file will be instantiated and
  405. * registered by the MBean server.
  406. *
  407. * @param url The URL of the text file to be loaded as String object.
  408. *
  409. * @return A set containing one entry per MLET tag in the m-let text file loaded.
  410. * Each entry specifies either the ObjectInstance for the created MBean, or a throwable object
  411. * (that is, an error or an exception) if the MBean could not be created.
  412. *
  413. * @exception ServiceNotFoundException One of the following errors has occurred: The m-let text file does
  414. * not contain an MLET tag, the m-let text file is not found, a mandatory
  415. * attribute of the MLET tag is not specified, the url is malformed.
  416. * @exception IllegalStateException MLet MBean is not registered with an MBeanServer.
  417. *
  418. */
  419. public Set getMBeansFromURL(String url) throws ServiceNotFoundException {
  420. String mth = "getMBeansFromURL";
  421. if (server == null) {
  422. throw new IllegalStateException("This MLet MBean is not registered with an MBeanServer.");
  423. }
  424. // Parse arguments
  425. if (url == null) {
  426. if (isTraceOn()) {
  427. trace(mth, "URL is null");
  428. }
  429. throw new ServiceNotFoundException("The specified URL is null");
  430. } else {
  431. url = url.replace(File.separatorChar,'/');
  432. }
  433. if (isTraceOn()) {
  434. trace(mth, "<URL = " + url + ">");
  435. }
  436. // Parse URL
  437. try {
  438. MLetParser parser = new MLetParser();
  439. mletList = parser.parseURL(url);
  440. } catch (Exception e) {
  441. final String msg =
  442. "Problems while parsing URL [" + url +
  443. "], got exception [" + e.toString() + "]";
  444. if (isTraceOn()) {
  445. trace(mth, msg);
  446. }
  447. ServiceNotFoundException snfe = new ServiceNotFoundException(msg);
  448. /* Make a best effort to set the cause, but if we don't
  449. succeed, too bad, you don't get that useful debugging
  450. information. We jump through hoops here so that we can
  451. work on platforms prior to J2SE 1.4 where the
  452. Throwable.initCause method was introduced. If we change
  453. the public interface of JMRuntimeException in a future
  454. version we can add getCause() so we don't need to do this. */
  455. try {
  456. java.lang.reflect.Method initCause =
  457. Throwable.class.getMethod("initCause",
  458. new Class[] {Throwable.class});
  459. initCause.invoke(snfe, new Object[] {e});
  460. } catch (Exception x) {
  461. // OK: just means we won't have debugging info
  462. }
  463. throw snfe;
  464. }
  465. // Check that the list of MLets is not empty
  466. if (mletList.size() == 0) {
  467. if (isTraceOn()) {
  468. trace(mth, "File " + url + " not found or MLET tag not defined in file");
  469. }
  470. throw new ServiceNotFoundException("File " + url + " not found or MLET tag not defined in file");
  471. }
  472. // Walk through the list of MLets
  473. HashSet mbeans = new HashSet();
  474. for(Enumeration e = mletList.elements(); e.hasMoreElements(); ) {
  475. // Get MLet item from list
  476. MLetContent elmt = (MLetContent) e.nextElement();
  477. // Initialise local variables
  478. String code = elmt.getCode();
  479. if (code != null) {
  480. if (code.endsWith(".class")) {
  481. code = code.substring(0, code.length() - 6);
  482. }
  483. }
  484. String name = elmt.getName();
  485. URL codebase = elmt.getCodeBase();
  486. String version = elmt.getVersion();
  487. String serName = elmt.getSerializedObject();
  488. String jarFiles = elmt.getJarFiles();
  489. URL documentBase = elmt.getDocumentBase();
  490. Map attributes = elmt.getAttributes();
  491. // Display debug information
  492. if (isTraceOn()) {
  493. trace(mth, "MLET TAG = " + attributes.toString());
  494. trace(mth, "CODEBASE = " + codebase);
  495. trace(mth, "ARCHIVE = " + jarFiles);
  496. trace(mth, "CODE = " + code);
  497. trace(mth, "OBJECT = " + serName);
  498. trace(mth, "NAME = " + name);
  499. trace(mth, "VERSION = " + version);
  500. trace(mth, "DOCUMENT URL = " + documentBase);
  501. }
  502. // Load classes from JAR files
  503. StringTokenizer st = new StringTokenizer(jarFiles, ",", false);
  504. while (st.hasMoreTokens()) {
  505. String tok = st.nextToken().trim();
  506. if (isTraceOn()) {
  507. trace(mth, "Load archive for codebase <" + codebase + ">, file <" + tok + ">");
  508. }
  509. // Check which is the codebase to be used for loading the jar file.
  510. // If we are using the base MLet implementation then it will be
  511. // always the remote server but if the service has been extended in
  512. // order to support caching and versioning then this method will
  513. // return the appropriate one.
  514. //
  515. try {
  516. codebase = check(version, codebase, tok, elmt);
  517. } catch (Exception ex) {
  518. if (isDebugOn()) {
  519. debug(mth, "check returned exception: " + ex);
  520. }
  521. mbeans.add(ex);
  522. continue;
  523. }
  524. // Appends the specified JAR file URL to the list of URLs to search for classes and resources.
  525. try {
  526. if (!Arrays.asList(getURLs()).contains(new URL(codebase.toString() + tok))) {
  527. addURL(codebase + tok);
  528. }
  529. } catch (MalformedURLException me) {
  530. // OK : Ignore jar file if its name provokes the URL to be an invalid one.
  531. }
  532. }
  533. // Instantiate the class specified in the
  534. // CODE or OBJECT section of the MLet tag
  535. //
  536. Object o = null;
  537. ObjectInstance objInst = null;
  538. if (code != null && serName != null) {
  539. if (isTraceOn()) {
  540. trace(mth, "CODE and OBJECT parameters cannot be specified at the same time in tag MLET.");
  541. }
  542. mbeans.add(new Error("CODE and OBJECT parameters cannot be specified at the same time in tag MLET"));
  543. continue;
  544. }
  545. if (code == null && serName == null) {
  546. if (isTraceOn()) {
  547. trace(mth, "Either CODE or OBJECT parameter must be specified in tag MLET.");
  548. }
  549. mbeans.add(new Error("Either CODE or OBJECT parameter must be specified in tag MLET"));
  550. continue;
  551. }
  552. try {
  553. if (code != null) {
  554. Vector signat = new Vector();
  555. Vector pars = new Vector();
  556. for (Iterator p = attributes.keySet().iterator(); p.hasNext(); ) {
  557. String param_name = (String) p.next();
  558. if (param_name.equals("types")) {
  559. signat = (Vector)elmt.getParameter(param_name);
  560. }
  561. if (param_name.equals("values")) {
  562. pars = (Vector)elmt.getParameter(param_name);
  563. }
  564. }
  565. for (int i = 0; i < signat.size(); i++) {
  566. pars.setElementAt(constructParameter((String)pars.elementAt(i), (String)signat.elementAt(i)), i);
  567. }
  568. if (signat.isEmpty()) {
  569. if (name == null) {
  570. objInst = server.createMBean(code, null, mletObjectName);
  571. } else {
  572. objInst = server.createMBean(code, new ObjectName(name), mletObjectName);
  573. }
  574. } else {
  575. Object[] parms = pars.toArray();
  576. String[] signature = new String[signat.size()];
  577. for (int i=0;i<signature.length;i++) {
  578. signature[i] = (String) signat.elementAt(i);
  579. }
  580. if (isDebugOn()) {
  581. for (int i=0;i<signature.length;i++) {
  582. debug(mth, "Signature = " + signature[i]);
  583. debug(mth, "Params = " + parms[i].toString());
  584. }
  585. }
  586. if (name == null) {
  587. objInst = server.createMBean(code, null, mletObjectName, parms, signature);
  588. } else {
  589. objInst = server.createMBean(code, new ObjectName(name), mletObjectName, parms, signature);
  590. }
  591. }
  592. } else {
  593. o = loadSerializedObject(codebase,serName);
  594. if (name == null) {
  595. server.registerMBean(o, null);
  596. } else {
  597. server.registerMBean(o, new ObjectName(name));
  598. }
  599. objInst = new ObjectInstance(name, o.getClass().getName());
  600. }
  601. } catch (ReflectionException ex) {
  602. if (isTraceOn()) {
  603. trace(mth, "ReflectionException: " + ex.getMessage());
  604. }
  605. mbeans.add(ex);
  606. continue;
  607. } catch (InstanceAlreadyExistsException ex) {
  608. if (isTraceOn()) {
  609. trace(mth, "InstanceAlreadyExistsException: " + ex.getMessage());
  610. }
  611. mbeans.add(ex);
  612. continue;
  613. } catch (MBeanRegistrationException ex) {
  614. if (isTraceOn()) {
  615. trace(mth, "MBeanRegistrationException: " + ex.getMessage());
  616. }
  617. mbeans.add(ex);
  618. continue;
  619. } catch (MBeanException ex) {
  620. if (isTraceOn()) {
  621. trace(mth, "MBeanException: " + ex.getMessage());
  622. }
  623. mbeans.add(ex);
  624. continue;
  625. } catch (NotCompliantMBeanException ex) {
  626. if (isTraceOn()) {
  627. trace(mth, "NotCompliantMBeanException: " + ex.getMessage());
  628. }
  629. mbeans.add(ex);
  630. continue;
  631. } catch (InstanceNotFoundException ex) {
  632. if (isTraceOn()) {
  633. trace(mth, "InstanceNotFoundException: " + ex.getMessage());
  634. }
  635. mbeans.add(ex);
  636. continue;
  637. } catch (IOException ex) {
  638. if (isTraceOn()) {
  639. trace(mth, "IOException: " + ex.getMessage());
  640. }
  641. mbeans.add(ex);
  642. continue;
  643. } catch (SecurityException ex) {
  644. if (isTraceOn()) {
  645. trace(mth, "SecurityException: " + ex.getMessage());
  646. }
  647. mbeans.add(ex);
  648. continue;
  649. } catch (Exception ex) {
  650. if (isTraceOn()) {
  651. trace(mth, "Exception: " + ex.getClass().getName() + ex.getMessage());
  652. }
  653. mbeans.add(ex);
  654. continue;
  655. } catch (Error ex) {
  656. if (isTraceOn()) {
  657. trace(mth, "Error: " + ex.getMessage());
  658. }
  659. mbeans.add(ex);
  660. continue;
  661. }
  662. mbeans.add(objInst);
  663. }
  664. return mbeans;
  665. }
  666. /**
  667. * Gets the current directory used by the library loader for
  668. * storing native libraries before they are loaded into memory.
  669. *
  670. * @return The current directory used by the library loader.
  671. *
  672. * @see #setLibraryDirectory
  673. */
  674. public String getLibraryDirectory() {
  675. return libraryDirectory;
  676. }
  677. /**
  678. * Sets the directory used by the library loader for storing
  679. * native libraries before they are loaded into memory.
  680. *
  681. * @param libdir The directory used by the library loader.
  682. *
  683. * @see #getLibraryDirectory
  684. */
  685. public void setLibraryDirectory(String libdir) {
  686. libraryDirectory = libdir;
  687. }
  688. /**
  689. * Allows the m-let to perform any operations it needs before
  690. * being registered in the MBean server. If the ObjectName is
  691. * null, the m-let provides a default name for its registration
  692. * <defaultDomain>:type=MLet
  693. *
  694. * @param server The MBean server in which the m-let will be registered.
  695. * @param name The object name of the m-let.
  696. *
  697. * @return The name of the m-let registered.
  698. *
  699. * @exception java.lang.Exception This exception should be caught by the MBean server and re-thrown
  700. *as an MBeanRegistrationException.
  701. */
  702. public ObjectName preRegister(MBeanServer server, ObjectName name) throws java.lang.Exception {
  703. // Initialise local pointer to the MBean server
  704. setMBeanServer(server);
  705. // If no name is specified return a default name for the MLet
  706. if (name == null) {
  707. name = new ObjectName(server.getDefaultDomain() + ":" + ServiceName.MLET);
  708. }
  709. this.mletObjectName = name;
  710. return this.mletObjectName;
  711. }
  712. /**
  713. * Allows the m-let to perform any operations needed after having been
  714. * registered in the MBean server or after the registration has failed.
  715. *
  716. * @param registrationDone Indicates whether or not the m-let has been successfully registered in
  717. * the MBean server. The value false means that either the registration phase
  718. * has failed.
  719. *
  720. */
  721. public void postRegister (Boolean registrationDone) {
  722. }
  723. /**
  724. * Allows the m-let to perform any operations it needs before being unregistered
  725. * by the MBean server.
  726. *
  727. * @exception java.langException This exception should be caught by the MBean server and re-thrown
  728. * as an MBeanRegistrationException.
  729. */
  730. public void preDeregister() throws java.lang.Exception {
  731. }
  732. /**
  733. * Allows the m-let to perform any operations needed after having been
  734. * unregistered in the MBean server.
  735. */
  736. public void postDeregister() {
  737. }
  738. /**
  739. * <p>Save this MLet's contents to the given {@link ObjectOutput}.
  740. * Not all implementations support this method. Those that do not
  741. * throw {@link UnsupportedOperationException}. A subclass may
  742. * override this method to support it or to change the format of
  743. * the written data.</p>
  744. *
  745. * <p>The format of the written data is not specified, but if
  746. * an implementation supports {@link #writeExternal} it must
  747. * also support {@link #readExternal} in such a way that what is
  748. * written by the former can be read by the latter.</p>
  749. *
  750. * @param out The object output stream to write to.
  751. *
  752. * @exception IOException If a problem occurred while writing.
  753. * @exception UnsupportedOperationException If this
  754. * implementation does not support this operation.
  755. */
  756. public void writeExternal(ObjectOutput out)
  757. throws IOException, UnsupportedOperationException {
  758. throw new UnsupportedOperationException("MLet.writeExternal");
  759. }
  760. /**
  761. * <p>Restore this MLet's contents from the given {@link ObjectInput}.
  762. * Not all implementations support this method. Those that do not
  763. * throw {@link UnsupportedOperationException}. A subclass may
  764. * override this method to support it or to change the format of
  765. * the read data.</p>
  766. *
  767. * <p>The format of the read data is not specified, but if an
  768. * implementation supports {@link #readExternal} it must also
  769. * support {@link #writeExternal} in such a way that what is
  770. * written by the latter can be read by the former.</p>
  771. *
  772. * @param in The object input stream to read from.
  773. *
  774. * @exception IOException if a problem occurred while reading.
  775. * @exception ClassNotFoundException if the class for the object
  776. * being restored cannot be found.
  777. * @exception UnsupportedOperationException if this
  778. * implementation does not support this operation.
  779. */
  780. public void readExternal(ObjectInput in)
  781. throws IOException, ClassNotFoundException,
  782. UnsupportedOperationException {
  783. throw new UnsupportedOperationException("MLet.readExternal");
  784. }
  785. /*
  786. * ------------------------------------------
  787. * PACKAGE METHODS
  788. * ------------------------------------------
  789. */
  790. /**
  791. * <p>Load a class, using the given {@link ClassLoaderRepository} if
  792. * the class is not found in this MLet's URLs. The given
  793. * ClassLoaderRepository can be null, in which case a {@link
  794. * ClassNotFoundException} occurs immediately if the class is not
  795. * found in this MLet's URLs.</p>
  796. *
  797. * @param name The name of the class we want to load.
  798. * @param clr The ClassLoaderRepository that will be used to search
  799. * for the given class, if it is not found in this
  800. * ClassLoader. May be null.
  801. * @return The resulting Class object.
  802. * @exception ClassNotFoundException The specified class could not be
  803. * found in this ClassLoader nor in the given
  804. * ClassLoaderRepository.
  805. *
  806. * @since.unbundled JMX 1.1
  807. */
  808. public synchronized Class loadClass(String name,
  809. ClassLoaderRepository clr)
  810. throws ClassNotFoundException {
  811. final ClassLoaderRepository before=currentClr;
  812. try {
  813. currentClr = clr;
  814. final Class c = loadClass(name);
  815. return c;
  816. } finally {
  817. currentClr = before;
  818. }
  819. }
  820. /*
  821. * ------------------------------------------
  822. * PROTECTED METHODS
  823. * ------------------------------------------
  824. */
  825. /**
  826. * This is the main method for class loaders that is being redefined.
  827. *
  828. * @param name The name of the class.
  829. *
  830. * @return The resulting Class object.
  831. *
  832. * @exception ClassNotFoundException The specified class could not be
  833. * found.
  834. */
  835. protected Class findClass(String name) throws ClassNotFoundException {
  836. /* currentClr is context sensitive - used to avoid recursion
  837. in the class loader repository. (This is no longer
  838. necessary with the new CLR semantics but is kept for
  839. compatibility with code that might have called the
  840. two-parameter loadClass explicitly.) */
  841. return findClass(name, currentClr);
  842. }
  843. /**
  844. * Called by {@link MLet#findClass(java.lang.String)}.
  845. *
  846. * @param name The name of the class that we want to load/find.
  847. * @param clr The ClassLoaderRepository that can be used to search
  848. * for the given class. This parameter is
  849. * <code>null</code> when called from within the
  850. * {@link javax.management.MBeanServerFactory#getClassLoaderRepository(javax.management.MBeanServer) Class Loader Repository}.
  851. * @exception ClassNotFoundException The specified class could not be
  852. * found.
  853. *
  854. **/
  855. Class findClass(String name, ClassLoaderRepository clr)
  856. throws ClassNotFoundException {
  857. Class c = null;
  858. if (isTraceOn()) {
  859. trace("findClass", name);
  860. }
  861. // Try looking in the JAR:
  862. try {
  863. c = super.findClass(name);
  864. if (isTraceOn()) {
  865. trace("findClass", "Class "+name+
  866. " loaded through mlet classloader");
  867. }
  868. } catch (ClassNotFoundException e) {
  869. // Drop through
  870. debug("findClass", "Class "+name+ " not found locally.");
  871. }
  872. // if we are not called from the ClassLoaderRepository
  873. if (c == null && delegateToCLR && clr != null) {
  874. // Try the classloader repository:
  875. //
  876. try {
  877. debug("findClass", "Class "+name+": looking in CLR");
  878. c = clr.loadClassBefore(this, name);
  879. // The loadClassBefore method never returns null.
  880. // If the class is not found we get an exception.
  881. if (isTraceOn()) {
  882. trace("findClass", "Class "+name+
  883. " loaded through the default classloader repository");
  884. }
  885. } catch (ClassNotFoundException e) {
  886. debug("findClass", "Class "+name+ " not found in CLR.");
  887. // Drop through
  888. }
  889. }
  890. if (c == null) {
  891. debug("findClass","Failed to load class " + name);
  892. throw new ClassNotFoundException(name);
  893. }
  894. return c;
  895. }
  896. /**
  897. * Returns the absolute path name of a native library. The VM invokes this method to locate the native
  898. * libraries that belong to classes loaded with this class loader. Libraries are searched in the JAR files
  899. * using first just the native library name and if not found the native library name together with the
  900. * architecture-specific path name (<code>OSName/OSArch/OSVersion/lib/nativelibname</code>), i.e.
  901. * <p>
  902. * the library stat on Solaris SPARC 5.7 will be searched in the JAR file as:
  903. * <OL>
  904. * <LI>libstat.so
  905. * <LI>SunOS/sparc/5.7/lib/libstat.so
  906. * </OL>
  907. * the library stat on Windows NT 4.0 will be searched in the JAR file as:
  908. * <OL>
  909. * <LI>stat.dll
  910. * <LI>WindowsNT/x86/4.0/lib/stat.dll
  911. * </OL>
  912. * <p>
  913. * If this method returns <code>null</code>, i.e. the libraries were not found in any of the JAR
  914. * files loaded with this class loader, the VM searches the library along the path specified as
  915. * the <code>java.library.path</code> property.
  916. *
  917. * @param libname The library name.
  918. *
  919. * @return The absolute path of the native library.
  920. */
  921. protected String findLibrary(String libname) {
  922. String abs_path;
  923. String mth = "findLibrary";
  924. // Get the platform-specific string representing a native library.
  925. //
  926. String nativelibname = System.mapLibraryName(libname);
  927. //
  928. // See if the native library is accessible as a resource through the JAR file.
  929. //
  930. if (isTraceOn()) {
  931. trace(mth, "Search " + libname + " in all JAR files.");
  932. }
  933. // First try to locate the library in the JAR file using only the native library name.
  934. // e.g. if user requested a load for "foo" on Solaris SPARC 5.7 we try to load
  935. // "libfoo.so" from the JAR file.
  936. //
  937. if (isTraceOn()) {
  938. trace(mth, "loadLibraryAsResource(" + nativelibname + ")");
  939. }
  940. abs_path = loadLibraryAsResource(nativelibname);
  941. if (abs_path != null) {
  942. if (isTraceOn()) {
  943. trace(mth, nativelibname + " loaded " + "absolute path = " + abs_path);
  944. }
  945. return abs_path;
  946. }
  947. // Next try to locate it using the native library name and the architecture-specific path name.
  948. // e.g. if user requested a load for "foo" on Solaris SPARC 5.7 we try to load
  949. // "SunOS/sparc/5.7/lib/libfoo.so" from the JAR file.
  950. //
  951. nativelibname = removeSpace(System.getProperty("os.name")) + File.separator +
  952. removeSpace(System.getProperty("os.arch")) + File.separator +
  953. removeSpace(System.getProperty("os.version")) + File.separator +
  954. "lib" + File.separator + nativelibname;
  955. if (isTraceOn()) {
  956. trace(mth, "loadLibraryAsResource(" + nativelibname + ")");
  957. }
  958. abs_path = loadLibraryAsResource(nativelibname);
  959. if (abs_path != null) {
  960. if (isTraceOn()) {
  961. trace(mth, nativelibname + " loaded " + "absolute path = " + abs_path);
  962. }
  963. return abs_path;
  964. }
  965. //
  966. // All paths exhausted, library not found in JAR file.
  967. //
  968. if (isTraceOn()) {
  969. trace(mth, libname + " not found in any JAR file.");
  970. trace(mth, "Search " + libname + " along the path specified as the java.library.path property.");
  971. }
  972. // Let the VM search the library along the path
  973. // specified as the java.library.path property.
  974. //
  975. return null;
  976. }
  977. /*
  978. * ------------------------------------------
  979. * PRIVATE METHODS
  980. * ------------------------------------------
  981. */
  982. private String getTmpDir() {
  983. // JDK 1.4
  984. String tmpDir = (String)System.getProperty("java.io.tmpdir");
  985. if (tmpDir != null) return tmpDir;
  986. // JDK < 1.4
  987. File tmpFile = null;
  988. try {
  989. // Try to guess the system temporary dir...
  990. tmpFile = File.createTempFile("tmp","jmx");
  991. if (tmpFile == null) return null;
  992. final File tmpDirFile = tmpFile.getParentFile();
  993. if (tmpDirFile == null) return null;
  994. return tmpDirFile.getAbsolutePath();
  995. } catch (Exception x) {
  996. debug("getTmpDir","Failed to determine system temporary dir.");
  997. return null;
  998. } finally {
  999. // Cleanup ...
  1000. if (tmpFile!=null) try {
  1001. tmpFile.delete();
  1002. } catch (Exception x) {
  1003. debug("getTmpDir","Failed to delete temporary file: " + x.getMessage());
  1004. }
  1005. }
  1006. }
  1007. /**
  1008. * Search the specified native library in any of the JAR files loaded by this classloader.
  1009. * If the library is found copy it into the library directory and return the absolute path.
  1010. * If the library is not found then return null.
  1011. */
  1012. private synchronized String loadLibraryAsResource(String libname) {
  1013. try {
  1014. InputStream is = getResourceAsStream(libname.replace(File.separatorChar,'/'));
  1015. if (is != null) {
  1016. File directory = new File(libraryDirectory);
  1017. directory.mkdirs();
  1018. File file = File.createTempFile(libname + ".", null, directory);
  1019. file.deleteOnExit();
  1020. FileOutputStream fileOutput = new FileOutputStream(file);
  1021. int c;
  1022. while ((c = is.read()) != -1) {
  1023. fileOutput.write(c);
  1024. }
  1025. is.close();
  1026. fileOutput.close();
  1027. if (file.exists()) {
  1028. return file.getAbsolutePath();
  1029. }
  1030. }
  1031. } catch (Exception e) {
  1032. debug("loadLibraryAsResource",libname+
  1033. ": Failed to load library. " + e);
  1034. return null;
  1035. }
  1036. return null;
  1037. }
  1038. /**
  1039. * Removes any white space from a string. This is used to
  1040. * convert strings such as "Windows NT" to "WindowsNT".
  1041. */
  1042. private String removeSpace(String s) {
  1043. s = s.trim();
  1044. int j = s.indexOf(' ');
  1045. if (j == -1) {
  1046. return s;
  1047. }
  1048. String temp = "";
  1049. int k = 0;
  1050. while (j != -1) {
  1051. s = s.substring(k);
  1052. j = s.indexOf(' ');
  1053. if (j != -1) {
  1054. temp = temp + s.substring(0, j);
  1055. } else {
  1056. temp = temp + s.substring(0);
  1057. }
  1058. k = j + 1;
  1059. }
  1060. return temp;
  1061. }
  1062. /**
  1063. * <p>This method is to be overridden when extending this service to
  1064. * support caching and versioning. It is called from {@link
  1065. * #getMBeansFromURL getMBeansFromURL} when the version,
  1066. * codebase, and jarfile have been extracted from the MLet file,
  1067. * and can be used to verify that it is all right to load the
  1068. * given MBean, or to replace the given URL with a different one.</p>
  1069. *
  1070. * <p>The default implementation of this method returns
  1071. * <code>codebase</code> unchanged.</p>
  1072. *
  1073. * @param version The version number of the <CODE>.jar</CODE>
  1074. * file stored locally.
  1075. * @param codebase The base URL of the remote <CODE>.jar</CODE> file.
  1076. * @param jarfile The name of the <CODE>.jar</CODE> file to be loaded.
  1077. * @param mlet The <CODE>MLetContent</CODE> instance that
  1078. * represents the <CODE>MLET</CODE> tag.
  1079. *
  1080. * @return the codebase to use for the loaded MBean. The returned
  1081. * value should not be null.
  1082. *
  1083. * @exception Exception if the MBean is not to be loaded for some
  1084. * reason. The exception will be added to the set returned by
  1085. * {@link #getMBeansFromURL getMBeansFromURL}.
  1086. *
  1087. * @since.unbundled JMX 1.2
  1088. */
  1089. protected URL check(String version, URL codebase, String jarfile,
  1090. MLetContent mlet)
  1091. throws Exception {
  1092. return codebase;
  1093. }
  1094. /**
  1095. * Loads the serialized object specified by the <CODE>OBJECT</CODE>
  1096. * attribute of the <CODE>MLET</CODE> tag.
  1097. *
  1098. * @param codebase The <CODE>codebase</CODE>.
  1099. * @param filename The name of the file containing the serialized object.
  1100. * @return The serialized object.
  1101. * @exception ClassNotFoundException The specified serialized object could not be found.
  1102. * @exception IOException An I/O error occurred while loading serialized object.
  1103. */
  1104. private Object loadSerializedObject(URL codebase, String filename) throws IOException, ClassNotFoundException {
  1105. if (filename != null) {
  1106. filename = filename.replace(File.separatorChar,'/');
  1107. }
  1108. if (isTraceOn()) {
  1109. trace("loadSerializedObject", codebase.toString() + filename);
  1110. }
  1111. InputStream is = getResourceAsStream(filename);
  1112. if (is != null) {
  1113. try {
  1114. ObjectInputStream ois = new MLetObjectInputStream(is, this);
  1115. Object serObject = ois.readObject();
  1116. ois.close();
  1117. return serObject;
  1118. } catch (IOException e) {
  1119. if (isDebugOn()) {
  1120. debug("loadSerializedObject", "Exception while deserializing " + filename + ", " + e.getMessage());
  1121. }
  1122. throw e;
  1123. } catch (ClassNotFoundException e) {
  1124. if (isDebugOn()) {
  1125. debug("loadSerializedObject", "Exception while deserializing " + filename + ", " + e.getMessage());
  1126. }
  1127. throw e;
  1128. }
  1129. } else {
  1130. if (isDebugOn()) {
  1131. debug("loadSerializedObject", "Error: File " + filename + " containing serialized object not found");
  1132. }
  1133. throw new Error("File " + filename + " containing serialized object not found");
  1134. }
  1135. }
  1136. /**
  1137. * Converts the String value of the constructor's parameter to
  1138. * a basic Java object with the type of the parameter.
  1139. */
  1140. private Object constructParameter(String param, String type) {
  1141. // check if it is a primitive type
  1142. Class c = (Class) primitiveClasses.get(type);
  1143. if (c != null) {
  1144. try {
  1145. Constructor cons =
  1146. c.getConstructor(new Class[] {String.class});
  1147. Object[] oo = new Object[1];
  1148. oo[0]=param;
  1149. return(cons.newInstance(oo));
  1150. } catch (Exception e) {
  1151. if (isDebugOn()) {
  1152. debug(dbgTag, "constructParameter", "Unexpected Exception" + e.getClass().getName() + " occured");
  1153. }
  1154. }
  1155. }
  1156. if (type.compareTo("java.lang.Boolean") == 0)
  1157. return new Boolean(param);
  1158. if (type.compareTo("java.lang.Byte") == 0)
  1159. return new Byte(param);
  1160. if (type.compareTo("java.lang.Short") == 0)
  1161. return new Short(param);
  1162. if (type.compareTo("java.lang.Long") == 0)
  1163. return new Long(param);
  1164. if (type.compareTo("java.lang.Integer") == 0)
  1165. return new Integer(param);
  1166. if (type.compareTo("java.lang.Float") == 0)
  1167. return new Float(param);
  1168. if (type.compareTo("java.lang.Double") == 0)
  1169. return new Double(param);
  1170. if (type.compareTo("java.lang.String") == 0)
  1171. return param;
  1172. return param;
  1173. }
  1174. private synchronized void setMBeanServer(final MBeanServer server) {
  1175. this.server = server;
  1176. currentClr = (ClassLoaderRepository)
  1177. AccessController.doPrivileged(new PrivilegedAction() {
  1178. public Object run() {
  1179. return server.getClassLoaderRepository();
  1180. }
  1181. });
  1182. }
  1183. // TRACES & DEBUG
  1184. //---------------
  1185. private boolean isTraceOn() {
  1186. return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_MLET);
  1187. }
  1188. private void trace(String clz, String func, String info) {
  1189. Trace.send(Trace.LEVEL_TRACE, Trace.INFO_MLET, clz, func, info);
  1190. }
  1191. private void trace(String func, String info) {
  1192. trace(dbgTag, func, info);
  1193. }
  1194. private boolean isDebugOn() {
  1195. return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_MLET);
  1196. }
  1197. private void debug(String clz, String func, String info) {
  1198. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_MLET, clz, func, info);
  1199. }
  1200. private void debug(String func, String info) {
  1201. debug(dbgTag, func, info);
  1202. }
  1203. }