808 lines · 30.1 KB · Java
RawDownload
 /* * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jmx.remote.util; import java.io.IOException;import java.io.ObjectOutputStream;import java.io.OutputStream;import java.util.Collection;import java.util.HashMap;import java.util.Hashtable;import java.util.Iterator;import java.util.Map;import java.util.SortedMap;import java.util.SortedSet;import java.util.StringTokenizer;import java.util.TreeMap;import java.util.TreeSet; import java.security.AccessController; import javax.management.ObjectName;import javax.management.MBeanServer;import javax.management.InstanceNotFoundException;import javax.management.remote.JMXConnectorFactory;import javax.management.remote.JMXConnectorServerFactory;import com.sun.jmx.mbeanserver.GetPropertyAction;import com.sun.jmx.remote.security.NotificationAccessController;import javax.management.remote.JMXConnector;import javax.management.remote.JMXConnectorServer; public class EnvHelp {     /**     * <p>Name of the attribute that specifies a default class loader     * object.     * The value associated with this attribute is a ClassLoader object</p>     */    private static final String DEFAULT_CLASS_LOADER =        JMXConnectorFactory.DEFAULT_CLASS_LOADER;     /**     * <p>Name of the attribute that specifies a default class loader     *    ObjectName.     * The value associated with this attribute is an ObjectName object</p>     */    private static final String DEFAULT_CLASS_LOADER_NAME =        JMXConnectorServerFactory.DEFAULT_CLASS_LOADER_NAME;     /**     * Get the Connector Server default class loader.     * <p>     * Returns:     * <p>     * <ul>     * <li>     *     The ClassLoader object found in <var>env</var> for     *     <code>jmx.remote.default.class.loader</code>, if any.     * </li>     * <li>     *     The ClassLoader pointed to by the ObjectName found in     *     <var>env</var> for <code>jmx.remote.default.class.loader.name</code>,     *     and registered in <var>mbs</var> if any.     * </li>     * <li>     *     The current thread's context classloader otherwise.     * </li>     * </ul>     *     * @param env Environment attributes.     * @param mbs The MBeanServer for which the connector server provides     * remote access.     *     * @return the connector server's default class loader.     *     * @exception IllegalArgumentException if one of the following is true:     * <ul>     * <li>both     *     <code>jmx.remote.default.class.loader</code> and     *     <code>jmx.remote.default.class.loader.name</code> are specified,     * </li>     * <li>or     *     <code>jmx.remote.default.class.loader</code> is not     *     an instance of {@link ClassLoader},     * </li>     * <li>or     *     <code>jmx.remote.default.class.loader.name</code> is not     *     an instance of {@link ObjectName},     * </li>     * <li>or     *     <code>jmx.remote.default.class.loader.name</code> is specified     *     but <var>mbs</var> is null.     * </li>     * @exception InstanceNotFoundException if     * <code>jmx.remote.default.class.loader.name</code> is specified     * and the ClassLoader MBean is not found in <var>mbs</var>.     */    public static ClassLoader resolveServerClassLoader(Map<String, ?> env,                                                       MBeanServer mbs)        throws InstanceNotFoundException {         if (env == null)            return Thread.currentThread().getContextClassLoader();         Object loader = env.get(DEFAULT_CLASS_LOADER);        Object name   = env.get(DEFAULT_CLASS_LOADER_NAME);         if (loader != null && name != null) {            final String msg = "Only one of " +                DEFAULT_CLASS_LOADER + " or " +                DEFAULT_CLASS_LOADER_NAME +                " should be specified.";            throw new IllegalArgumentException(msg);        }         if (loader == null && name == null)            return Thread.currentThread().getContextClassLoader();         if (loader != null) {            if (loader instanceof ClassLoader) {                return (ClassLoader) loader;            } else {                final String msg =                    "ClassLoader object is not an instance of " +                    ClassLoader.class.getName() + " : " +                    loader.getClass().getName();                throw new IllegalArgumentException(msg);            }        }         ObjectName on;        if (name instanceof ObjectName) {            on = (ObjectName) name;        } else {            final String msg =                "ClassLoader name is not an instance of " +                ObjectName.class.getName() + " : " +                name.getClass().getName();            throw new IllegalArgumentException(msg);        }         if (mbs == null)            throw new IllegalArgumentException("Null MBeanServer object");         return mbs.getClassLoader(on);    }     /**     * Get the Connector Client default class loader.     * <p>     * Returns:     * <p>     * <ul>     * <li>     *     The ClassLoader object found in <var>env</var> for     *     <code>jmx.remote.default.class.loader</code>, if any.     * </li>     * <li>The <tt>Thread.currentThread().getContextClassLoader()</tt>     *     otherwise.     * </li>     * </ul>     * <p>     * Usually a Connector Client will call     * <pre>     * ClassLoader dcl = EnvHelp.resolveClientClassLoader(env);     * </pre>     * in its <code>connect(Map env)</code> method.     *     * @return The connector client default class loader.     *     * @exception IllegalArgumentException if     * <code>jmx.remote.default.class.loader</code> is specified     * and is not an instance of {@link ClassLoader}.     */    public static ClassLoader resolveClientClassLoader(Map<String, ?> env) {         if (env == null)            return Thread.currentThread().getContextClassLoader();         Object loader = env.get(DEFAULT_CLASS_LOADER);         if (loader == null)            return Thread.currentThread().getContextClassLoader();         if (loader instanceof ClassLoader) {            return (ClassLoader) loader;        } else {            final String msg =                "ClassLoader object is not an instance of " +                ClassLoader.class.getName() + " : " +                loader.getClass().getName();            throw new IllegalArgumentException(msg);        }    }     /**     * Initialize the cause field of a {@code Throwable} object.     *     * @param throwable The {@code Throwable} on which the cause is set.     * @param cause The cause to set on the supplied {@code Throwable}.     * @return the {@code Throwable} with the cause field initialized.     */    public static <T extends Throwable> T initCause(T throwable,                                                    Throwable cause) {        throwable.initCause(cause);        return throwable;    }     /**     * Returns the cause field of a {@code Throwable} object.     * The cause field can be got only if <var>t</var> has an     * {@link Throwable#getCause()} method (JDK Version >= 1.4)     * @param t {@code Throwable} on which the cause must be set.     * @return the cause if getCause() succeeded and the got value is not     * null, otherwise return the <var>t</var>.     */    public static Throwable getCause(Throwable t) {        Throwable ret = t;         try {            java.lang.reflect.Method getCause =                t.getClass().getMethod("getCause", (Class<?>[]) null);            ret = (Throwable)getCause.invoke(t, (Object[]) null);         } catch (Exception e) {            // OK.            // it must be older than 1.4.        }        return (ret != null) ? ret: t;    }      /**     * <p>Name of the attribute that specifies the size of a notification     * buffer for a connector server. The default value is 1000.     */    public static final String BUFFER_SIZE_PROPERTY =        "jmx.remote.x.notification.buffer.size";      /**     * Returns the size of a notification buffer for a connector server.     * The default value is 1000.     */    public static int getNotifBufferSize(Map<String, ?> env) {        int defaultQueueSize = 1000; // default value         // keep it for the compability for the fix:        // 6174229: Environment parameter should be notification.buffer.size        // instead of buffer.size        final String oldP = "jmx.remote.x.buffer.size";         // the default value re-specified in the system        try {            GetPropertyAction act = new GetPropertyAction(BUFFER_SIZE_PROPERTY);            String s = AccessController.doPrivileged(act);            if (s != null) {                defaultQueueSize = Integer.parseInt(s);            } else { // try the old one                act = new GetPropertyAction(oldP);                s = AccessController.doPrivileged(act);                if (s != null) {                    defaultQueueSize = Integer.parseInt(s);                }            }        } catch (RuntimeException e) {            logger.warning("getNotifBufferSize",                           "Can't use System property "+                           BUFFER_SIZE_PROPERTY+ ": " + e);              logger.debug("getNotifBufferSize", e);        }         int queueSize = defaultQueueSize;         try {            if (env.containsKey(BUFFER_SIZE_PROPERTY)) {                queueSize = (int)EnvHelp.getIntegerAttribute(env,BUFFER_SIZE_PROPERTY,                                            defaultQueueSize,0,                                            Integer.MAX_VALUE);            } else { // try the old one                queueSize = (int)EnvHelp.getIntegerAttribute(env,oldP,                                            defaultQueueSize,0,                                            Integer.MAX_VALUE);            }        } catch (RuntimeException e) {            logger.warning("getNotifBufferSize",                           "Can't determine queuesize (using default): "+                           e);            logger.debug("getNotifBufferSize", e);        }         return queueSize;    }     /**     * <p>Name of the attribute that specifies the maximum number of     * notifications that a client will fetch from its server.. The     * value associated with this attribute should be an     * <code>Integer</code> object.  The default value is 1000.</p>     */    public static final String MAX_FETCH_NOTIFS =        "jmx.remote.x.notification.fetch.max";     /**     * Returns the maximum notification number which a client will     * fetch every time.     */    public static int getMaxFetchNotifNumber(Map<String, ?> env) {        return (int) getIntegerAttribute(env, MAX_FETCH_NOTIFS, 1000, 1,                                         Integer.MAX_VALUE);    }     /**     * <p>Name of the attribute that specifies the timeout for a     * client to fetch notifications from its server. The value     * associated with this attribute should be a <code>Long</code>     * object.  The default value is 60000 milliseconds.</p>     */    public static final String FETCH_TIMEOUT =        "jmx.remote.x.notification.fetch.timeout";     /**     * Returns the timeout for a client to fetch notifications.     */    public static long getFetchTimeout(Map<String, ?> env) {        return getIntegerAttribute(env, FETCH_TIMEOUT, 60000L, 0,                Long.MAX_VALUE);    }     /**     * <p>Name of the attribute that specifies an object that will check     * accesses to add/removeNotificationListener and also attempts to     * receive notifications.  The value associated with this attribute     * should be a <code>NotificationAccessController</code> object.     * The default value is null.</p>     * This field is not public because of its com.sun dependency.     */    public static final String NOTIF_ACCESS_CONTROLLER =            "com.sun.jmx.remote.notification.access.controller";     public static NotificationAccessController getNotificationAccessController(            Map<String, ?> env) {        return (env == null) ? null :            (NotificationAccessController) env.get(NOTIF_ACCESS_CONTROLLER);    }     /**     * Get an integer-valued attribute with name <code>name</code>     * from <code>env</code>.  If <code>env</code> is null, or does     * not contain an entry for <code>name</code>, return     * <code>defaultValue</code>.  The value may be a Number, or it     * may be a String that is parsable as a long.  It must be at     * least <code>minValue</code> and at most<code>maxValue</code>.     *     * @throws IllegalArgumentException if <code>env</code> contains     * an entry for <code>name</code> but it does not meet the     * constraints above.     */    public static long getIntegerAttribute(Map<String, ?> env, String name,                                           long defaultValue, long minValue,                                           long maxValue) {        final Object o;         if (env == null || (o = env.get(name)) == null)            return defaultValue;         final long result;         if (o instanceof Number)            result = ((Number) o).longValue();        else if (o instanceof String) {            result = Long.parseLong((String) o);            /* May throw a NumberFormatException, which is an               IllegalArgumentException.  */        } else {            final String msg =                "Attribute " + name + " value must be Integer or String: " + o;            throw new IllegalArgumentException(msg);        }         if (result < minValue) {            final String msg =                "Attribute " + name + " value must be at least " + minValue +                ": " + result;            throw new IllegalArgumentException(msg);        }         if (result > maxValue) {            final String msg =                "Attribute " + name + " value must be at most " + maxValue +                ": " + result;            throw new IllegalArgumentException(msg);        }         return result;    }     public static final String DEFAULT_ORB="java.naming.corba.orb";     /* Check that all attributes have a key that is a String.       Could make further checks, e.g. appropriate types for attributes.  */    public static void checkAttributes(Map<?, ?> attributes) {        for (Object key : attributes.keySet()) {            if (!(key instanceof String)) {                final String msg =                    "Attributes contain key that is not a string: " + key;                throw new IllegalArgumentException(msg);            }        }    }     /* Return a writable map containing only those attributes that are       serializable, and that are not hidden by       jmx.remote.x.hidden.attributes or the default list of hidden       attributes.  */    public static <V> Map<String, V> filterAttributes(Map<String, V> attributes) {        if (logger.traceOn()) {            logger.trace("filterAttributes", "starts");        }         SortedMap<String, V> map = new TreeMap<String, V>(attributes);        purgeUnserializable(map.values());        hideAttributes(map);        return map;    }     /**     * Remove from the given Collection any element that is not a     * serializable object.     */    private static void purgeUnserializable(Collection<?> objects) {        logger.trace("purgeUnserializable", "starts");        ObjectOutputStream oos = null;        int i = 0;        for (Iterator<?> it = objects.iterator(); it.hasNext(); i++) {            Object v = it.next();             if (v == null || v instanceof String) {                if (logger.traceOn()) {                    logger.trace("purgeUnserializable",                                 "Value trivially serializable: " + v);                }                continue;            }             try {                if (oos == null)                    oos = new ObjectOutputStream(new SinkOutputStream());                oos.writeObject(v);                if (logger.traceOn()) {                    logger.trace("purgeUnserializable",                                 "Value serializable: " + v);                }            } catch (IOException e) {                if (logger.traceOn()) {                    logger.trace("purgeUnserializable",                                 "Value not serializable: " + v + ": " +                                 e);                }                it.remove();                oos = null; // ObjectOutputStream invalid after exception            }        }    }     /**     * The value of this attribute, if present, is a string specifying     * what other attributes should not appear in     * JMXConnectorServer.getAttributes().  It is a space-separated     * list of attribute patterns, where each pattern is either an     * attribute name, or an attribute prefix followed by a "*"     * character.  The "*" has no special significance anywhere except     * at the end of a pattern.  By default, this list is added to the     * list defined by {@link #DEFAULT_HIDDEN_ATTRIBUTES} (which     * uses the same format).  If the value of this attribute begins     * with an "=", then the remainder of the string defines the     * complete list of attribute patterns.

Lines 1–500 of 808.