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