< prev index next >

src/java.logging/share/classes/java/util/logging/LogManager.java

Print this page




  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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package java.util.logging;
  28 
  29 import java.io.*;
  30 import java.util.*;
  31 import java.security.*;
  32 import java.lang.ref.ReferenceQueue;
  33 import java.lang.ref.WeakReference;
  34 import java.util.concurrent.ConcurrentHashMap;

  35 import java.util.concurrent.CopyOnWriteArrayList;
  36 import java.util.concurrent.locks.ReentrantLock;






  37 import sun.misc.JavaAWTAccess;
  38 import sun.misc.ManagedLocalsThread;
  39 import sun.misc.SharedSecrets;
  40 
  41 /**
  42  * There is a single global LogManager object that is used to
  43  * maintain a set of shared state about Loggers and log services.
  44  * <p>
  45  * This LogManager object:
  46  * <ul>
  47  * <li> Manages a hierarchical namespace of Logger objects.  All
  48  *      named Loggers are stored in this namespace.
  49  * <li> Manages a set of logging control properties.  These are
  50  *      simple key-value pairs that can be used by Handlers and
  51  *      other logging objects to configure themselves.
  52  * </ul>
  53  * <p>
  54  * The global LogManager object can be retrieved using LogManager.getLogManager().
  55  * The LogManager object is created during class initialization and
  56  * cannot subsequently be changed.


 771                     return false;
 772                 }
 773             }
 774 
 775             // We're adding a new logger.
 776             // Note that we are creating a weak reference here.
 777             final LogManager owner = getOwner();
 778             logger.setLogManager(owner);
 779             ref = owner.new LoggerWeakRef(logger);
 780 
 781             // Apply any initial level defined for the new logger, unless
 782             // the logger's level is already initialized
 783             Level level = owner.getLevelProperty(name + ".level", null);
 784             if (level != null && !logger.isLevelInitialized()) {
 785                 doSetLevel(logger, level);
 786             }
 787 
 788             // instantiation of the handler is done in the LogManager.addLogger
 789             // implementation as a handler class may be only visible to LogManager
 790             // subclass for the custom log manager case
 791             processParentHandlers(logger, name);
 792 
 793             // Find the new node and its parent.
 794             LogNode node = getNode(name);
 795             node.loggerRef = ref;
 796             Logger parent = null;
 797             LogNode nodep = node.parent;
 798             while (nodep != null) {
 799                 LoggerWeakRef nodeRef = nodep.loggerRef;
 800                 if (nodeRef != null) {
 801                     parent = nodeRef.get();
 802                     if (parent != null) {
 803                         break;
 804                     }
 805                 }
 806                 nodep = nodep.parent;
 807             }
 808 
 809             if (parent != null) {
 810                 doSetParent(logger, parent);
 811             }


 819             // soon as it is published in namedLoggers (findLogger takes
 820             // benefit of the ConcurrentHashMap implementation of namedLoggers
 821             // to avoid synchronizing on retrieval when that is possible).
 822             namedLoggers.put(name, ref);
 823             return true;
 824         }
 825 
 826         void removeLoggerRef(String name, LoggerWeakRef ref) {
 827             namedLoggers.remove(name, ref);
 828         }
 829 
 830         synchronized Enumeration<String> getLoggerNames() {
 831             // ensure that this context is properly initialized before
 832             // returning logger names.
 833             ensureInitialized();
 834             return Collections.enumeration(namedLoggers.keySet());
 835         }
 836 
 837         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
 838         // parents have levels or handlers defined, make sure they are instantiated.
 839         private void processParentHandlers(final Logger logger, final String name) {

 840             final LogManager owner = getOwner();
 841             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 842                 @Override
 843                 public Void run() {
 844                     if (logger != owner.rootLogger) {
 845                         boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
 846                         if (!useParent) {
 847                             logger.setUseParentHandlers(false);
 848                         }
 849                     }
 850                     return null;
 851                 }
 852             });
 853 
 854             int ix = 1;
 855             for (;;) {
 856                 int ix2 = name.indexOf('.', ix);
 857                 if (ix2 < 0) {
 858                     break;
 859                 }
 860                 String pname = name.substring(0, ix2);
 861                 if (owner.getProperty(pname + ".level") != null ||
 862                     owner.getProperty(pname + ".handlers") != null) {
 863                     // This pname has a level/handlers definition.
 864                     // Make sure it exists.
 865                     demandLogger(pname, null, null);


 866                 }
 867                 ix = ix2+1;
 868             }
 869         }
 870 
 871         // Gets a node in our tree of logger nodes.
 872         // If necessary, create it.
 873         LogNode getNode(String name) {
 874             if (name == null || name.equals("")) {
 875                 return root;
 876             }
 877             LogNode node = root;
 878             while (name.length() > 0) {
 879                 int ix = name.indexOf('.');
 880                 String head;
 881                 if (ix > 0) {
 882                     head = name.substring(0, ix);
 883                     name = name.substring(ix + 1);
 884                 } else {
 885                     head = name;


 925                         // the other Logger is not holding a strong reference to
 926                         // the other Logger, then it is possible for the other
 927                         // Logger to be GC'ed after we saw it in addLogger() and
 928                         // before we can refetch it. If it has been GC'ed then
 929                         // we'll just loop around and try again.
 930                         result = findLogger(name);
 931                     }
 932                 } while (result == null);
 933             }
 934             return result;
 935         }
 936     }
 937 
 938     // Add new per logger handlers.
 939     // We need to raise privilege here. All our decisions will
 940     // be made based on the logging configuration, which can
 941     // only be modified by trusted code.
 942     private void loadLoggerHandlers(final Logger logger, final String name,
 943                                     final String handlersPropertyName)
 944     {
 945         AccessController.doPrivileged(new PrivilegedAction<Object>() {
 946             @Override
 947             public Object run() {
 948                 String names[] = parseClassNames(handlersPropertyName);
 949                 final boolean ensureCloseOnReset = names.length > 0
 950                     && getBooleanProperty(handlersPropertyName + ".ensureCloseOnReset",true);



 951 






 952                 int count = 0;













 953                 for (String type : names) {
 954                     try {
 955                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(type);
 956                         Handler hdl = (Handler) clz.newInstance();
 957                         // Check if there is a property defining the
 958                         // this handler's level.
 959                         String levs = getProperty(type + ".level");
 960                         if (levs != null) {
 961                             Level l = Level.findLevel(levs);
 962                             if (l != null) {
 963                                 hdl.setLevel(l);
 964                             } else {
 965                                 // Probably a bad level. Drop through.
 966                                 System.err.println("Can't set level for " + type);
 967                             }
 968                         }
 969                         // Add this Handler to the logger
 970                         logger.addHandler(hdl);
 971                         if (++count == 1 && ensureCloseOnReset) {
 972                             // add this logger to the closeOnResetLoggers list.
 973                             closeOnResetLoggers.addIfAbsent(CloseOnReset.create(logger));
 974                         }
 975                     } catch (Exception ex) {
 976                         System.err.println("Can't load log handler \"" + type + "\"");
 977                         System.err.println("" + ex);
 978                         ex.printStackTrace();
 979                     }
 980                 }
 981 
 982                 return null;
 983             }
 984         });
 985     }
 986 
 987 
 988     // loggerRefQueue holds LoggerWeakRef objects for Logger objects
 989     // that have been GC'ed.
 990     private final ReferenceQueue<Logger> loggerRefQueue
 991         = new ReferenceQueue<>();
 992 
 993     // Package-level inner class.
 994     // Helper class for managing WeakReferences to Logger objects.
 995     //
 996     // LogManager.namedLoggers
 997     //     - has weak references to all named Loggers
 998     //     - namedLoggers keeps the LoggerWeakRef objects for the named
 999     //       Loggers around until we can deal with the book keeping for
1000     //       the named Logger that is being GC'ed.
1001     // LogManager.LogNode.loggerRef
1002     //     - has a weak reference to a named Logger
1003     //     - the LogNode will also keep the LoggerWeakRef objects for
1004     //       the named Loggers around; currently LogNodes never go away.


1237      *
1238      * @return  enumeration of logger name strings
1239      */
1240     public Enumeration<String> getLoggerNames() {
1241         return getUserContext().getLoggerNames();
1242     }
1243 
1244     /**
1245      * Reinitialize the logging properties and reread the logging configuration.
1246      * <p>
1247      * The same rules are used for locating the configuration properties
1248      * as are used at startup.  So normally the logging properties will
1249      * be re-read from the same file that was used at startup.
1250      * <P>
1251      * Any log level definitions in the new configuration file will be
1252      * applied using Logger.setLevel(), if the target Logger exists.
1253      * <p>
1254      * Any {@linkplain #addConfigurationListener registered configuration
1255      * listener} will be invoked after the properties are read.
1256      *











1257      * @exception  SecurityException  if a security manager exists and if
1258      *             the caller does not have LoggingPermission("control").
1259      * @exception  IOException if there are IO problems reading the configuration.
1260      */
1261     public void readConfiguration() throws IOException, SecurityException {
1262         checkPermission();
1263 
1264         // if a configuration class is specified, load it and use it.
1265         String cname = System.getProperty("java.util.logging.config.class");
1266         if (cname != null) {
1267             try {
1268                 // Instantiate the named class.  It is its constructor's
1269                 // responsibility to initialize the logging configuration, by
1270                 // calling readConfiguration(InputStream) with a suitable stream.
1271                 try {
1272                     Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
1273                     clz.newInstance();
1274                     return;
1275                 } catch (ClassNotFoundException ex) {
1276                     Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
1277                     clz.newInstance();
1278                     return;
1279                 }
1280             } catch (Exception ex) {
1281                 System.err.println("Logging configuration class \"" + cname + "\" failed");
1282                 System.err.println("" + ex);
1283                 // keep going and useful config file.
1284             }
1285         }
1286 








1287         String fname = System.getProperty("java.util.logging.config.file");
1288         if (fname == null) {
1289             fname = System.getProperty("java.home");
1290             if (fname == null) {
1291                 throw new Error("Can't find java.home ??");
1292             }
1293             File f = new File(fname, "conf");
1294             f = new File(f, "logging.properties");
1295             fname = f.getCanonicalPath();
1296         }
1297         try (final InputStream in = new FileInputStream(fname)) {
1298             final BufferedInputStream bin = new BufferedInputStream(in);
1299             readConfiguration(bin);
1300         }

1301     }
1302 
1303     /**
1304      * Reset the logging configuration.
1305      * <p>
1306      * For all named loggers, the reset operation removes and closes
1307      * all Handlers and (except for the root logger) sets the level
1308      * to null.  The root logger's level is set to Level.INFO.
1309      *
1310      * @exception  SecurityException  if a security manager exists and if
1311      *             the caller does not have LoggingPermission("control").
1312      */
1313 
1314     public void reset() throws SecurityException {
1315         checkPermission();
1316 
1317         List<CloseOnReset> persistent;
1318 
1319         // We don't want reset() and readConfiguration()
1320         // to run in parallel


1412             String word = hands.substring(ix, end);
1413             ix = end+1;
1414             word = word.trim();
1415             if (word.length() == 0) {
1416                 continue;
1417             }
1418             result.add(word);
1419         }
1420         return result.toArray(new String[result.size()]);
1421     }
1422 
1423     /**
1424      * Reinitialize the logging properties and reread the logging configuration
1425      * from the given stream, which should be in java.util.Properties format.
1426      * Any {@linkplain #addConfigurationListener registered configuration
1427      * listener} will be invoked after the properties are read.
1428      * <p>
1429      * Any log level definitions in the new configuration file will be
1430      * applied using Logger.setLevel(), if the target Logger exists.
1431      *











1432      * @param ins       stream to read properties from
1433      * @exception  SecurityException  if a security manager exists and if
1434      *             the caller does not have LoggingPermission("control").
1435      * @exception  IOException if there are problems reading from the stream.
1436      */
1437     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
1438         checkPermission();
1439 
1440         // We don't want reset() and readConfiguration() to run
1441         // in parallel.
1442         configurationLock.lock();
1443         try {
1444             if (globalHandlersState == STATE_SHUTDOWN) {
1445                 // already in terminal state: don't even bother
1446                 // to read the configuration
1447                 return;
1448             }
1449 
1450             // change state to STATE_READING_CONFIG to signal reset() to not change it
1451             globalHandlersState = STATE_READING_CONFIG;


1489                 // Note that we need to reinitialize global handles when
1490                 // they are first referenced.
1491                 globalHandlersState = STATE_UNINITIALIZED;
1492             } catch (Throwable t) {
1493                 // If there were any trouble, then set state to STATE_INITIALIZED
1494                 // so that no global handlers reinitialization is performed on not fully
1495                 // initialized configuration.
1496                 globalHandlersState = STATE_INITIALIZED;
1497                 // re-throw
1498                 throw t;
1499             }
1500         } finally {
1501             configurationLock.unlock();
1502         }
1503 
1504         // should be called out of lock to avoid dead-lock situations
1505         // when user code is involved
1506         invokeConfigurationListeners();
1507     }
1508 












































































































































































































































































































































































































































































































































































