38 import java.util.SortedSet;
39 import java.util.StringTokenizer;
40 import java.util.TreeMap;
41 import java.util.TreeSet;
42
43 import java.security.AccessController;
44
45 import javax.management.ObjectName;
46 import javax.management.MBeanServer;
47 import javax.management.InstanceNotFoundException;
48 import javax.management.remote.JMXConnectorFactory;
49 import javax.management.remote.JMXConnectorServerFactory;
50 import com.sun.jmx.mbeanserver.GetPropertyAction;
51 import com.sun.jmx.remote.security.NotificationAccessController;
52 import javax.management.remote.JMXConnector;
53 import javax.management.remote.JMXConnectorServer;
54
55 public class EnvHelp {
56
57 /**
58 * <p>Name of the attribute that specifies a default class loader
59 * object.
60 * The value associated with this attribute is a ClassLoader object</p>
61 */
62 private static final String DEFAULT_CLASS_LOADER =
63 JMXConnectorFactory.DEFAULT_CLASS_LOADER;
64
65 /**
66 * <p>Name of the attribute that specifies a default class loader
67 * ObjectName.
68 * The value associated with this attribute is an ObjectName object</p>
69 */
70 private static final String DEFAULT_CLASS_LOADER_NAME =
71 JMXConnectorServerFactory.DEFAULT_CLASS_LOADER_NAME;
72
73 /**
74 * Get the Connector Server default class loader.
75 * <p>
76 * Returns:
77 * <p>
78 * <ul>
79 * <li>
80 * The ClassLoader object found in <var>env</var> for
81 * <code>jmx.remote.default.class.loader</code>, if any.
82 * </li>
83 * <li>
84 * The ClassLoader pointed to by the ObjectName found in
85 * <var>env</var> for <code>jmx.remote.default.class.loader.name</code>,
86 * and registered in <var>mbs</var> if any.
87 * </li>
88 * <li>
89 * The current thread's context classloader otherwise.
90 * </li>
91 * </ul>
92 *
93 * @param env Environment attributes.
94 * @param mbs The MBeanServer for which the connector server provides
95 * remote access.
96 *
97 * @return the connector server's default class loader.
98 *
99 * @exception IllegalArgumentException if one of the following is true:
100 * <ul>
101 * <li>both
102 * <code>jmx.remote.default.class.loader</code> and
103 * <code>jmx.remote.default.class.loader.name</code> are specified,
104 * </li>
105 * <li>or
106 * <code>jmx.remote.default.class.loader</code> is not
107 * an instance of {@link ClassLoader},
108 * </li>
109 * <li>or
110 * <code>jmx.remote.default.class.loader.name</code> is not
111 * an instance of {@link ObjectName},
112 * </li>
113 * <li>or
114 * <code>jmx.remote.default.class.loader.name</code> is specified
115 * but <var>mbs</var> is null.
116 * </li>
117 * @exception InstanceNotFoundException if
118 * <code>jmx.remote.default.class.loader.name</code> is specified
119 * and the ClassLoader MBean is not found in <var>mbs</var>.
120 */
121 public static ClassLoader resolveServerClassLoader(Map<String, ?> env,
122 MBeanServer mbs)
123 throws InstanceNotFoundException {
124
125 if (env == null)
126 return Thread.currentThread().getContextClassLoader();
127
128 Object loader = env.get(DEFAULT_CLASS_LOADER);
129 Object name = env.get(DEFAULT_CLASS_LOADER_NAME);
130
131 if (loader != null && name != null) {
132 final String msg = "Only one of " +
133 DEFAULT_CLASS_LOADER + " or " +
134 DEFAULT_CLASS_LOADER_NAME +
135 " should be specified.";
136 throw new IllegalArgumentException(msg);
155 if (name instanceof ObjectName) {
156 on = (ObjectName) name;
157 } else {
158 final String msg =
159 "ClassLoader name is not an instance of " +
160 ObjectName.class.getName() + " : " +
161 name.getClass().getName();
162 throw new IllegalArgumentException(msg);
163 }
164
165 if (mbs == null)
166 throw new IllegalArgumentException("Null MBeanServer object");
167
168 return mbs.getClassLoader(on);
169 }
170
171 /**
172 * Get the Connector Client default class loader.
173 * <p>
174 * Returns:
175 * <p>
176 * <ul>
177 * <li>
178 * The ClassLoader object found in <var>env</var> for
179 * <code>jmx.remote.default.class.loader</code>, if any.
180 * </li>
181 * <li>The <tt>Thread.currentThread().getContextClassLoader()</tt>
182 * otherwise.
183 * </li>
184 * </ul>
185 * <p>
186 * Usually a Connector Client will call
187 * <pre>
188 * ClassLoader dcl = EnvHelp.resolveClientClassLoader(env);
189 * </pre>
190 * in its <code>connect(Map env)</code> method.
191 *
192 * @return The connector client default class loader.
193 *
194 * @exception IllegalArgumentException if
195 * <code>jmx.remote.default.class.loader</code> is specified
215 throw new IllegalArgumentException(msg);
216 }
217 }
218
219 /**
220 * Initialize the cause field of a {@code Throwable} object.
221 *
222 * @param throwable The {@code Throwable} on which the cause is set.
223 * @param cause The cause to set on the supplied {@code Throwable}.
224 * @return the {@code Throwable} with the cause field initialized.
225 */
226 public static <T extends Throwable> T initCause(T throwable,
227 Throwable cause) {
228 throwable.initCause(cause);
229 return throwable;
230 }
231
232 /**
233 * Returns the cause field of a {@code Throwable} object.
234 * The cause field can be got only if <var>t</var> has an
235 * {@link Throwable#getCause()} method (JDK Version >= 1.4)
236 * @param t {@code Throwable} on which the cause must be set.
237 * @return the cause if getCause() succeeded and the got value is not
238 * null, otherwise return the <var>t</var>.
239 */
240 public static Throwable getCause(Throwable t) {
241 Throwable ret = t;
242
243 try {
244 java.lang.reflect.Method getCause =
245 t.getClass().getMethod("getCause", (Class<?>[]) null);
246 ret = (Throwable)getCause.invoke(t, (Object[]) null);
247
248 } catch (Exception e) {
249 // OK.
250 // it must be older than 1.4.
251 }
252 return (ret != null) ? ret: t;
253 }
254
255
256 /**
257 * <p>Name of the attribute that specifies the size of a notification
258 * buffer for a connector server. The default value is 1000.
259 */
260 public static final String BUFFER_SIZE_PROPERTY =
261 "jmx.remote.x.notification.buffer.size";
262
263
264 /**
265 * Returns the size of a notification buffer for a connector server.
266 * The default value is 1000.
267 */
268 public static int getNotifBufferSize(Map<String, ?> env) {
269 int defaultQueueSize = 1000; // default value
270
271 // keep it for the compability for the fix:
272 // 6174229: Environment parameter should be notification.buffer.size
273 // instead of buffer.size
274 final String oldP = "jmx.remote.x.buffer.size";
275
276 // the default value re-specified in the system
277 try {
299 if (env.containsKey(BUFFER_SIZE_PROPERTY)) {
300 queueSize = (int)EnvHelp.getIntegerAttribute(env,BUFFER_SIZE_PROPERTY,
301 defaultQueueSize,0,
302 Integer.MAX_VALUE);
303 } else { // try the old one
304 queueSize = (int)EnvHelp.getIntegerAttribute(env,oldP,
305 defaultQueueSize,0,
306 Integer.MAX_VALUE);
307 }
308 } catch (RuntimeException e) {
309 logger.warning("getNotifBufferSize",
310 "Can't determine queuesize (using default): "+
311 e);
312 logger.debug("getNotifBufferSize", e);
313 }
314
315 return queueSize;
316 }
317
318 /**
319 * <p>Name of the attribute that specifies the maximum number of
320 * notifications that a client will fetch from its server.. The
321 * value associated with this attribute should be an
322 * <code>Integer</code> object. The default value is 1000.</p>
323 */
324 public static final String MAX_FETCH_NOTIFS =
325 "jmx.remote.x.notification.fetch.max";
326
327 /**
328 * Returns the maximum notification number which a client will
329 * fetch every time.
330 */
331 public static int getMaxFetchNotifNumber(Map<String, ?> env) {
332 return (int) getIntegerAttribute(env, MAX_FETCH_NOTIFS, 1000, 1,
333 Integer.MAX_VALUE);
334 }
335
336 /**
337 * <p>Name of the attribute that specifies the timeout for a
338 * client to fetch notifications from its server. The value
339 * associated with this attribute should be a <code>Long</code>
340 * object. The default value is 60000 milliseconds.</p>
341 */
342 public static final String FETCH_TIMEOUT =
343 "jmx.remote.x.notification.fetch.timeout";
344
345 /**
346 * Returns the timeout for a client to fetch notifications.
347 */
348 public static long getFetchTimeout(Map<String, ?> env) {
349 return getIntegerAttribute(env, FETCH_TIMEOUT, 60000L, 0,
350 Long.MAX_VALUE);
351 }
352
353 /**
354 * <p>Name of the attribute that specifies an object that will check
355 * accesses to add/removeNotificationListener and also attempts to
356 * receive notifications. The value associated with this attribute
357 * should be a <code>NotificationAccessController</code> object.
358 * The default value is null.</p>
359 * This field is not public because of its com.sun dependency.
360 */
361 public static final String NOTIF_ACCESS_CONTROLLER =
362 "com.sun.jmx.remote.notification.access.controller";
363
364 public static NotificationAccessController getNotificationAccessController(
365 Map<String, ?> env) {
366 return (env == null) ? null :
367 (NotificationAccessController) env.get(NOTIF_ACCESS_CONTROLLER);
368 }
369
370 /**
371 * Get an integer-valued attribute with name <code>name</code>
372 * from <code>env</code>. If <code>env</code> is null, or does
373 * not contain an entry for <code>name</code>, return
374 * <code>defaultValue</code>. The value may be a Number, or it
375 * may be a String that is parsable as a long. It must be at
376 * least <code>minValue</code> and at most<code>maxValue</code>.
377 *
378 * @throws IllegalArgumentException if <code>env</code> contains
613 else
614 nextPrefix = sentinelKey;
615 }
616 }
617 }
618
619 private static void parseHiddenAttributes(String hide,
620 SortedSet<String> hiddenStrings,
621 SortedSet<String> hiddenPrefixes) {
622 final StringTokenizer tok = new StringTokenizer(hide);
623 while (tok.hasMoreTokens()) {
624 String s = tok.nextToken();
625 if (s.endsWith("*"))
626 hiddenPrefixes.add(s.substring(0, s.length() - 1));
627 else
628 hiddenStrings.add(s);
629 }
630 }
631
632 /**
633 * <p>Name of the attribute that specifies the timeout to keep a
634 * server side connection after answering last client request.
635 * The default value is 120000 milliseconds.</p>
636 */
637 public static final String SERVER_CONNECTION_TIMEOUT =
638 "jmx.remote.x.server.connection.timeout";
639
640 /**
641 * Returns the server side connection timeout.
642 */
643 public static long getServerConnectionTimeout(Map<String, ?> env) {
644 return getIntegerAttribute(env, SERVER_CONNECTION_TIMEOUT, 120000L,
645 0, Long.MAX_VALUE);
646 }
647
648 /**
649 * <p>Name of the attribute that specifies the period in
650 * millisecond for a client to check its connection. The default
651 * value is 60000 milliseconds.</p>
652 */
653 public static final String CLIENT_CONNECTION_CHECK_PERIOD =
654 "jmx.remote.x.client.connection.check.period";
655
656 /**
657 * Returns the client connection check period.
658 */
659 public static long getConnectionCheckPeriod(Map<String, ?> env) {
660 return getIntegerAttribute(env, CLIENT_CONNECTION_CHECK_PERIOD, 60000L,
661 0, Long.MAX_VALUE);
662 }
663
664 /**
665 * Computes a boolean value from a string value retrieved from a
666 * property in the given map.
667 *
668 * @param stringBoolean the string value that must be converted
669 * into a boolean value.
670 *
671 * @return
724 return false;
725 else
726 throw new IllegalArgumentException(
727 "Property value must be \"true\" or \"false\" instead of \"" +
728 stringBoolean + "\"");
729 }
730
731 /**
732 * Converts a map into a valid hash table, i.e.
733 * it removes all the 'null' values from the map.
734 */
735 public static <K, V> Hashtable<K, V> mapToHashtable(Map<K, V> map) {
736 HashMap<K, V> m = new HashMap<K, V>(map);
737 if (m.containsKey(null)) m.remove(null);
738 for (Iterator<?> i = m.values().iterator(); i.hasNext(); )
739 if (i.next() == null) i.remove();
740 return new Hashtable<K, V>(m);
741 }
742
743 /**
744 * <p>Name of the attribute that specifies whether a connector server
745 * should not prevent the VM from exiting
746 */
747 public static final String JMX_SERVER_DAEMON = "jmx.remote.x.daemon";
748
749 /**
750 * Returns true if {@value SERVER_DAEMON} is specified in the {@code env}
751 * as a key and its value is a String and it is equal to true ignoring case.
752 *
753 * @param env
754 * @return
755 */
756 public static boolean isServerDaemon(Map<String, ?> env) {
757 return (env != null) &&
758 ("true".equalsIgnoreCase((String)env.get(JMX_SERVER_DAEMON)));
759 }
760
761 private static final class SinkOutputStream extends OutputStream {
762 public void write(byte[] b, int off, int len) {}
763 public void write(int b) {}
764 }
765
766 private static final ClassLogger logger =
767 new ClassLogger("javax.management.remote.misc", "EnvHelp");
768 }
|
38 import java.util.SortedSet;
39 import java.util.StringTokenizer;
40 import java.util.TreeMap;
41 import java.util.TreeSet;
42
43 import java.security.AccessController;
44
45 import javax.management.ObjectName;
46 import javax.management.MBeanServer;
47 import javax.management.InstanceNotFoundException;
48 import javax.management.remote.JMXConnectorFactory;
49 import javax.management.remote.JMXConnectorServerFactory;
50 import com.sun.jmx.mbeanserver.GetPropertyAction;
51 import com.sun.jmx.remote.security.NotificationAccessController;
52 import javax.management.remote.JMXConnector;
53 import javax.management.remote.JMXConnectorServer;
54
55 public class EnvHelp {
56
57 /**
58 * Name of the attribute that specifies a default class loader
59 * object.
60 * The value associated with this attribute is a ClassLoader object.
61 */
62 private static final String DEFAULT_CLASS_LOADER =
63 JMXConnectorFactory.DEFAULT_CLASS_LOADER;
64
65 /**
66 * Name of the attribute that specifies a default class loader
67 * ObjectName.
68 * The value associated with this attribute is an ObjectName object.
69 */
70 private static final String DEFAULT_CLASS_LOADER_NAME =
71 JMXConnectorServerFactory.DEFAULT_CLASS_LOADER_NAME;
72
73 /**
74 * Get the Connector Server default class loader.
75 * <p>
76 * Returns:
77 * <ul>
78 * <li>
79 * The ClassLoader object found in <var>env</var> for
80 * <code>jmx.remote.default.class.loader</code>, if any.
81 * </li>
82 * <li>
83 * The ClassLoader pointed to by the ObjectName found in
84 * <var>env</var> for <code>jmx.remote.default.class.loader.name</code>,
85 * and registered in <var>mbs</var> if any.
86 * </li>
87 * <li>
88 * The current thread's context classloader otherwise.
89 * </li>
90 * </ul>
91 *
92 * @param env Environment attributes.
93 * @param mbs The MBeanServer for which the connector server provides
94 * remote access.
95 *
96 * @return the connector server's default class loader.
97 *
98 * @exception IllegalArgumentException if one of the following is true:
99 * <ul>
100 * <li>both
101 * <code>jmx.remote.default.class.loader</code> and
102 * <code>jmx.remote.default.class.loader.name</code> are specified,
103 * </li>
104 * <li>or
105 * <code>jmx.remote.default.class.loader</code> is not
106 * an instance of {@link ClassLoader},
107 * </li>
108 * <li>or
109 * <code>jmx.remote.default.class.loader.name</code> is not
110 * an instance of {@link ObjectName},
111 * </li>
112 * <li>or
113 * <code>jmx.remote.default.class.loader.name</code> is specified
114 * but <var>mbs</var> is null.
115 * </li>
116 * </ul>
117 * @exception InstanceNotFoundException if
118 * <code>jmx.remote.default.class.loader.name</code> is specified
119 * and the ClassLoader MBean is not found in <var>mbs</var>.
120 */
121 public static ClassLoader resolveServerClassLoader(Map<String, ?> env,
122 MBeanServer mbs)
123 throws InstanceNotFoundException {
124
125 if (env == null)
126 return Thread.currentThread().getContextClassLoader();
127
128 Object loader = env.get(DEFAULT_CLASS_LOADER);
129 Object name = env.get(DEFAULT_CLASS_LOADER_NAME);
130
131 if (loader != null && name != null) {
132 final String msg = "Only one of " +
133 DEFAULT_CLASS_LOADER + " or " +
134 DEFAULT_CLASS_LOADER_NAME +
135 " should be specified.";
136 throw new IllegalArgumentException(msg);
155 if (name instanceof ObjectName) {
156 on = (ObjectName) name;
157 } else {
158 final String msg =
159 "ClassLoader name is not an instance of " +
160 ObjectName.class.getName() + " : " +
161 name.getClass().getName();
162 throw new IllegalArgumentException(msg);
163 }
164
165 if (mbs == null)
166 throw new IllegalArgumentException("Null MBeanServer object");
167
168 return mbs.getClassLoader(on);
169 }
170
171 /**
172 * Get the Connector Client default class loader.
173 * <p>
174 * Returns:
175 * <ul>
176 * <li>
177 * The ClassLoader object found in <var>env</var> for
178 * <code>jmx.remote.default.class.loader</code>, if any.
179 * </li>
180 * <li>The <tt>Thread.currentThread().getContextClassLoader()</tt>
181 * otherwise.
182 * </li>
183 * </ul>
184 * <p>
185 * Usually a Connector Client will call
186 * <pre>
187 * ClassLoader dcl = EnvHelp.resolveClientClassLoader(env);
188 * </pre>
189 * in its <code>connect(Map env)</code> method.
190 *
191 * @return The connector client default class loader.
192 *
193 * @exception IllegalArgumentException if
194 * <code>jmx.remote.default.class.loader</code> is specified
214 throw new IllegalArgumentException(msg);
215 }
216 }
217
218 /**
219 * Initialize the cause field of a {@code Throwable} object.
220 *
221 * @param throwable The {@code Throwable} on which the cause is set.
222 * @param cause The cause to set on the supplied {@code Throwable}.
223 * @return the {@code Throwable} with the cause field initialized.
224 */
225 public static <T extends Throwable> T initCause(T throwable,
226 Throwable cause) {
227 throwable.initCause(cause);
228 return throwable;
229 }
230
231 /**
232 * Returns the cause field of a {@code Throwable} object.
233 * The cause field can be got only if <var>t</var> has an
234 * {@link Throwable#getCause()} method (JDK Version {@literal >=} 1.4)
235 * @param t {@code Throwable} on which the cause must be set.
236 * @return the cause if getCause() succeeded and the got value is not
237 * null, otherwise return the <var>t</var>.
238 */
239 public static Throwable getCause(Throwable t) {
240 Throwable ret = t;
241
242 try {
243 java.lang.reflect.Method getCause =
244 t.getClass().getMethod("getCause", (Class<?>[]) null);
245 ret = (Throwable)getCause.invoke(t, (Object[]) null);
246
247 } catch (Exception e) {
248 // OK.
249 // it must be older than 1.4.
250 }
251 return (ret != null) ? ret: t;
252 }
253
254
255 /**
256 * Name of the attribute that specifies the size of a notification
257 * buffer for a connector server. The default value is 1000.
258 */
259 public static final String BUFFER_SIZE_PROPERTY =
260 "jmx.remote.x.notification.buffer.size";
261
262
263 /**
264 * Returns the size of a notification buffer for a connector server.
265 * The default value is 1000.
266 */
267 public static int getNotifBufferSize(Map<String, ?> env) {
268 int defaultQueueSize = 1000; // default value
269
270 // keep it for the compability for the fix:
271 // 6174229: Environment parameter should be notification.buffer.size
272 // instead of buffer.size
273 final String oldP = "jmx.remote.x.buffer.size";
274
275 // the default value re-specified in the system
276 try {
298 if (env.containsKey(BUFFER_SIZE_PROPERTY)) {
299 queueSize = (int)EnvHelp.getIntegerAttribute(env,BUFFER_SIZE_PROPERTY,
300 defaultQueueSize,0,
301 Integer.MAX_VALUE);
302 } else { // try the old one
303 queueSize = (int)EnvHelp.getIntegerAttribute(env,oldP,
304 defaultQueueSize,0,
305 Integer.MAX_VALUE);
306 }
307 } catch (RuntimeException e) {
308 logger.warning("getNotifBufferSize",
309 "Can't determine queuesize (using default): "+
310 e);
311 logger.debug("getNotifBufferSize", e);
312 }
313
314 return queueSize;
315 }
316
317 /**
318 * Name of the attribute that specifies the maximum number of
319 * notifications that a client will fetch from its server. The
320 * value associated with this attribute should be an
321 * {@code Integer} object. The default value is 1000.
322 */
323 public static final String MAX_FETCH_NOTIFS =
324 "jmx.remote.x.notification.fetch.max";
325
326 /**
327 * Returns the maximum notification number which a client will
328 * fetch every time.
329 */
330 public static int getMaxFetchNotifNumber(Map<String, ?> env) {
331 return (int) getIntegerAttribute(env, MAX_FETCH_NOTIFS, 1000, 1,
332 Integer.MAX_VALUE);
333 }
334
335 /**
336 * Name of the attribute that specifies the timeout for a
337 * client to fetch notifications from its server. The value
338 * associated with this attribute should be a <code>Long</code>
339 * object. The default value is 60000 milliseconds.
340 */
341 public static final String FETCH_TIMEOUT =
342 "jmx.remote.x.notification.fetch.timeout";
343
344 /**
345 * Returns the timeout for a client to fetch notifications.
346 */
347 public static long getFetchTimeout(Map<String, ?> env) {
348 return getIntegerAttribute(env, FETCH_TIMEOUT, 60000L, 0,
349 Long.MAX_VALUE);
350 }
351
352 /**
353 * Name of the attribute that specifies an object that will check
354 * accesses to add/removeNotificationListener and also attempts to
355 * receive notifications. The value associated with this attribute
356 * should be a <code>NotificationAccessController</code> object.
357 * The default value is null.
358 * <p>
359 * This field is not public because of its com.sun dependency.
360 */
361 public static final String NOTIF_ACCESS_CONTROLLER =
362 "com.sun.jmx.remote.notification.access.controller";
363
364 public static NotificationAccessController getNotificationAccessController(
365 Map<String, ?> env) {
366 return (env == null) ? null :
367 (NotificationAccessController) env.get(NOTIF_ACCESS_CONTROLLER);
368 }
369
370 /**
371 * Get an integer-valued attribute with name <code>name</code>
372 * from <code>env</code>. If <code>env</code> is null, or does
373 * not contain an entry for <code>name</code>, return
374 * <code>defaultValue</code>. The value may be a Number, or it
375 * may be a String that is parsable as a long. It must be at
376 * least <code>minValue</code> and at most<code>maxValue</code>.
377 *
378 * @throws IllegalArgumentException if <code>env</code> contains
613 else
614 nextPrefix = sentinelKey;
615 }
616 }
617 }
618
619 private static void parseHiddenAttributes(String hide,
620 SortedSet<String> hiddenStrings,
621 SortedSet<String> hiddenPrefixes) {
622 final StringTokenizer tok = new StringTokenizer(hide);
623 while (tok.hasMoreTokens()) {
624 String s = tok.nextToken();
625 if (s.endsWith("*"))
626 hiddenPrefixes.add(s.substring(0, s.length() - 1));
627 else
628 hiddenStrings.add(s);
629 }
630 }
631
632 /**
633 * Name of the attribute that specifies the timeout to keep a
634 * server side connection after answering last client request.
635 * The default value is 120000 milliseconds.
636 */
637 public static final String SERVER_CONNECTION_TIMEOUT =
638 "jmx.remote.x.server.connection.timeout";
639
640 /**
641 * Returns the server side connection timeout.
642 */
643 public static long getServerConnectionTimeout(Map<String, ?> env) {
644 return getIntegerAttribute(env, SERVER_CONNECTION_TIMEOUT, 120000L,
645 0, Long.MAX_VALUE);
646 }
647
648 /**
649 * Name of the attribute that specifies the period in
650 * millisecond for a client to check its connection. The default
651 * value is 60000 milliseconds.
652 */
653 public static final String CLIENT_CONNECTION_CHECK_PERIOD =
654 "jmx.remote.x.client.connection.check.period";
655
656 /**
657 * Returns the client connection check period.
658 */
659 public static long getConnectionCheckPeriod(Map<String, ?> env) {
660 return getIntegerAttribute(env, CLIENT_CONNECTION_CHECK_PERIOD, 60000L,
661 0, Long.MAX_VALUE);
662 }
663
664 /**
665 * Computes a boolean value from a string value retrieved from a
666 * property in the given map.
667 *
668 * @param stringBoolean the string value that must be converted
669 * into a boolean value.
670 *
671 * @return
724 return false;
725 else
726 throw new IllegalArgumentException(
727 "Property value must be \"true\" or \"false\" instead of \"" +
728 stringBoolean + "\"");
729 }
730
731 /**
732 * Converts a map into a valid hash table, i.e.
733 * it removes all the 'null' values from the map.
734 */
735 public static <K, V> Hashtable<K, V> mapToHashtable(Map<K, V> map) {
736 HashMap<K, V> m = new HashMap<K, V>(map);
737 if (m.containsKey(null)) m.remove(null);
738 for (Iterator<?> i = m.values().iterator(); i.hasNext(); )
739 if (i.next() == null) i.remove();
740 return new Hashtable<K, V>(m);
741 }
742
743 /**
744 * Name of the attribute that specifies whether a connector server
745 * should not prevent the VM from exiting
746 */
747 public static final String JMX_SERVER_DAEMON = "jmx.remote.x.daemon";
748
749 /**
750 * Returns true if {@value JMX_SERVER_DAEMON} is specified in the {@code env}
751 * as a key and its value is a String and it is equal to true ignoring case.
752 *
753 * @param env
754 * @return
755 */
756 public static boolean isServerDaemon(Map<String, ?> env) {
757 return (env != null) &&
758 ("true".equalsIgnoreCase((String)env.get(JMX_SERVER_DAEMON)));
759 }
760
761 private static final class SinkOutputStream extends OutputStream {
762 public void write(byte[] b, int off, int len) {}
763 public void write(int b) {}
764 }
765
766 private static final ClassLogger logger =
767 new ClassLogger("javax.management.remote.misc", "EnvHelp");
768 }
|