Skip to content

Package: LogManagerProperties

LogManagerProperties

nameinstructionbranchcomplexitylinemethod
LogManagerProperties(Properties, String)
M: 15 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
checkLogManagerAccess()
M: 28 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 15 C: 0
0%
M: 1 C: 0
0%
checkLoggingAccess()
M: 31 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 12 C: 0
0%
M: 1 C: 0
0%
clone()
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
containsKey(Object)
M: 29 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
equals(Object)
M: 25 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
exportCopy(Properties)
M: 13 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
findClass(String)
M: 41 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
fromLogManager(String)
M: 34 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 14 C: 0
0%
M: 1 C: 0
0%
get(Object)
M: 31 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
getClassLoaders()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getLocalHost(Object)
M: 36 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
getProperty(String)
M: 50 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
getProperty(String, String)
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getZonedDateTime(LogRecord)
M: 69 C: 0
0%
M: 12 C: 0
0%
M: 7 C: 0
0%
M: 19 C: 0
0%
M: 1 C: 0
0%
hasLogManager()
M: 11 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
hashCode()
M: 11 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
isReflectionClass(String)
M: 35 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
isStaticUtilityClass(String)
M: 48 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
loadLogManager()
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
newComparator(String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
newErrorManager(String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
newFilter(String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
newFormatter(String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
newObjectFrom(String, Class)
M: 49 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
paramOrError(InvocationTargetException)
M: 16 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
parseDurationToMillis(CharSequence)
M: 73 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 14 C: 0
0%
M: 1 C: 0
0%
preWrite(Object)
M: 12 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
propertyNames()
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
put(Object, Object)
M: 26 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
readConfiguration()
M: 33 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 12 C: 0
0%
M: 1 C: 0
0%
reflectionClassNames()
M: 102 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 14 C: 0
0%
M: 1 C: 0
0%
remove(Object)
M: 14 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
reverseOrder(Comparator)
M: 54 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 19 C: 0
0%
M: 1 C: 0
0%
setProperty(String, String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 102 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 28 C: 0
0%
M: 1 C: 0
0%
toLanguageTag(Locale)
M: 87 C: 0
0%
M: 12 C: 0
0%
M: 7 C: 0
0%
M: 17 C: 0
0%
M: 1 C: 0
0%
tryLoad(String, ClassLoader)
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
wrapOrThrow(ExceptionInInitializerError)
M: 11 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
writeReplace()
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 2009, 2023 Oracle and/or its affiliates. All rights reserved.
3: * Copyright (c) 2009, 2023 Jason Mehrens. All rights reserved.
4: *
5: * This program and the accompanying materials are made available under the
6: * terms of the Eclipse Public License v. 2.0, which is available at
7: * http://www.eclipse.org/legal/epl-2.0.
8: *
9: * This Source Code may also be made available under the following Secondary
10: * Licenses when the conditions for such availability set forth in the
11: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
12: * version 2 with the GNU Classpath Exception, which is available at
13: * https://www.gnu.org/software/classpath/license.html.
14: *
15: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
16: */
17:
18: package org.eclipse.angus.mail.util.logging;
19:
20: import java.io.*;
21: import java.lang.reflect.InvocationTargetException;
22: import java.lang.reflect.Method;
23: import java.lang.reflect.Modifier;
24: import java.lang.reflect.UndeclaredThrowableException;
25: import java.security.AccessController;
26: import java.security.PrivilegedAction;
27: import java.util.*;
28: import java.util.logging.*;
29: import java.util.logging.Formatter;
30:
31: /**
32: * An adapter class to allow the Mail API to access the LogManager properties.
33: * The LogManager properties are treated as the root of all properties. First,
34: * the parent properties are searched. If no value is found, then, the
35: * LogManager is searched with prefix value. If not found, then, just the key
36: * itself is searched in the LogManager. If a value is found in the LogManager
37: * it is then copied to this properties object with no key prefix. If no value
38: * is found in the LogManager or the parent properties, then this properties
39: * object is searched only by passing the key value.
40: *
41: * <p>
42: * This class also emulates the LogManager functions for creating new objects
43: * from string class names. This is to support initial setup of objects such as
44: * log filters, formatters, error managers, etc.
45: *
46: * <p>
47: * This class should never be exposed outside of this package. Keep this class
48: * package private (default access).
49: *
50: * @author Jason Mehrens
51: * @since JavaMail 1.4.3
52: */
53: final class LogManagerProperties extends Properties {
54:
55: /**
56: * Generated serial id.
57: */
58: private static final long serialVersionUID = -2239983349056806252L;
59: /**
60: * Holds the method used to get the LogRecord instant if running on JDK 9 or
61: * later.
62: */
63: private static final Method LR_GET_INSTANT;
64:
65: /**
66: * Holds the method used to get the default time zone if running on JDK 9 or
67: * later.
68: */
69: private static final Method ZI_SYSTEM_DEFAULT;
70:
71: /**
72: * Holds the method used to convert and instant to a zoned date time if
73: * running on JDK 9 later.
74: */
75: private static final Method ZDT_OF_INSTANT;
76:
77: static {
78: Method lrgi = null;
79: Method zisd = null;
80: Method zdtoi = null;
81: try {
82: lrgi = LogRecord.class.getMethod("getInstant");
83: assert Comparable.class
84:• .isAssignableFrom(lrgi.getReturnType()) : lrgi;
85: zisd = findClass("java.time.ZoneId")
86: .getMethod("systemDefault");
87:• if (!Modifier.isStatic(zisd.getModifiers())) {
88: throw new NoSuchMethodException(zisd.toString());
89: }
90:
91: zdtoi = findClass("java.time.ZonedDateTime")
92: .getMethod("ofInstant", findClass("java.time.Instant"),
93: findClass("java.time.ZoneId"));
94:• if (!Modifier.isStatic(zdtoi.getModifiers())) {
95: throw new NoSuchMethodException(zdtoi.toString());
96: }
97:
98:• if (!Comparable.class.isAssignableFrom(zdtoi.getReturnType())) {
99: throw new NoSuchMethodException(zdtoi.toString());
100: }
101: } catch (final RuntimeException ignore) {
102: } catch (final Exception ignore) { //No need for specific catch.
103: } catch (final LinkageError ignore) {
104: } finally {
105:• if (lrgi == null || zisd == null || zdtoi == null) {
106: lrgi = null; //If any are null then clear all.
107: zisd = null;
108: zdtoi = null;
109: }
110: }
111:
112: LR_GET_INSTANT = lrgi;
113: ZI_SYSTEM_DEFAULT = zisd;
114: ZDT_OF_INSTANT = zdtoi;
115: }
116: /**
117: * Caches the read only reflection class names string array. Declared
118: * volatile for safe publishing only. The VO_VOLATILE_REFERENCE_TO_ARRAY
119: * warning is a false positive.
120: */
121: @SuppressWarnings("VolatileArrayField")
122: private static volatile String[] REFLECT_NAMES;
123: /**
124: * Caches the LogManager or Properties so we only read the configuration
125: * once.
126: */
127: private static final Object LOG_MANAGER = loadLogManager();
128:
129: /**
130: * Get the LogManager or loads a Properties object to use as the LogManager.
131: *
132: * @return the LogManager or a loaded Properties object.
133: * @since JavaMail 1.5.3
134: */
135: private static Object loadLogManager() {
136: Object m;
137: try {
138: m = LogManager.getLogManager();
139: } catch (final LinkageError restricted) {
140: m = readConfiguration();
141: } catch (final RuntimeException unexpected) {
142: m = readConfiguration();
143: }
144: return m;
145: }
146:
147: /**
148: * Create a properties object from the default logging configuration file.
149: * Since the LogManager is not available in restricted environments, only
150: * the default configuration is applicable.
151: *
152: * @return a properties object loaded with the default configuration.
153: * @since JavaMail 1.5.3
154: */
155: private static Properties readConfiguration() {
156: /**
157: * Load the properties file so the default settings are available when
158: * user code creates a logging object. The class loader for the
159: * restricted LogManager can't access these classes to attach them to a
160: * logger or handler on startup. Creating logging objects at this point
161: * is both useless and risky.
162: */
163: final Properties props = new Properties();
164: try {
165: String n = System.getProperty("java.util.logging.config.file");
166:• if (n != null) {
167: final File f = new File(n).getCanonicalFile();
168: final InputStream in = new FileInputStream(f);
169: try {
170: props.load(in);
171: } finally {
172: in.close();
173: }
174: }
175: } catch (final RuntimeException permissionsOrMalformed) {
176: } catch (final Exception ioe) {
177: } catch (final LinkageError unexpected) {
178: }
179: return props;
180: }
181:
182: /**
183: * Gets LogManger property for the running JVM. If the LogManager doesn't
184: * exist then the default LogManger properties are used.
185: *
186: * @param name the property name.
187: * @return the LogManager.
188: * @throws NullPointerException if the given name is null.
189: * @since JavaMail 1.5.3
190: */
191: static String fromLogManager(final String name) {
192:• if (name == null) {
193: throw new NullPointerException();
194: }
195:
196: final Object m = LOG_MANAGER;
197: try {
198:• if (m instanceof Properties) {
199: return ((Properties) m).getProperty(name);
200: }
201: } catch (final RuntimeException unexpected) {
202: }
203:
204:• if (m != null) {
205: try {
206:• if (m instanceof LogManager) {
207: return ((LogManager) m).getProperty(name);
208: }
209: } catch (final LinkageError restricted) {
210: } catch (final RuntimeException unexpected) {
211: }
212: }
213: return null;
214: }
215:
216: /**
217: * Check that the current context is trusted to modify the logging
218: * configuration. This requires LoggingPermission("control").
219: * @throws SecurityException if a security manager exists and the caller
220: * does not have {@code LoggingPermission("control")}.
221: * @since JavaMail 1.5.3
222: */
223: static void checkLogManagerAccess() {
224: boolean checked = false;
225: final Object m = LOG_MANAGER;
226:• if (m != null) {
227: try {
228:• if (m instanceof LogManager) {
229: checked = true;
230: ((LogManager) m).checkAccess();
231: }
232: } catch (final SecurityException notAllowed) {
233:• if (checked) {
234: throw notAllowed;
235: }
236: } catch (final LinkageError restricted) {
237: } catch (final RuntimeException unexpected) {
238: }
239: }
240:
241:• if (!checked) {
242: checkLoggingAccess();
243: }
244: }
245:
246: /**
247: * Check that the current context is trusted to modify the logging
248: * configuration when the LogManager is not present. This requires
249: * LoggingPermission("control").
250: * @throws SecurityException if a security manager exists and the caller
251: * does not have {@code LoggingPermission("control")}.
252: * @since JavaMail 1.5.3
253: */
254: private static void checkLoggingAccess() {
255: /**
256: * Some environments selectively enforce logging permissions by allowing
257: * access to loggers but not allowing access to handlers. This is an
258: * indirect way of checking for LoggingPermission when the LogManager is
259: * not present. The root logger will lazy create handlers so the global
260: * logger is used instead as it is a known named logger with well
261: * defined behavior. If the global logger is a subclass then fallback to
262: * using the SecurityManager.
263: */
264: boolean checked = false;
265: final Logger global = Logger.getLogger("global");
266: try {
267:• if (Logger.class == global.getClass()) {
268: global.removeHandler((Handler) null);
269: checked = true;
270: }
271: } catch (final NullPointerException unexpected) {
272: }
273:
274:• if (!checked) {
275: final SecurityManager sm = System.getSecurityManager();
276:• if (sm != null) {
277: sm.checkPermission(new LoggingPermission("control", null));
278: }
279: }
280: }
281:
282: /**
283: * Determines if access to the {@code java.util.logging.LogManager} class is
284: * restricted by the class loader.
285: *
286: * @return true if a LogManager is present.
287: * @since JavaMail 1.5.3
288: */
289: static boolean hasLogManager() {
290: final Object m = LOG_MANAGER;
291:• return m != null && !(m instanceof Properties);
292: }
293:
294: /**
295: * Gets the ZonedDateTime from the given log record.
296: *
297: * @param record used to generate the zoned date time.
298: * @return null if LogRecord doesn't support nanoseconds otherwise a new
299: * zoned date time is returned.
300: * @throws NullPointerException if record is null.
301: * @since JavaMail 1.5.6
302: */
303: @SuppressWarnings("UseSpecificCatch")
304: static Comparable<?> getZonedDateTime(LogRecord record) {
305:• if (record == null) {
306: throw new NullPointerException();
307: }
308: final Method m = ZDT_OF_INSTANT;
309:• if (m != null) {
310: try {
311: return (Comparable<?>) m.invoke((Object) null,
312: LR_GET_INSTANT.invoke(record),
313: ZI_SYSTEM_DEFAULT.invoke((Object) null));
314: } catch (final RuntimeException ignore) {
315:• assert LR_GET_INSTANT != null
316: && ZI_SYSTEM_DEFAULT != null : ignore;
317: } catch (final InvocationTargetException ite) {
318: final Throwable cause = ite.getCause();
319:• if (cause instanceof Error) {
320: throw (Error) cause;
321:• } else if (cause instanceof RuntimeException) {
322: throw (RuntimeException) cause;
323: } else { //Should never happen.
324: throw new UndeclaredThrowableException(ite);
325: }
326: } catch (final Exception ignore) {
327: }
328: }
329: return null;
330: }
331:
332: /**
333: * Gets the local host name from the given service.
334: *
335: * @param s the service to examine.
336: * @return the local host name or null.
337: * @throws IllegalAccessException if the method is inaccessible.
338: * @throws InvocationTargetException if the method throws an exception.
339: * @throws LinkageError if the linkage fails.
340: * @throws NullPointerException if the given service is null.
341: * @throws ExceptionInInitializerError if the static initializer fails.
342: * @throws Exception if there is a problem.
343: * @throws NoSuchMethodException if the given service does not have a method
344: * to get the local host name as a string.
345: * @throws SecurityException if unable to inspect properties of object.
346: * @since JavaMail 1.5.3
347: */
348: static String getLocalHost(final Object s) throws Exception {
349: try {
350: final Method m = s.getClass().getMethod("getLocalHost");
351:• if (!Modifier.isStatic(m.getModifiers())
352:• && m.getReturnType() == String.class) {
353: return (String) m.invoke(s);
354: } else {
355: throw new NoSuchMethodException(m.toString());
356: }
357: } catch (final ExceptionInInitializerError EIIE) {
358: throw wrapOrThrow(EIIE);
359: } catch (final InvocationTargetException ite) {
360: throw paramOrError(ite);
361: }
362: }
363:
364: /**
365: * Used to parse an ISO-8601 duration format of {@code PnDTnHnMn.nS}.
366: *
367: * @param value an ISO-8601 duration character sequence.
368: * @return the number of milliseconds parsed from the duration.
369: * @throws ClassNotFoundException if the java.time classes are not present.
370: * @throws IllegalAccessException if the method is inaccessible.
371: * @throws InvocationTargetException if the method throws an exception.
372: * @throws LinkageError if the linkage fails.
373: * @throws NullPointerException if the given duration is null.
374: * @throws ExceptionInInitializerError if the static initializer fails.
375: * @throws Exception if there is a problem.
376: * @throws NoSuchMethodException if the correct time methods are missing.
377: * @throws SecurityException if reflective access to the java.time classes
378: * are not allowed.
379: * @since JavaMail 1.5.5
380: */
381: static long parseDurationToMillis(final CharSequence value) throws Exception {
382: try {
383: final Class<?> k = findClass("java.time.Duration");
384: final Method parse = k.getMethod("parse", CharSequence.class);
385:• if (!k.isAssignableFrom(parse.getReturnType())
386:• || !Modifier.isStatic(parse.getModifiers())) {
387: throw new NoSuchMethodException(parse.toString());
388: }
389:
390: final Method toMillis = k.getMethod("toMillis");
391:• if (!Long.TYPE.isAssignableFrom(toMillis.getReturnType())
392:• || Modifier.isStatic(toMillis.getModifiers())) {
393: throw new NoSuchMethodException(toMillis.toString());
394: }
395: return (Long) toMillis.invoke(parse.invoke(null, value));
396: } catch (final ExceptionInInitializerError EIIE) {
397: throw wrapOrThrow(EIIE);
398: } catch (final InvocationTargetException ite) {
399: throw paramOrError(ite);
400: }
401: }
402:
403: /**
404: * Converts a locale to a language tag.
405: *
406: * @param locale the locale to convert.
407: * @return the language tag.
408: * @throws NullPointerException if the given locale is null.
409: * @since JavaMail 1.4.5
410: */
411: static String toLanguageTag(final Locale locale) {
412: final String l = locale.getLanguage();
413: final String c = locale.getCountry();
414: final String v = locale.getVariant();
415: final char[] b = new char[l.length() + c.length() + v.length() + 2];
416: int count = l.length();
417: l.getChars(0, count, b, 0);
418:• if (c.length() != 0 || (l.length() != 0 && v.length() != 0)) {
419: b[count] = '-';
420: ++count; //be nice to the client compiler.
421: c.getChars(0, c.length(), b, count);
422: count += c.length();
423: }
424:
425:• if (v.length() != 0 && (l.length() != 0 || c.length() != 0)) {
426: b[count] = '-';
427: ++count; //be nice to the client compiler.
428: v.getChars(0, v.length(), b, count);
429: count += v.length();
430: }
431: return String.valueOf(b, 0, count);
432: }
433:
434: /**
435: * Creates a new filter from the given class name.
436: *
437: * @param name the fully qualified class name.
438: * @return a new filter.
439: * @throws ClassCastException if class name does not match the type.
440: * @throws ClassNotFoundException if the class name was not found.
441: * @throws IllegalAccessException if the constructor is inaccessible.
442: * @throws InstantiationException if the given class name is abstract.
443: * @throws InvocationTargetException if the constructor throws an exception.
444: * @throws LinkageError if the linkage fails.
445: * @throws ExceptionInInitializerError if the static initializer fails.
446: * @throws Exception to match the error method of the ErrorManager.
447: * @throws NoSuchMethodException if the class name does not have a no
448: * argument constructor.
449: * @since JavaMail 1.4.5
450: */
451: static Filter newFilter(String name) throws Exception {
452: return newObjectFrom(name, Filter.class);
453: }
454:
455: /**
456: * Creates a new formatter from the given class name.
457: *
458: * @param name the fully qualified class name.
459: * @return a new formatter.
460: * @throws ClassCastException if class name does not match the type.
461: * @throws ClassNotFoundException if the class name was not found.
462: * @throws IllegalAccessException if the constructor is inaccessible.
463: * @throws InstantiationException if the given class name is abstract.
464: * @throws InvocationTargetException if the constructor throws an exception.
465: * @throws LinkageError if the linkage fails.
466: * @throws ExceptionInInitializerError if the static initializer fails.
467: * @throws Exception to match the error method of the ErrorManager.
468: * @throws NoSuchMethodException if the class name does not have a no
469: * argument constructor.
470: * @since JavaMail 1.4.5
471: */
472: static Formatter newFormatter(String name) throws Exception {
473: return newObjectFrom(name, Formatter.class);
474: }
475:
476: /**
477: * Creates a new log record comparator from the given class name.
478: *
479: * @param name the fully qualified class name.
480: * @return a new comparator.
481: * @throws ClassCastException if class name does not match the type.
482: * @throws ClassNotFoundException if the class name was not found.
483: * @throws IllegalAccessException if the constructor is inaccessible.
484: * @throws InstantiationException if the given class name is abstract.
485: * @throws InvocationTargetException if the constructor throws an exception.
486: * @throws LinkageError if the linkage fails.
487: * @throws ExceptionInInitializerError if the static initializer fails.
488: * @throws Exception to match the error method of the ErrorManager.
489: * @throws NoSuchMethodException if the class name does not have a no
490: * argument constructor.
491: * @since JavaMail 1.4.5
492: * @see java.util.logging.LogRecord
493: */
494: @SuppressWarnings("unchecked")
495: static Comparator<? super LogRecord> newComparator(String name) throws Exception {
496: return newObjectFrom(name, Comparator.class);
497: }
498:
499: /**
500: * Returns a comparator that imposes the reverse ordering of the specified
501: * {@link Comparator}. If the given comparator declares a public
502: * reverseOrder method that method is called first and the return value is
503: * used. If that method is not declared or the caller does not have access
504: * then a comparator wrapping the given comparator is returned.
505: *
506: * @param <T> the element type to be compared
507: * @param c a comparator whose ordering is to be reversed by the returned
508: * comparator
509: * @return A comparator that imposes the reverse ordering of the specified
510: * comparator.
511: * @throws NullPointerException if the given comparator is null.
512: * @since JavaMail 1.5.0
513: */
514: @SuppressWarnings({"unchecked", "ThrowableResultIgnored"})
515: static <T> Comparator<T> reverseOrder(final Comparator<T> c) {
516:• if (c == null) {
517: throw new NullPointerException();
518: }
519:
520: Comparator<T> reverse = null;
521: //Comparator in Java 1.8 has 'reversed' as a default method.
522: //This code calls that method first to allow custom
523: //code to define what reverse order means.
524: try {
525: //assert Modifier.isPublic(c.getClass().getModifiers()) :
526: // Modifier.toString(c.getClass().getModifiers());
527: final Method m = c.getClass().getMethod("reversed");
528:• if (!Modifier.isStatic(m.getModifiers())
529:• && Comparator.class.isAssignableFrom(m.getReturnType())) {
530: try {
531: reverse = (Comparator<T>) m.invoke(c);
532: } catch (final ExceptionInInitializerError eiie) {
533: throw wrapOrThrow(eiie);
534: }
535: }
536: } catch (final NoSuchMethodException ignore) {
537: } catch (final IllegalAccessException ignore) {
538: } catch (final RuntimeException ignore) {
539: } catch (final InvocationTargetException ite) {
540: paramOrError(ite); //Ignore invocation bugs (returned values).
541: }
542:
543:• if (reverse == null) {
544: reverse = Collections.reverseOrder(c);
545: }
546: return reverse;
547: }
548:
549: /**
550: * Creates a new error manager from the given class name.
551: *
552: * @param name the fully qualified class name.
553: * @return a new error manager.
554: * @throws ClassCastException if class name does not match the type.
555: * @throws ClassNotFoundException if the class name was not found.
556: * @throws IllegalAccessException if the constructor is inaccessible.
557: * @throws InstantiationException if the given class name is abstract.
558: * @throws InvocationTargetException if the constructor throws an exception.
559: * @throws LinkageError if the linkage fails.
560: * @throws ExceptionInInitializerError if the static initializer fails.
561: * @throws Exception to match the error method of the ErrorManager.
562: * @throws NoSuchMethodException if the class name does not have a no
563: * argument constructor.
564: * @since JavaMail 1.4.5
565: */
566: static ErrorManager newErrorManager(String name) throws Exception {
567: return newObjectFrom(name, ErrorManager.class);
568: }
569:
570: /**
571: * Determines if the given class name identifies a utility class.
572: *
573: * @param name the fully qualified class name.
574: * @return true if the given class name
575: * @throws ClassNotFoundException if the class name was not found.
576: * @throws IllegalAccessException if the constructor is inaccessible.
577: * @throws LinkageError if the linkage fails.
578: * @throws ExceptionInInitializerError if the static initializer fails.
579: * @throws Exception to match the error method of the ErrorManager.
580: * @throws SecurityException if unable to inspect properties of class.
581: * @since JavaMail 1.5.2
582: */
583: static boolean isStaticUtilityClass(String name) throws Exception {
584: final Class<?> c = findClass(name);
585: final Class<?> obj = Object.class;
586: Method[] methods;
587: boolean util;
588:• if (c != obj && (methods = c.getMethods()).length != 0) {
589: util = true;
590:• for (Method m : methods) {
591:• if (m.getDeclaringClass() != obj
592:• && !Modifier.isStatic(m.getModifiers())) {
593: util = false;
594: break;
595: }
596: }
597: } else {
598: util = false;
599: }
600: return util;
601: }
602:
603: /**
604: * Determines if the given class name is a reflection class name responsible
605: * for invoking methods and or constructors.
606: *
607: * @param name the fully qualified class name.
608: * @return true if the given class name
609: * @throws ClassNotFoundException if the class name was not found.
610: * @throws IllegalAccessException if the constructor is inaccessible.
611: * @throws LinkageError if the linkage fails.
612: * @throws ExceptionInInitializerError if the static initializer fails.
613: * @throws Exception to match the error method of the ErrorManager.
614: * @throws SecurityException if unable to inspect properties of class.
615: * @since JavaMail 1.5.2
616: */
617: static boolean isReflectionClass(String name) throws Exception {
618: String[] names = REFLECT_NAMES;
619:• if (names == null) { //Benign data race.
620: REFLECT_NAMES = names = reflectionClassNames();
621: }
622:
623:• for (String rf : names) { //The set of names is small.
624:• if (name.equals(rf)) {
625: return true;
626: }
627: }
628:
629: findClass(name); //Fail late instead of normal return.
630: return false;
631: }
632:
633: /**
634: * Determines all of the reflection class names used to invoke methods.
635: *
636: * This method performs indirect and direct calls on a throwable to capture
637: * the standard class names and the implementation class names.
638: *
639: * @return a string array containing the fully qualified class names.
640: * @throws Exception if there is a problem.
641: */
642: private static String[] reflectionClassNames() throws Exception {
643: final Class<?> thisClass = LogManagerProperties.class;
644:• assert Modifier.isFinal(thisClass.getModifiers()) : thisClass;
645: try {
646: final HashSet<String> traces = new HashSet<>();
647: Throwable t = Throwable.class.getConstructor().newInstance();
648:• for (StackTraceElement ste : t.getStackTrace()) {
649:• if (!thisClass.getName().equals(ste.getClassName())) {
650: traces.add(ste.getClassName());
651: } else {
652: break;
653: }
654: }
655:
656: Throwable.class.getMethod("fillInStackTrace").invoke(t);
657:• for (StackTraceElement ste : t.getStackTrace()) {
658:• if (!thisClass.getName().equals(ste.getClassName())) {
659: traces.add(ste.getClassName());
660: } else {
661: break;
662: }
663: }
664: return traces.toArray(new String[traces.size()]);
665: } catch (final InvocationTargetException ITE) {
666: throw paramOrError(ITE);
667: }
668: }
669:
670: /**
671: * Creates a new object from the given class name.
672: *
673: * @param <T> The generic class type.
674: * @param name the fully qualified class name.
675: * @param type the assignable type for the given name.
676: * @return a new object assignable to the given type.
677: * @throws ClassCastException if class name does not match the type.
678: * @throws ClassNotFoundException if the class name was not found.
679: * @throws IllegalAccessException if the constructor is inaccessible.
680: * @throws InstantiationException if the given class name is abstract.
681: * @throws InvocationTargetException if the constructor throws an exception.
682: * @throws LinkageError if the linkage fails.
683: * @throws ExceptionInInitializerError if the static initializer fails.
684: * @throws Exception to match the error method of the ErrorManager.
685: * @throws NoSuchMethodException if the class name does not have a no
686: * argument constructor.
687: * @since JavaMail 1.4.5
688: */
689: static <T> T newObjectFrom(String name, Class<T> type) throws Exception {
690: try {
691: final Class<?> clazz = LogManagerProperties.findClass(name);
692: //This check avoids additional side effects when the name parameter
693: //is a literal name and not a class name.
694:• if (type.isAssignableFrom(clazz)) {
695: try {
696: return type.cast(clazz.getConstructor().newInstance());
697: } catch (final InvocationTargetException ITE) {
698: throw paramOrError(ITE);
699: }
700: } else {
701: throw new ClassCastException(clazz.getName()
702: + " cannot be cast to " + type.getName());
703: }
704: } catch (final NoClassDefFoundError NCDFE) {
705: //No class def found can occur on filesystems that are
706: //case insensitive (BUG ID 6196068). In some cases, we allow class
707: //names or literal names, this code guards against the case where a
708: //literal name happens to match a class name in a different case.
709: //This is also a nice way to adapt this error for the error manager.
710: throw new ClassNotFoundException(NCDFE.toString(), NCDFE);
711: } catch (final ExceptionInInitializerError EIIE) {
712: throw wrapOrThrow(EIIE);
713: }
714: }
715:
716: /**
717: * Returns the given exception or throws the escaping cause.
718: *
719: * @param ite any invocation target.
720: * @return the exception.
721: * @throws VirtualMachineError if present as cause.
722: * @throws ThreadDeath if present as cause.
723: * @since JavaMail 1.4.5
724: */
725: private static Exception paramOrError(InvocationTargetException ite) {
726: final Throwable cause = ite.getCause();
727:• if (cause != null) {
728: //Bitwise inclusive OR produces tighter bytecode for instanceof
729: //and matches with multicatch syntax.
730:• if (cause instanceof VirtualMachineError
731: | cause instanceof ThreadDeath) {
732: throw (Error) cause;
733: }
734: }
735: return ite;
736: }
737:
738: /**
739: * Throws the given error if the cause is an error otherwise the given error
740: * is wrapped.
741: *
742: * @param eiie the error.
743: * @return an InvocationTargetException.
744: * @since JavaMail 1.5.0
745: */
746: private static InvocationTargetException wrapOrThrow(
747: ExceptionInInitializerError eiie) {
748: //This linkage error will escape the constructor new instance call.
749: //If the cause is an error, rethrow to skip any error manager.
750:• if (eiie.getCause() instanceof Error) {
751: throw eiie;
752: } else {
753: //Considered a bug in the code, wrap the error so it can be
754: //reported to the error manager.
755: return new InvocationTargetException(eiie);
756: }
757: }
758:
759: /**
760: * This code is modified from the LogManager, which explictly states
761: * searching the system class loader first, then the context class loader.
762: * There is resistance (compatibility) to change this behavior to simply
763: * searching the context class loader.
764: *
765: * @param name full class name
766: * @return the class.
767: * @throws LinkageError if the linkage fails.
768: * @throws ClassNotFoundException if the class name was not found.
769: * @throws ExceptionInInitializerError if static initializer fails.
770: */
771: private static Class<?> findClass(String name) throws ClassNotFoundException {
772: ClassLoader[] loaders = getClassLoaders();
773:• assert loaders.length == 2 : loaders.length;
774: Class<?> clazz;
775:• if (loaders[0] != null) {
776: try {
777: clazz = Class.forName(name, false, loaders[0]);
778: } catch (ClassNotFoundException tryContext) {
779: clazz = tryLoad(name, loaders[1]);
780: }
781: } else {
782: clazz = tryLoad(name, loaders[1]);
783: }
784: return clazz;
785: }
786:
787: /**
788: * Loads a class using the given loader or the class loader of this class.
789: *
790: * @param name the class name.
791: * @param l any class loader or null.
792: * @return the raw class.
793: * @throws ClassNotFoundException if not found.
794: */
795: private static Class<?> tryLoad(String name, ClassLoader l) throws ClassNotFoundException {
796:• if (l != null) {
797: return Class.forName(name, false, l);
798: } else {
799: return Class.forName(name);
800: }
801: }
802:
803: /**
804: * Gets the class loaders using elevated privileges.
805: *
806: * @return any array of class loaders. Indexes may be null.
807: */
808: private static ClassLoader[] getClassLoaders() {
809: return AccessController.doPrivileged(new PrivilegedAction<ClassLoader[]>() {
810:
811: @SuppressWarnings("override") //JDK-6954234
812: public ClassLoader[] run() {
813: final ClassLoader[] loaders = new ClassLoader[2];
814: try {
815: loaders[0] = ClassLoader.getSystemClassLoader();
816: } catch (SecurityException ignore) {
817: loaders[0] = null;
818: }
819:
820: try {
821: loaders[1] = Thread.currentThread().getContextClassLoader();
822: } catch (SecurityException ignore) {
823: loaders[1] = null;
824: }
825: return loaders;
826: }
827: });
828: }
829: /**
830: * The namespace prefix to search LogManager and defaults.
831: */
832: private final String prefix;
833:
834: /**
835: * Creates a log manager properties object.
836: *
837: * @param parent the parent properties.
838: * @param prefix the namespace prefix.
839: * @throws NullPointerException if <code>prefix</code> or
840: * <code>parent</code> is <code>null</code>.
841: */
842: LogManagerProperties(final Properties parent, final String prefix) {
843: super(parent);
844:• if (parent == null || prefix == null) {
845: throw new NullPointerException();
846: }
847: this.prefix = prefix;
848: }
849:
850: /**
851: * Returns a properties object that contains a snapshot of the current
852: * state. This method violates the clone contract so that no instances of
853: * LogManagerProperties is exported for public use.
854: *
855: * @return the snapshot.
856: * @since JavaMail 1.4.4
857: */
858: @Override
859: @SuppressWarnings("CloneDoesntCallSuperClone")
860: public synchronized Object clone() {
861: return exportCopy(defaults);
862: }
863:
864: /**
865: * Searches defaults, then searches the log manager if available or the
866: * system properties by the prefix property, and then by the key itself.
867: *
868: * @param key a non null key.
869: * @return the value for that key.
870: */
871: @Override
872: public synchronized String getProperty(final String key) {
873: String value = defaults.getProperty(key);
874:• if (value == null) {
875:• if (key.length() > 0) {
876: value = fromLogManager(prefix + '.' + key);
877: }
878:
879:• if (value == null) {
880: value = fromLogManager(key);
881: }
882:
883: /**
884: * Copy the log manager properties as we read them. If a value is no
885: * longer present in the LogManager read it from here. The reason
886: * this works is because LogManager.reset() closes all attached
887: * handlers therefore, stale values only exist in closed handlers.
888: */
889:• if (value != null) {
890: super.put(key, value);
891: } else {
892: Object v = super.get(key); //defaults are not used.
893:• value = v instanceof String ? (String) v : null;
894: }
895: }
896: return value;
897: }
898:
899: /**
900: * Calls getProperty directly. If getProperty returns null the default value
901: * is returned.
902: *
903: * @param key a key to search for.
904: * @param def the default value to use if not found.
905: * @return the value for the key.
906: * @since JavaMail 1.4.4
907: */
908: @Override
909: public String getProperty(final String key, final String def) {
910: final String value = this.getProperty(key);
911:• return value == null ? def : value;
912: }
913:
914: /**
915: * Required to work with PropUtil. Calls getProperty directly if the given
916: * key is a string. Otherwise, performs a get operation on the defaults
917: * followed by the normal hash table get.
918: *
919: * @param key any key.
920: * @return the value for the key or null.
921: * @since JavaMail 1.4.5
922: */
923: @Override
924: public synchronized Object get(final Object key) {
925: Object value;
926:• if (key instanceof String) {
927: value = getProperty((String) key);
928: } else {
929: value = null;
930: }
931:
932: //Search for non-string value.
933:• if (value == null) {
934: value = defaults.get(key);
935:• if (value == null && !defaults.containsKey(key)) {
936: value = super.get(key);
937: }
938: }
939: return value;
940: }
941:
942: /**
943: * Required to work with PropUtil. An updated copy of the key is fetched
944: * from the log manager if the key doesn't exist in this properties.
945: *
946: * @param key any key.
947: * @return the value for the key or the default value for the key.
948: * @since JavaMail 1.4.5
949: */
950: @Override
951: public synchronized Object put(final Object key, final Object value) {
952:• if (key instanceof String && value instanceof String) {
953: final Object def = preWrite(key);
954: final Object man = super.put(key, value);
955:• return man == null ? def : man;
956: } else {
957: return super.put(key, value);
958: }
959: }
960:
961: /**
962: * Calls the put method directly.
963: *
964: * @param key any key.
965: * @return the value for the key or the default value for the key.
966: * @since JavaMail 1.4.5
967: */
968: @Override
969: public Object setProperty(String key, String value) {
970: return this.put(key, value);
971: }
972:
973: /**
974: * Required to work with PropUtil. An updated copy of the key is fetched
975: * from the log manager prior to returning.
976: *
977: * @param key any key.
978: * @return the value for the key or null.
979: * @since JavaMail 1.4.5
980: */
981: @Override
982: public synchronized boolean containsKey(final Object key) {
983:• boolean found = key instanceof String
984:• && getProperty((String) key) != null;
985:• if (!found) {
986:• found = defaults.containsKey(key) || super.containsKey(key);
987: }
988: return found;
989: }
990:
991: /**
992: * Required to work with PropUtil. An updated copy of the key is fetched
993: * from the log manager if the key doesn't exist in this properties.
994: *
995: * @param key any key.
996: * @return the value for the key or the default value for the key.
997: * @since JavaMail 1.4.5
998: */
999: @Override
1000: public synchronized Object remove(final Object key) {
1001: final Object def = preWrite(key);
1002: final Object man = super.remove(key);
1003:• return man == null ? def : man;
1004: }
1005:
1006: /**
1007: * It is assumed that this method will never be called. No way to get the
1008: * property names from LogManager.
1009: *
1010: * @return the property names
1011: */
1012: @Override
1013: public Enumeration<?> propertyNames() {
1014: assert false;
1015: return super.propertyNames();
1016: }
1017:
1018: /**
1019: * It is assumed that this method will never be called. The prefix value is
1020: * not used for the equals method.
1021: *
1022: * @param o any object or null.
1023: * @return true if equal, otherwise false.
1024: */
1025: @Override
1026: public boolean equals(final Object o) {
1027:• if (o == null) {
1028: return false;
1029: }
1030:• if (o == this) {
1031: return true;
1032: }
1033:• if (o instanceof Properties == false) {
1034: return false;
1035: }
1036: assert false : prefix;
1037: return super.equals(o);
1038: }
1039:
1040: /**
1041: * It is assumed that this method will never be called. See equals.
1042: *
1043: * @return the hash code.
1044: */
1045: @Override
1046: public int hashCode() {
1047: assert false : prefix.hashCode();
1048: return super.hashCode();
1049: }
1050:
1051: /**
1052: * Called before a write operation of a key. Caches a key read from the log
1053: * manager in this properties object. The key is only cached if it is an
1054: * instance of a String and this properties doesn't contain a copy of the
1055: * key.
1056: *
1057: * @param key the key to search.
1058: * @return the default value for the key.
1059: */
1060: private Object preWrite(final Object key) {
1061:• assert Thread.holdsLock(this);
1062: return get(key);
1063: }
1064:
1065: /**
1066: * Creates a public snapshot of this properties object using the given
1067: * parent properties.
1068: *
1069: * @param parent the defaults to use with the snapshot.
1070: * @return the safe snapshot.
1071: */
1072: private Properties exportCopy(final Properties parent) {
1073: Thread.holdsLock(this);
1074: final Properties child = new Properties(parent);
1075: child.putAll(this);
1076: return child;
1077: }
1078:
1079: /**
1080: * It is assumed that this method will never be called. We return a safe
1081: * copy for export to avoid locking this properties object or the defaults
1082: * during write.
1083: *
1084: * @return the parent properties.
1085: * @throws ObjectStreamException if there is a problem.
1086: */
1087: private synchronized Object writeReplace() throws ObjectStreamException {
1088: assert false;
1089: return exportCopy((Properties) defaults.clone());
1090: }
1091: }