1509     /**
1510      * Get the value of a logging property.
1511      * The method returns null if the property is not found.
1512      * @param name      property name
1513      * @return          property value
1514      */
1515     public String getProperty(String name) {
1516         return props.getProperty(name);
1517     }
1518 
1519     // Package private method to get a String property.
1520     // If the property is not defined we return the given
1521     // default value.
1522     String getStringProperty(String name, String defaultValue) {
1523         String val = getProperty(name);
1524         if (val == null) {
1525             return defaultValue;
1526         }
1527         return val.trim();
1528     }




  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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package java.util.logging;
  28 
  29 import java.io.*;
  30 import java.util.*;
  31 import java.security.*;
  32 import java.lang.ref.ReferenceQueue;
  33 import java.lang.ref.WeakReference;
  34 import java.util.concurrent.ConcurrentHashMap;
  35 import java.nio.file.Paths;
  36 import java.util.concurrent.CopyOnWriteArrayList;
  37 import java.util.concurrent.locks.ReentrantLock;
  38 import java.util.function.BiFunction;
  39 import java.util.function.BiPredicate;
  40 import java.util.function.Function;
  41 import java.util.function.Predicate;
  42 import java.util.stream.Collectors;
  43 import java.util.stream.Stream;
  44 import sun.misc.JavaAWTAccess;
  45 import sun.misc.ManagedLocalsThread;
  46 import sun.misc.SharedSecrets;
  47 
  48 /**
  49  * There is a single global LogManager object that is used to
  50  * maintain a set of shared state about Loggers and log services.
  51  * <p>
  52  * This LogManager object:
  53  * <ul>
  54  * <li> Manages a hierarchical namespace of Logger objects.  All
  55  *      named Loggers are stored in this namespace.
  56  * <li> Manages a set of logging control properties.  These are
  57  *      simple key-value pairs that can be used by Handlers and
  58  *      other logging objects to configure themselves.
  59  * </ul>
  60  * <p>
  61  * The global LogManager object can be retrieved using LogManager.getLogManager().
  62  * The LogManager object is created during class initialization and
  63  * cannot subsequently be changed.


 778                     return false;
 779                 }
 780             }
 781 
 782             // We're adding a new logger.
 783             // Note that we are creating a weak reference here.
 784             final LogManager owner = getOwner();
 785             logger.setLogManager(owner);
 786             ref = owner.new LoggerWeakRef(logger);
 787 
 788             // Apply any initial level defined for the new logger, unless
 789             // the logger's level is already initialized
 790             Level level = owner.getLevelProperty(name + ".level", null);
 791             if (level != null && !logger.isLevelInitialized()) {
 792                 doSetLevel(logger, level);
 793             }
 794 
 795             // instantiation of the handler is done in the LogManager.addLogger
 796             // implementation as a handler class may be only visible to LogManager
 797             // subclass for the custom log manager case
 798             processParentHandlers(logger, name, VisitedLoggers.of(null));
 799 
 800             // Find the new node and its parent.
 801             LogNode node = getNode(name);
 802             node.loggerRef = ref;
 803             Logger parent = null;
 804             LogNode nodep = node.parent;
 805             while (nodep != null) {
 806                 LoggerWeakRef nodeRef = nodep.loggerRef;
 807                 if (nodeRef != null) {
 808                     parent = nodeRef.get();
 809                     if (parent != null) {
 810                         break;
 811                     }
 812                 }
 813                 nodep = nodep.parent;
 814             }
 815 
 816             if (parent != null) {
 817                 doSetParent(logger, parent);
 818             }


 826             // soon as it is published in namedLoggers (findLogger takes
 827             // benefit of the ConcurrentHashMap implementation of namedLoggers
 828             // to avoid synchronizing on retrieval when that is possible).
 829             namedLoggers.put(name, ref);
 830             return true;
 831         }
 832 
 833         void removeLoggerRef(String name, LoggerWeakRef ref) {
 834             namedLoggers.remove(name, ref);
 835         }
 836 
 837         synchronized Enumeration<String> getLoggerNames() {
 838             // ensure that this context is properly initialized before
 839             // returning logger names.
 840             ensureInitialized();
 841             return Collections.enumeration(namedLoggers.keySet());
 842         }
 843 
 844         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
 845         // parents have levels or handlers defined, make sure they are instantiated.
 846         private void processParentHandlers(final Logger logger, final String name,
 847                 BiPredicate<Logger,String> visited) {
 848             final LogManager owner = getOwner();
 849             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 850                 @Override
 851                 public Void run() {
 852                     if (logger != owner.rootLogger) {
 853                         boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
 854                         if (!useParent) {
 855                             logger.setUseParentHandlers(false);
 856                         }
 857                     }
 858                     return null;
 859                 }
 860             });
 861 
 862             int ix = 1;
 863             for (;;) {
 864                 int ix2 = name.indexOf('.', ix);
 865                 if (ix2 < 0) {
 866                     break;
 867                 }
 868                 String pname = name.substring(0, ix2);
 869                 if (owner.getProperty(pname + ".level") != null ||
 870                     owner.getProperty(pname + ".handlers") != null) {
 871                     // This pname has a level/handlers definition.
 872                     // Make sure it exists.
 873                     if (visited.test(demandLogger(pname, null, null), pname)) {
 874                         break;
 875                     }
 876                 }
 877                 ix = ix2+1;
 878             }
 879         }
 880 
 881         // Gets a node in our tree of logger nodes.
 882         // If necessary, create it.
 883         LogNode getNode(String name) {
 884             if (name == null || name.equals("")) {
 885                 return root;
 886             }
 887             LogNode node = root;
 888             while (name.length() > 0) {
 889                 int ix = name.indexOf('.');
 890                 String head;
 891                 if (ix > 0) {
 892                     head = name.substring(0, ix);
 893                     name = name.substring(ix + 1);
 894                 } else {
 895                     head = name;


 935                         // the other Logger is not holding a strong reference to
 936                         // the other Logger, then it is possible for the other
 937                         // Logger to be GC'ed after we saw it in addLogger() and
 938                         // before we can refetch it. If it has been GC'ed then
 939                         // we'll just loop around and try again.
 940                         result = findLogger(name);
 941                     }
 942                 } while (result == null);
 943             }
 944             return result;
 945         }
 946     }
 947 
 948     // Add new per logger handlers.
 949     // We need to raise privilege here. All our decisions will
 950     // be made based on the logging configuration, which can
 951     // only be modified by trusted code.
 952     private void loadLoggerHandlers(final Logger logger, final String name,
 953                                     final String handlersPropertyName)
 954     {
 955         AccessController.doPrivileged(new PrivilegedAction<Void>() {
 956             @Override
 957             public Void run() {
 958                 setLoggerHandlers(logger, name, handlersPropertyName,
 959                     createLoggerHandlers(name, handlersPropertyName));
 960                 return null;
 961             }
 962         });
 963     }
 964 
 965     private void setLoggerHandlers(final Logger logger, final String name,
 966                                    final String handlersPropertyName,
 967                                    List<Handler> handlers)
 968     {
 969         final boolean ensureCloseOnReset = ! handlers.isEmpty()
 970                     && getBooleanProperty(handlersPropertyName + ".ensureCloseOnReset",true);
 971         int count = 0;
 972         for (Handler hdl : handlers) {
 973             logger.addHandler(hdl);
 974             if (++count == 1 && ensureCloseOnReset) {
 975                 // add this logger to the closeOnResetLoggers list.
 976                 closeOnResetLoggers.addIfAbsent(CloseOnReset.create(logger));
 977             }
 978         }
 979     }
 980 
 981     private List<Handler> createLoggerHandlers(final String name, final String handlersPropertyName)
 982     {
 983         String names[] = parseClassNames(handlersPropertyName);
 984         List<Handler> handlers = new ArrayList<>(names.length);
 985         for (String type : names) {
 986             try {
 987                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(type);
 988                 Handler hdl = (Handler) clz.newInstance();
 989                 // Check if there is a property defining the
 990                 // this handler's level.
 991                 String levs = getProperty(type + ".level");
 992                 if (levs != null) {
 993                     Level l = Level.findLevel(levs);
 994                     if (l != null) {
 995                         hdl.setLevel(l);
 996                     } else {
 997                         // Probably a bad level. Drop through.
 998                         System.err.println("Can't set level for " + type);
 999                     }
1000                 }
1001                 // Add this Handler to the logger
1002                 handlers.add(hdl);




1003             } catch (Exception ex) {
1004                 System.err.println("Can't load log handler \"" + type + "\"");
1005                 System.err.println("" + ex);
1006                 ex.printStackTrace();
1007             }
1008         }
1009 
1010         return handlers;


1011     }
1012 
1013 
1014     // loggerRefQueue holds LoggerWeakRef objects for Logger objects
1015     // that have been GC'ed.
1016     private final ReferenceQueue<Logger> loggerRefQueue
1017         = new ReferenceQueue<>();
1018 
1019     // Package-level inner class.
1020     // Helper class for managing WeakReferences to Logger objects.
1021     //
1022     // LogManager.namedLoggers
1023     //     - has weak references to all named Loggers
1024     //     - namedLoggers keeps the LoggerWeakRef objects for the named
1025     //       Loggers around until we can deal with the book keeping for
1026     //       the named Logger that is being GC'ed.
1027     // LogManager.LogNode.loggerRef
1028     //     - has a weak reference to a named Logger
1029     //     - the LogNode will also keep the LoggerWeakRef objects for
1030     //       the named Loggers around; currently LogNodes never go away.


1263      *
1264      * @return  enumeration of logger name strings
1265      */
1266     public Enumeration<String> getLoggerNames() {
1267         return getUserContext().getLoggerNames();
1268     }
1269 
1270     /**
1271      * Reinitialize the logging properties and reread the logging configuration.
1272      * <p>
1273      * The same rules are used for locating the configuration properties
1274      * as are used at startup.  So normally the logging properties will
1275      * be re-read from the same file that was used at startup.
1276      * <P>
1277      * Any log level definitions in the new configuration file will be
1278      * applied using Logger.setLevel(), if the target Logger exists.
1279      * <p>
1280      * Any {@linkplain #addConfigurationListener registered configuration
1281      * listener} will be invoked after the properties are read.
1282      *
1283      * @apiNote {@code readConfiguration} is principally useful for
1284      *    establishing the LogManager primordial configuration.
1285      *    <p>
1286      *    Calling this method directly from the application code after the
1287      *    LogManager has been initialized is discouraged.
1288      *
1289      *    Applications that wish to update the LogManager
1290      *    configuration after the LogManager has been initialized should
1291      *    call {@link #updateConfiguration(java.util.function.Function)}
1292      *    instead.
1293      *
1294      * @exception  SecurityException  if a security manager exists and if
1295      *             the caller does not have LoggingPermission("control").
1296      * @exception  IOException if there are IO problems reading the configuration.
1297      */
1298     public void readConfiguration() throws IOException, SecurityException {
1299         checkPermission();
1300 
1301         // if a configuration class is specified, load it and use it.
1302         String cname = System.getProperty("java.util.logging.config.class");
1303         if (cname != null) {
1304             try {
1305                 // Instantiate the named class.  It is its constructor's
1306                 // responsibility to initialize the logging configuration, by
1307                 // calling readConfiguration(InputStream) with a suitable stream.
1308                 try {
1309                     Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
1310                     clz.newInstance();
1311                     return;
1312                 } catch (ClassNotFoundException ex) {
1313                     Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
1314                     clz.newInstance();
1315                     return;
1316                 }
1317             } catch (Exception ex) {
1318                 System.err.println("Logging configuration class \"" + cname + "\" failed");
1319                 System.err.println("" + ex);
1320                 // keep going and useful config file.
1321             }
1322         }
1323 
1324         String fname = getConfigurationFileName();
1325         try (final InputStream in = new FileInputStream(fname)) {
1326             final BufferedInputStream bin = new BufferedInputStream(in);
1327             readConfiguration(bin);
1328         }
1329     }
1330 
1331     String getConfigurationFileName() throws IOException {
1332         String fname = System.getProperty("java.util.logging.config.file");
1333         if (fname == null) {
1334             fname = System.getProperty("java.home");
1335             if (fname == null) {
1336                 throw new Error("Can't find java.home ??");
1337             }
1338             fname = Paths.get(fname, "conf", "logging.properties")
1339                     .toAbsolutePath().normalize().toString();





1340         }
1341         return fname;
1342     }
1343 
1344     /**
1345      * Reset the logging configuration.
1346      * <p>
1347      * For all named loggers, the reset operation removes and closes
1348      * all Handlers and (except for the root logger) sets the level
1349      * to null.  The root logger's level is set to Level.INFO.
1350      *
1351      * @exception  SecurityException  if a security manager exists and if
1352      *             the caller does not have LoggingPermission("control").
1353      */
1354 
1355     public void reset() throws SecurityException {
1356         checkPermission();
1357 
1358         List<CloseOnReset> persistent;
1359 
1360         // We don't want reset() and readConfiguration()
1361         // to run in parallel


1453             String word = hands.substring(ix, end);
1454             ix = end+1;
1455             word = word.trim();
1456             if (word.length() == 0) {
1457                 continue;
1458             }
1459             result.add(word);
1460         }
1461         return result.toArray(new String[result.size()]);
1462     }
1463 
1464     /**
1465      * Reinitialize the logging properties and reread the logging configuration
1466      * from the given stream, which should be in java.util.Properties format.
1467      * Any {@linkplain #addConfigurationListener registered configuration
1468      * listener} will be invoked after the properties are read.
1469      * <p>
1470      * Any log level definitions in the new configuration file will be
1471      * applied using Logger.setLevel(), if the target Logger exists.
1472      *
1473      * @apiNote {@code readConfiguration} is principally useful for applications
1474      *    which use the {@code "java.util.logging.config.class"} property
1475      *    to establish their own custom configuration.
1476      *    <p>
1477      *    Calling this method directly from the application code after the
1478      *    LogManager has been initialized is discouraged.
1479      *    Applications that wish to update the LogManager configuration after
1480      *    the LogManager has been initialized should call
1481      *    {@link #updateConfiguration(java.io.InputStream, java.util.function.Function)}
1482      *    instead.
1483      *
1484      * @param ins       stream to read properties from
1485      * @exception  SecurityException  if a security manager exists and if
1486      *             the caller does not have LoggingPermission("control").
1487      * @exception  IOException if there are problems reading from the stream.
1488      */
1489     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
1490         checkPermission();
1491 
1492         // We don't want reset() and readConfiguration() to run
1493         // in parallel.
1494         configurationLock.lock();
1495         try {
1496             if (globalHandlersState == STATE_SHUTDOWN) {
1497                 // already in terminal state: don't even bother
1498                 // to read the configuration
1499                 return;
1500             }
1501 
1502             // change state to STATE_READING_CONFIG to signal reset() to not change it
1503             globalHandlersState = STATE_READING_CONFIG;


1541                 // Note that we need to reinitialize global handles when
1542                 // they are first referenced.
1543                 globalHandlersState = STATE_UNINITIALIZED;
1544             } catch (Throwable t) {
1545                 // If there were any trouble, then set state to STATE_INITIALIZED
1546                 // so that no global handlers reinitialization is performed on not fully
1547                 // initialized configuration.
1548                 globalHandlersState = STATE_INITIALIZED;
1549                 // re-throw
1550                 throw t;
1551             }
1552         } finally {
1553             configurationLock.unlock();
1554         }
1555 
1556         // should be called out of lock to avoid dead-lock situations
1557         // when user code is involved
1558         invokeConfigurationListeners();
1559     }
1560 
1561     // This enum enumerate the configuration properties that will be
1562     // re-established on existing loggers when the configuration is updated
1563     // with LogManager.updateConfiguration().
1564     //
1565     // Note that this works properly only for the global LogManager - as
1566     // Handler and its subclasses get their configuration from
1567     // LogManager.getLogManager().
1568     //
1569     static enum ConfigurationProperties implements Predicate<String> {
1570         LEVEL(".level"), HANDLERS(".handlers"), USEPARENT(".useParentHandlers");
1571         final String suffix;
1572         final int length;
1573         private ConfigurationProperties(String suffix) {
1574             this.suffix = Objects.requireNonNull(suffix);
1575             length = suffix.length();
1576         }
1577         @Override
1578         public boolean test(String key) {
1579             if (this == HANDLERS && suffix.substring(1).equals(key)) return true;
1580             if (this == HANDLERS && suffix.equals(key)) return false;
1581             return key.endsWith(suffix);
1582         }
1583         String key(String loggerName) {
1584             if (this == HANDLERS && (loggerName == null || loggerName.isEmpty())) {
1585                 return suffix.substring(1);
1586             }
1587             return loggerName + suffix;
1588         }
1589         String loggerName(String key) {
1590             assert key.equals(suffix.substring(1)) && this == HANDLERS || key.endsWith(suffix);
1591             if (this == HANDLERS && suffix.substring(1).equals(key)) return "";
1592             return key.substring(0, key.length() - length);
1593         }
1594 
1595         /**
1596          * If the property is one that should be reestablished by
1597          * updateConfiguration, returns the name of the logger for which the
1598          * property is configured. Otherwise, returns null.
1599          * @param property a property key in 'props'
1600          * @return the name of the logger on which the property is to be set,
1601          *         if the property is one that we should reestablish.
1602          *         {@code null} otherwise.
1603          */
1604         static String getLoggerName(String property) {
1605             for (ConfigurationProperties p : ConfigurationProperties.ALL) {
1606                 if (p.test(property)) {
1607                     return p.loggerName(property);
1608                 }
1609             }
1610             return null; // Not a property that should be reestablished.
1611         }
1612 
1613         /**
1614          * If the property is one that should be reestablished by
1615          * updateConfiguration, returns the corresponding
1616          * ConfigurationProperties object. Otherwise, returns null.
1617          * @param property a property key in 'props'
1618          * @return the corresponding ConfigurationProperties object,
1619          *         if the property is one that we should reestablish.
1620          *         {@code null} otherwise.
1621          */
1622         static ConfigurationProperties of(String property) {
1623             for (ConfigurationProperties p : ConfigurationProperties.ALL) {
1624                 if (p.test(property)) {
1625                     return p;
1626                 }
1627             }
1628             return null; // Not a property that should be reestablished.
1629         }
1630 
1631         /**
1632          * Returns true if the given property is one that should be reestablished.
1633          * Used to filter property name streams.
1634          * @param property a property key from the configuration.
1635          * @return true if this property is of interest for updateConfiguration.
1636          */
1637         static boolean isOf(String property) {
1638             return of(property) != null;
1639         }
1640 
1641         /**
1642          * Returns true if the new property value is different from the old.
1643          * @param k a property key in the configuration
1644          * @param previous the old configuration
1645          * @param next the new configuration
1646          * @return true if the property is changing value between the two
1647          *         configurations.
1648          */
1649         static boolean isChanging(String k, Properties previous, Properties next) {
1650             final String p = trim(previous.getProperty(k, null));
1651             final String n = trim(next.getProperty(k, null));
1652             return ! Objects.equals(p,n);
1653         }
1654 
1655         /**
1656          * Applies the remapping function for the given key to the next
1657          * configuration.
1658          * If the remapping function is null then this method does nothing.
1659          * Otherwise, it calls the remapping function to compute the value
1660          * that should be associated with {@code key} in the resulting
1661          * configuration, and applies it to {@code next}.
1662          * If the remapping function returns {@code null} the key is removed
1663          * from {@code next}.
1664          *
1665          * @param k a property key in the configuration
1666          * @param previous the old configuration
1667          * @param next the new configuration (modified by this function)
1668          * @param remappingFunction the remapping function.
1669          */
1670         static void merge(String k, Properties previous, Properties next,
1671                           BiFunction<String, String, String> remappingFunction) {
1672             if (remappingFunction != null) {
1673                 String p = trim(previous.getProperty(k, null));
1674                 String n = trim(next.getProperty(k, null));
1675                 String mapped = trim(remappingFunction.apply(p,n));
1676                 if (!Objects.equals(n, mapped)) {
1677                     if (mapped == null) {
1678                         next.remove(k);
1679                     } else {
1680                         next.setProperty(k, mapped);
1681                     }
1682                 }
1683             }
1684         }
1685 
1686         private static final EnumSet<ConfigurationProperties> ALL =
1687                 EnumSet.allOf(ConfigurationProperties.class);
1688     }
1689 
1690     // trim the value if not null.
1691     private static String trim(String value) {
1692         return value == null ? null : value.trim();
1693     }
1694 
1695     /**
1696      * An object that keep track of loggers we have already visited.
1697      * Used when updating configuration, to avoid processing the same logger
1698      * twice.
1699      */
1700     static final class VisitedLoggers implements BiPredicate<Logger, String> {
1701         final Map<Logger,String> visited;
1702         private VisitedLoggers(Map<Logger,String> visited) {
1703             this.visited = visited;
1704         }
1705         @Override
1706         public boolean test(Logger logger, String name) {
1707             return visited != null && visited.put(logger, name) != null;
1708         }
1709         public void clear() {
1710             if (visited != null) visited.clear();
1711         }
1712 
1713         public static VisitedLoggers of(IdentityHashMap<Logger, String> visited) {
1714             return visited == null ? NEVER : new VisitedLoggers(visited);
1715         }
1716 
1717         // An object that considers that no logger has ever been visited.
1718         // This is used when processParentHandlers is called from
1719         // LoggerContext.addLocalLogger
1720         static final VisitedLoggers NEVER = new VisitedLoggers(null);
1721     }
1722 
1723 
1724     /**
1725      * Type of the modification for a given property. One of ADDED, CHANGED,
1726      * or REMOVED.
1727      */
1728     static enum ModType {
1729         ADDED,   // property had no value in the old conf, but has one in the new.
1730         CHANGED, // property has a different value in the old conf and the new conf.
1731         REMOVED; // property has no value in the new conf, but had one in the old.
1732         static ModType of(String previous, String next) {
1733             if (previous == null && next != null) {
1734                 return ADDED;
1735             }
1736             if (next == null && previous != null) {
1737                 return REMOVED;
1738             }
1739             if (!Objects.equals(trim(previous), trim(next))) {
1740                 return CHANGED;
1741             }
1742             return null;
1743         }
1744     }
1745 
1746     /**
1747      * Updates an existing configuration.
1748      * <p>
1749      * @implSpec
1750      * This is equivalent to calling:
1751      * <pre>
1752      *   try (final InputStream in = new FileInputStream(&lt;logging.properties&gt;)) {
1753      *       final BufferedInputStream bin = new BufferedInputStream(in);
1754      *       updateConfiguration(bin, mapper);
1755      *   }
1756      * </pre>
1757      * where {@code <logging.properties>} is the logging configuration file path.
1758      * <p>
1759      * Note that this method not take into account the value of the
1760      * {@code "java.util.logging.config.class"} property.
1761      * The {@code "java.util.logging.config.file"} system property is read
1762      * to find the logging properties file, whether the
1763      * {@code "java.util.logging.config.class"} property is set or not.
1764      * If the {@code "java.util.logging.config.file"} system property is not
1765      * defined then the default configuration is used.
1766      * The default configuration is typically loaded from the properties file
1767      * "{@code conf/logging.properties}" in the Java installation directory.
1768      *
1769      * @param mapper Used to control how the old configuration and
1770      *   candidate configuration will be mapped into the new configuration.
1771      *   See {@link
1772      *   #updateConfiguration(java.io.InputStream, java.util.function.Function)}
1773      *   for more details.
1774      *
1775      * @throws  SecurityException  if a security manager exists and if
1776      *          the caller does not have LoggingPermission("control"), or
1777      *          does not have the permissions required to set up the
1778      *          configuration (e.g. open file specified for FileHandlers
1779      *          etc...)
1780      *
1781      * @throws  IOException if there are problems reading from the
1782      *          logging configuration file.
1783      */
1784     public void updateConfiguration(Function<String, BiFunction<String,String,String>> mapper)
1785             throws IOException {
1786         checkPermission();
1787         String fname = getConfigurationFileName();
1788         try (final InputStream in = new FileInputStream(fname)) {
1789             final BufferedInputStream bin = new BufferedInputStream(in);
1790             updateConfiguration(bin, mapper);
1791         }
1792     }
1793 
1794     /**
1795      * Update the logging configuration.  The given {@code mapper} function
1796      * is invoked for each configuration key in order to produce a resulting
1797      * logging configuration to to be applied. The result of applying that new
1798      * configuration is detailed in the table below.
1799      * The registered {@linkplain #addConfigurationListener configuration
1800      * listener} will be invoked after the configuration is successfully updated.
1801      * <br>
1802      * <table>
1803      *   <caption>Updating configuration properties</caption>
1804      * <tr>
1805      * <th>Property</th>
1806      * <th>Resulting Behavior</th>
1807      * </tr>
1808      * <tr>
1809      * <td valign="top">{@code <logger>.level}</td>
1810      * <td>
1811      * <ul>
1812      *   <li>If the new configuration defines a level for a logger and
1813      *       if the new level is different than the level specified in the
1814      *       the old configuration, or not specified in
1815      *       the old configuration, then the level for that logger will be
1816      *       updated, and the change propagated to the existing logger children,
1817      *       if necessary.
1818      *   </li>
1819      *   <li>If the old configuration defined a level for a logger, and the new
1820      *       configuration doesn't, then the logger level remains unchanged.
1821      *       To completely replace a configuration - the caller should therefore
1822      *       call {@link #reset() reset} to empty the current configuration, before
1823      *       calling {@code updateConfiguration}.
1824      *   </li>
1825      * </ul>
1826      * </td>
1827      * <tr>
1828      * <td valign="top">{@code <logger>.useParentHandlers}</td>
1829      * <td>
1830      * <ul>
1831      *   <li>If either the new or the old value for the useParentHandlers property
1832      *       is not null, then if the logger exists or if children for
1833      *       that logger exist, that logger will be updated to the new value.
1834      *       The value of the useParentHandlers property is the value specified
1835      *       in the configuration; if not specified, the default is true.
1836      *   </li>
1837      * </ul>
1838      * </td>
1839      * </tr>
1840      * <tr>
1841      * <td valign="top">{@code <logger>.handlers}</td>
1842      * <td>
1843      * <ul>
1844      *   <li>If the new configuration defines a list of handlers for a logger,
1845      *       and if the new list is different than the list specified in the old
1846      *       configuration for that logger (that could be empty), if the logger
1847      *       exists or whose children exist, the handlers associated with that logger
1848      *       are closed and removed and the new handlers will be created per the new
1849      *       configuration and added to that logger.
1850      *   </li>
1851      *   <li>If the old configuration defined some handlers for a logger, and
1852      *       the new configuration doesn't, if that logger exists,
1853      *       its handlers will be removed and closed.
1854      *   </li>
1855      *   <li>Changing the list of handlers on an existing logger will cause all
1856      *       its previous handlers to be removed and closed, regardless of whether
1857      *       they had been created from the configuration or programmatically.
1858      *       The old handlers will be replaced by new handlers, if any.
1859      *   </li>
1860      * </ul>
1861      * </td>
1862      * </tr>
1863      * <tr>
1864      * <td valign="top">{@code <handler-name>.*}</td>
1865      * <td>
1866      * <ul>
1867      *   <li>Properties configured/changed on handler classes will only affect
1868      *       newly created handlers. If a node is configured with the same list
1869      *       of handlers in the old and the new configuration, then these handlers
1870      *       will remain unchanged.
1871      *   </li>
1872      * </ul>
1873      * </td>
1874      * </tr>
1875      * </table>
1876      * <p>
1877      * To completely reestablish a configuration, an application can first call
1878      * {@link #reset() reset} to fully remove the old configuration, followed by
1879      * {@code updateConfiguration} to establish the new configuration.
1880      * <p>
1881      * Note that this method has no special handling for the "config" property.
1882      * The new value provided by the mapper function will be stored in the
1883      * LogManager properties, but {@code updateConfiguration} will not parse its
1884      * value nor instantiate the classes it points to.
1885      *
1886      * @param ins      stream to read properties from
1887      * @param mapper a functional interface that takes a configuration
1888      *            key and returns a remapping function for values associated
1889      *            with that key. The remapping function takes the old value
1890      *            and the candidate new value as parameters and produces the
1891      *            actual value to be applied. If the {@code mapper} is null,
1892      *            or if the remapping function it returns is null, then the
1893      *            candidate value will be the new value.
1894      *            A {@code null} value passed as parameter to the remapping
1895      *            function indicates that no value was present in the
1896      *            corresponding configuration.
1897      *            <p>
1898      *            Examples of {@code mapper} are:
1899      *            <ul><li>{@code (k) -> ((o, n) -> n)}: always take the new value.
1900      *                    equivalent to passing null for {@code mapper}</li>
1901      *                <li>{@code (k) -> ((o, n) -> n == null ? o : n)}: keep the
1902      *                    old value if the candidate configuration has no value
1903      *                    for that key, otherwise take the new value.
1904      *                    This is equivalent to adding the new
1905      *                    configuration to the old, letting new values override
1906      *                    old values, as what would be obtained with
1907      *                    {@code result.putAll(old); result.putAll(candidate)}.
1908      *                </li>
1909      *                <li>{@code (k) -> ((o, n) -> o == null ? n : o)}: only
1910      *                    take the new value if the old configuration didn't
1911      *                    have a value for that key.
1912      *                    This is equivalent to appending the new
1913      *                    configuration to the old, without letting new values
1914      *                    override old values, as what would be obtained with
1915      *                    {@code result.putAll(candidate); result.putAll(old)}.
1916      *                </li>
1917      *                <li>
1918      * <pre>{@code (k) -> k.endsWith(".handlers")}
1919      *      {@code     ? ((o, n) -> (o == null ? n : o))}
1920      *      {@code     : ((o, n) -> n)}</pre> do not let the new configuration
1921      *                 override existing per logger handlers. Only root handlers
1922      *                 can be overridden.</li>
1923      *            </ul>
1924      * @throws  SecurityException if a security manager exists and if
1925      *          the caller does not have LoggingPermission("control"), or
1926      *          does not have the permissions required to set up the
1927      *          configuration (e.g. open files specified for FileHandlers)
1928      *
1929      * @throws  IOException if there are problems reading from the
1930      *          logging configuration file.
1931      */
1932     public void updateConfiguration(InputStream ins,
1933             Function<String, BiFunction<String,String,String>> mapper)
1934             throws IOException {
1935         checkPermission();
1936         ensureLogManagerInitialized();
1937         drainLoggerRefQueueBounded();
1938 
1939         final Properties previous;
1940         final Set<String> updatePropertyNames;
1941         Properties next = new Properties();
1942         next.load(ins);
1943         List<LoggerContext> cxs = Collections.emptyList();
1944         final VisitedLoggers visited = VisitedLoggers.of(new IdentityHashMap<>());
1945 
1946         if (globalHandlersState == STATE_SHUTDOWN) return;
1947         
1948         // exclusive lock: readConfiguration/reset/updateConfiguration can't
1949         //           run concurrently.
1950         // configurationLock.writeLock().lock();
1951         configurationLock.lock();
1952         try {
1953             if (globalHandlersState == STATE_SHUTDOWN) return;
1954             previous = props;
1955 
1956             // Builds a TreeSet of all (old and new) property names.
1957             updatePropertyNames =
1958                     Stream.concat(previous.stringPropertyNames().stream(),
1959                                   next.stringPropertyNames().stream())
1960                         .collect(Collectors.toCollection(TreeSet::new));
1961 
1962             if (mapper != null) {
1963                 // mapper will potentially modify the content of
1964                 // 'next', so we need to call it before affecting props=next.
1965                 // give a chance to the mapper to control all
1966                 // properties - not just those we will reset.
1967                 updatePropertyNames.stream()
1968                         .forEachOrdered(k -> ConfigurationProperties
1969                                 .merge(k, previous, next, mapper.apply(k)));
1970             }
1971 
1972             props = next;
1973 
1974             // allKeys will contain all keys:
1975             //    - which correspond to a configuration property we are interested in
1976             //      (first filter)
1977             //    - whose value is changing (new, removed, different) in the configuration
1978             //      (second filter)
1979             final Stream<String> allKeys = updatePropertyNames.stream()
1980                     .filter(ConfigurationProperties::isOf)
1981                     .filter(k -> ConfigurationProperties.isChanging(k, previous, next));
1982 
1983             // Group configuration properties by logger name
1984             // We use a TreeMap so that parent loggers will be visited before
1985             // child loggers.
1986             final Map<String, TreeSet<String>> loggerConfigs =
1987                     allKeys.collect(
1988                             Collectors.groupingBy(
1989                                     ConfigurationProperties::getLoggerName,
1990                                     TreeMap::new,
1991                                     Collectors.toCollection(TreeSet::new)));
1992 
1993             if (!loggerConfigs.isEmpty()) {
1994                 cxs = contexts();
1995             }
1996             final List<Logger> tmp = cxs.isEmpty()
1997                     ? Collections.emptyList() : new ArrayList<>(cxs.size());
1998             for (Map.Entry<String, TreeSet<String>> e : loggerConfigs.entrySet()) {
1999                 // This can be a logger name, or something else...
2000                 // The only thing we know is that we found a property
2001                 //    we are interested in.
2002                 // For instance, if we found x.y.z.level, then x.y.z could be
2003                 // a logger, but it could also be a handler class...
2004                 // Anyway...
2005                 final String name = e.getKey();
2006                 final Set<String> properties = e.getValue();
2007                 tmp.clear();
2008                 for (LoggerContext cx : cxs) {
2009                     Logger l = cx.findLogger(name);
2010                     if (l == null) continue;
2011                     if (!visited.test(l, name)) {
2012                         tmp.add(l);
2013                     }
2014                 }
2015                 if (tmp.isEmpty()) continue;
2016                 for (String pk : properties) {
2017                     ConfigurationProperties cp = ConfigurationProperties.of(pk);
2018                     String p = previous.getProperty(pk, null);
2019                     String n = next.getProperty(pk, null);
2020 
2021                     // Determines the type of modification.
2022                     ModType mod = ModType.of(p, n);
2023 
2024                     // mod == null means that the two values are equals, there
2025                     // is nothing to do. Usually, this should not happen as such
2026                     // properties should have been filtered above.
2027                     // It could happen however if the properties had
2028                     // trailing/leading whitespaces.
2029                     if (mod == null) continue;
2030 
2031                     switch (cp) {
2032                         case LEVEL:
2033                             if (mod == ModType.REMOVED) continue;
2034                             Level level = Level.findLevel(trim(n));
2035                             if (level == null) {
2036                                 if (name.isEmpty()) {
2037                                     rootLogger.setLevel(level);
2038                                 }
2039                                 for (Logger l : tmp) {
2040                                     if (!name.isEmpty() || l != rootLogger) {
2041                                         l.setLevel(level);
2042                                     }
2043                                 }
2044                             }
2045                             break;
2046                         case USEPARENT:
2047                             if (!name.isEmpty()) {
2048                                 boolean useParent = getBooleanProperty(pk, true);
2049                                 if (n != null || p != null) {
2050                                     // reset the flag only if the previous value
2051                                     // or the new value are not null.
2052                                    for (Logger l : tmp) {
2053                                         l.setUseParentHandlers(useParent);
2054                                     }
2055                                 }
2056                             }
2057                             break;
2058                         case HANDLERS:
2059                             List<Handler> hdls = null;
2060                             if (name.isEmpty()) {
2061                                 // special handling for the root logger.
2062                                 globalHandlersState = STATE_READING_CONFIG;
2063                                 try {
2064                                     closeHandlers(rootLogger);
2065                                     globalHandlersState = STATE_UNINITIALIZED;
2066                                 } catch (Throwable t) {
2067                                     globalHandlersState = STATE_INITIALIZED;
2068                                     throw t;
2069                                 }
2070                             }
2071                             for (Logger l : tmp) {
2072                                 if (l == rootLogger) continue;
2073                                 closeHandlers(l);
2074                                 if (mod == ModType.REMOVED) {
2075                                     closeOnResetLoggers.removeIf(c -> c.logger == l);
2076                                     continue;
2077                                 }
2078                                 if (hdls == null) {
2079                                     hdls = name.isEmpty()
2080                                             ? Arrays.asList(rootLogger.getHandlers())
2081                                             : createLoggerHandlers(name, pk);
2082                                 }
2083                                 setLoggerHandlers(l, name, pk, hdls);
2084                             }
2085                             break;
2086                         default: break;
2087                     }
2088                 }
2089             }
2090         } finally {
2091             configurationLock.unlock();
2092             visited.clear();
2093         }
2094 
2095         // Now ensure that if an existing logger has acquired a new parent
2096         // in the configuration, this new parent will be created - if needed,
2097         // and added to the context of the existing child.
2098         //
2099         drainLoggerRefQueueBounded();
2100         for (LoggerContext cx : cxs) {
2101             for (Enumeration<String> names = cx.getLoggerNames() ; names.hasMoreElements();) {
2102                 String name = names.nextElement();
2103                 if (name.isEmpty()) continue;  // don't need to process parents on root.
2104                 Logger l = cx.findLogger(name);
2105                 if (l != null && !visited.test(l, name)) {
2106                     // should pass visited here to cut the processing when
2107                     // reaching a logger already visited.
2108                     cx.processParentHandlers(l, name, visited);
2109                 }
2110             }
2111         }
2112 
2113         // We changed the configuration: invoke configuration listeners
2114         invokeConfigurationListeners();
2115     }
2116 
2117     /**
2118      * Get the value of a logging property.
2119      * The method returns null if the property is not found.
2120      * @param name      property name
2121      * @return          property value
2122      */
2123     public String getProperty(String name) {
2124         return props.getProperty(name);
2125     }
2126 
2127     // Package private method to get a String property.
2128     // If the property is not defined we return the given
2129     // default value.
2130     String getStringProperty(String name, String defaultValue) {
2131         String val = getProperty(name);
2132         if (val == null) {
2133             return defaultValue;
2134         }
2135         return val.trim();
2136     }


< prev index next >