Program: 35768
Project: 35768
Buggy source:
/** 
 * Updates the logging configuration. <p> For each configuration key in the   {@linkplain #getProperty(java.lang.String) existing configuration} andthe given input stream configuration, the given  {@code mapper} functionis invoked to map from the configuration key to a function, <i>f(o,n)</i>, that takes the old value and new value and returns the resulting value to be applied in the resulting configuration, as specified in the table below. <p>Let <i>k</i> be a configuration key in the old or new configuration, <i>o</i> be the old value (i.e. the value associated with <i>k</i> in the old configuration), <i>n</i> be the new value (i.e. the value associated with <i>k</i> in the new configuration), and <i>f</i> be the function returned by  {@code mapper.apply(}<i>k</i>  {@code )}: then <i>v = f(o,n)</i> is the resulting value. If <i>v</i> is not   {@code null}, then a property <i>k</i> with value <i>v</i> will be added to the resulting configuration. Otherwise, it will be omitted. <br>A   {@code null} value may be passed to function<i>f</i> to indicate that the corresponding configuration has no configuration key <i>k</i>. The function <i>f</i> may return  {@code null} to indicate thatthere will be no value associated with <i>k</i> in the resulting configuration. <p> If  {@code mapper} is {@code null}, then <i>v</i> will be set to <i>n</i>. <p> LogManager   {@linkplain #getProperty(java.lang.String) properties} areupdated with the resulting value in the resulting configuration. <p> The registered  {@linkplain #addConfigurationListener configurationlisteners} will be invoked after the configuration is successfully updated.<br><br> <table summary="Updating configuration properties"> <tr> <th>Property</th> <th>Resulting Behavior</th> </tr> <tr> <td valign="top"> {@code <logger>.level}</td> <td> <ul> <li>If the resulting configuration defines a level for a logger and if the resulting level is different than the level specified in the the old configuration, or not specified in the old configuration, then if the logger exists or if children for that logger exist, the level for that logger will be updated, and the change propagated to any existing logger children. This may cause the logger to be created, if necessary. </li> <li>If the old configuration defined a level for a logger, and the resulting configuration doesn't, then this change will not be propagated to existing loggers, if any. To completely replace a configuration - the caller should therefore call   {@link #reset() reset} to empty the current configuration,before calling  {@code updateConfiguration}. </li> </ul> </td> <tr> <td valign="top">  {@code <logger>.useParentHandlers}</td> <td> <ul> <li>If either the resulting or the old value for the useParentHandlers property is not null, then if the logger exists or if children for that logger exist, that logger will be updated to the resulting value. The value of the useParentHandlers property is the value specified in the configuration; if not specified, the default is true. </li> </ul> </td> </tr> <tr> <td valign="top">  {@code <logger>.handlers}</td> <td> <ul> <li>If the resulting configuration defines a list of handlers for a logger, and if the resulting list is different than the list specified in the old configuration for that logger (that could be empty), then if the logger exists or its children exist, the handlers associated with that logger are closed and removed and the new handlers will be created per the resulting configuration and added to that logger, creating that logger if necessary. </li> <li>If the old configuration defined some handlers for a logger, and the resulting configuration doesn't, if that logger exists, its handlers will be removed and closed. </li> <li>Changing the list of handlers on an existing logger will cause all its previous handlers to be removed and closed, regardless of whether they had been created from the configuration or programmatically. The old handlers will be replaced by new handlers, if any. </li> </ul> </td> </tr> <tr> <td valign="top">  {@code <handler-name>.*}</td> <td> <ul> <li>Properties configured/changed on handler classes will only affect newly created handlers. If a node is configured with the same list of handlers in the old and the resulting configuration, then these handlers will remain unchanged. </li> </ul> </td> </tr> <tr> <td valign="top">  {@code config} and any other property</td><td> <ul> <li>The resulting value for these property will be stored in the LogManager properties, but  {@code updateConfiguration} will not parseor process their values. </li> </ul> </td> </tr> </table> <p> <em>Example mapper functions:</em> <br><br> <ul> <li>Replace all logging properties with the new configuration: <br><br> {@code     (k) -> ((o, n) -> n)}: <br><br>this is equivalent to passing a null   {@code mapper} parameter.</li> <li>Merge the new configuration and old configuration and use the new value if <i>k</i> exists in the new configuration: <br><br> {@code     (k) -> ((o, n) -> n == null ? o : n)}: <br><br>as if merging two collections as follows:  {@code result.putAll(oldc); result.putAll(newc)}.<br></li> <li>Merge the new configuration and old configuration and use the old value if <i>k</i> exists in the old configuration: <br><br>  {@code     (k) -> ((o, n) -> o == null ? n : o)}: <br><br>as if merging two collections as follows:  {@code result.putAll(newc); result.putAll(oldc)}.<br></li> <li>Replace all properties with the new configuration except the handler property to configure Logger's handler that is not root logger: <br> <pre>  {@code (k) -> k.endsWith(".handlers")}{@code     ? ((o, n) -> (o == null ? n : o))}{@code     : ((o, n) -> n)}</pre> </li> </ul> <p> To completely reinitialize a configuration, an application can first call  {@link #reset() reset} to fully remove the old configuration, followed by{@code updateConfiguration} to initialize the new configuration.
 * @param ins    a stream to read properties from
 * @param mapper a functional interface that takes a configurationkey <i>k</i> and returns a function <i>f(o,n)</i> whose returned value will be applied to the resulting configuration. The function <i>f</i> may return  {@code null} to indicate that the property<i>k</i> will not be added to the resulting configuration. <br> If  {@code mapper} is {@code null} then {@code (k) -> ((o, n) -> n)} isassumed. <br> For each <i>k</i>, the mapped function <i>f</i> will be invoked with the value associated with <i>k</i> in the old configuration (i.e <i>o</i>) and the value associated with <i>k</i> in the new configuration (i.e. <i>n</i>). <br>A  {@code null} value for <i>o</i> or <i>n</i> indicates that novalue was present for <i>k</i> in the corresponding configuration.
 * @throws SecurityException if a security manager exists and ifthe caller does not have LoggingPermission("control"), or does not have the permissions required to set up the configuration (e.g. open files specified for FileHandlers)
 * @throws NullPointerException if {@code ins} is null or if{@code mapper} returns a null function when invoked.
 * @throws IOException if there are problems reading from the stream,or the given stream is not in the {@linkplain java.util.Properties properties file} format.
 * @since 9
 */
public void updateConfiguration(InputStream ins,Function<String,BiFunction<String,String,String>> mapper) throws IOException {
  checkPermission();
  ensureLogManagerInitialized();
  drainLoggerRefQueueBounded();
  final Properties previous;
  final Set<String> updatePropertyNames;
  List<LoggerContext> cxs=Collections.emptyList();
  final VisitedLoggers visited=new VisitedLoggers();
  final Properties next=new Properties();
  try {
    next.load(ins);
  }
 catch (  IllegalArgumentException x) {
    throw new IOException(x.getMessage(),x);
  }
  if (globalHandlersState == STATE_SHUTDOWN)   return;
  configurationLock.lock();
  try {
    if (globalHandlersState == STATE_SHUTDOWN)     return;
    previous=props;
    updatePropertyNames=Stream.concat(previous.stringPropertyNames().stream(),next.stringPropertyNames().stream()).collect(Collectors.toCollection(TreeSet::new));
    if (mapper != null) {
      updatePropertyNames.stream().forEachOrdered(k -> ConfigProperty.merge(k,previous,next,Objects.requireNonNull(mapper.apply(k))));
    }
    props=next;
    final Stream<String> allKeys=updatePropertyNames.stream().filter(ConfigProperty::matches).filter(k -> ConfigProperty.needsUpdating(k,previous,next));
    final Map<String,TreeSet<String>> loggerConfigs=allKeys.collect(Collectors.groupingBy(ConfigProperty::getLoggerName,TreeMap::new,Collectors.toCollection(TreeSet::new)));
    if (!loggerConfigs.isEmpty()) {
      cxs=contexts();
    }
    final List<Logger> loggers=cxs.isEmpty() ? Collections.emptyList() : new ArrayList<>(cxs.size());
    for (    Map.Entry<String,TreeSet<String>> e : loggerConfigs.entrySet()) {
      final String name=e.getKey();
      final Set<String> properties=e.getValue();
      loggers.clear();
      for (      LoggerContext cx : cxs) {
        Logger l=cx.findLogger(name);
        if (l != null && !visited.test(l)) {
          loggers.add(l);
        }
      }
      if (loggers.isEmpty())       continue;
      for (      String pk : properties) {
        ConfigProperty cp=ConfigProperty.find(pk).get();
        String p=previous.getProperty(pk,null);
        String n=next.getProperty(pk,null);
        ModType mod=ModType.of(p,n);
        if (mod == ModType.SAME)         continue;
switch (cp) {
case LEVEL:
          if (mod == ModType.REMOVED)           continue;
        Level level=Level.findLevel(trim(n));
      if (level != null) {
        if (name.isEmpty()) {
          rootLogger.setLevel(level);
        }
        for (        Logger l : loggers) {
          if (!name.isEmpty() || l != rootLogger) {
            l.setLevel(level);
          }
        }
      }
    break;
case USEPARENT:
  if (!name.isEmpty()) {
    boolean useParent=getBooleanProperty(pk,true);
    if (n != null || p != null) {
      for (      Logger l : loggers) {
        l.setUseParentHandlers(useParent);
      }
    }
  }
break;
case HANDLERS:
List<Handler> hdls=null;
if (name.isEmpty()) {
globalHandlersState=STATE_READING_CONFIG;
try {
closeHandlers(rootLogger);
globalHandlersState=STATE_UNINITIALIZED;
}
 catch (Throwable t) {
globalHandlersState=STATE_INITIALIZED;
throw t;
}
}
for (Logger l : loggers) {
if (l == rootLogger) continue;
closeHandlers(l);
if (mod == ModType.REMOVED) {
closeOnResetLoggers.removeIf(c -> c.logger == l);
continue;
}
if (hdls == null) {
hdls=name.isEmpty() ? Arrays.asList(rootLogger.getHandlers()) : createLoggerHandlers(name,pk);
}
setLoggerHandlers(l,name,pk,hdls);
}
break;
default :
break;
}
}
}
}
  finally {
configurationLock.unlock();
visited.clear();
}
drainLoggerRefQueueBounded();
for (LoggerContext cx : cxs) {
for (Enumeration<String> names=cx.getLoggerNames(); names.hasMoreElements(); ) {
String name=names.nextElement();
if (name.isEmpty()) continue;
Logger l=cx.findLogger(name);
if (l != null && !visited.test(l)) {
cx.processParentHandlers(l,name,visited);
}
}
}
invokeConfigurationListeners();
}

Fixed version (ground truth):
/** 
 * Updates the logging configuration. <p> For each configuration key in the   {@linkplain #getProperty(java.lang.String) existing configuration} andthe given input stream configuration, the given  {@code mapper} functionis invoked to map from the configuration key to a function, <i>f(o,n)</i>, that takes the old value and new value and returns the resulting value to be applied in the resulting configuration, as specified in the table below. <p>Let <i>k</i> be a configuration key in the old or new configuration, <i>o</i> be the old value (i.e. the value associated with <i>k</i> in the old configuration), <i>n</i> be the new value (i.e. the value associated with <i>k</i> in the new configuration), and <i>f</i> be the function returned by  {@code mapper.apply(}<i>k</i>  {@code )}: then <i>v = f(o,n)</i> is the resulting value. If <i>v</i> is not   {@code null}, then a property <i>k</i> with value <i>v</i> will be added to the resulting configuration. Otherwise, it will be omitted. <br>A   {@code null} value may be passed to function<i>f</i> to indicate that the corresponding configuration has no configuration key <i>k</i>. The function <i>f</i> may return  {@code null} to indicate thatthere will be no value associated with <i>k</i> in the resulting configuration. <p> If  {@code mapper} is {@code null}, then <i>v</i> will be set to <i>n</i>. <p> LogManager   {@linkplain #getProperty(java.lang.String) properties} areupdated with the resulting value in the resulting configuration. <p> The registered  {@linkplain #addConfigurationListener configurationlisteners} will be invoked after the configuration is successfully updated.<br><br> <table><caption style="display:none">Updating configuration properties</caption> <tr> <th>Property</th> <th>Resulting Behavior</th> </tr> <tr> <td valign="top"> {@code <logger>.level}</td> <td> <ul> <li>If the resulting configuration defines a level for a logger and if the resulting level is different than the level specified in the the old configuration, or not specified in the old configuration, then if the logger exists or if children for that logger exist, the level for that logger will be updated, and the change propagated to any existing logger children. This may cause the logger to be created, if necessary. </li> <li>If the old configuration defined a level for a logger, and the resulting configuration doesn't, then this change will not be propagated to existing loggers, if any. To completely replace a configuration - the caller should therefore call   {@link #reset() reset} to empty the current configuration,before calling  {@code updateConfiguration}. </li> </ul> </td> <tr> <td valign="top">  {@code <logger>.useParentHandlers}</td> <td> <ul> <li>If either the resulting or the old value for the useParentHandlers property is not null, then if the logger exists or if children for that logger exist, that logger will be updated to the resulting value. The value of the useParentHandlers property is the value specified in the configuration; if not specified, the default is true. </li> </ul> </td> </tr> <tr> <td valign="top">  {@code <logger>.handlers}</td> <td> <ul> <li>If the resulting configuration defines a list of handlers for a logger, and if the resulting list is different than the list specified in the old configuration for that logger (that could be empty), then if the logger exists or its children exist, the handlers associated with that logger are closed and removed and the new handlers will be created per the resulting configuration and added to that logger, creating that logger if necessary. </li> <li>If the old configuration defined some handlers for a logger, and the resulting configuration doesn't, if that logger exists, its handlers will be removed and closed. </li> <li>Changing the list of handlers on an existing logger will cause all its previous handlers to be removed and closed, regardless of whether they had been created from the configuration or programmatically. The old handlers will be replaced by new handlers, if any. </li> </ul> </td> </tr> <tr> <td valign="top">  {@code <handler-name>.*}</td> <td> <ul> <li>Properties configured/changed on handler classes will only affect newly created handlers. If a node is configured with the same list of handlers in the old and the resulting configuration, then these handlers will remain unchanged. </li> </ul> </td> </tr> <tr> <td valign="top">  {@code config} and any other property</td><td> <ul> <li>The resulting value for these property will be stored in the LogManager properties, but  {@code updateConfiguration} will not parseor process their values. </li> </ul> </td> </tr> </table> <p> <em>Example mapper functions:</em> <br><br> <ul> <li>Replace all logging properties with the new configuration: <br><br> {@code     (k) -> ((o, n) -> n)}: <br><br>this is equivalent to passing a null   {@code mapper} parameter.</li> <li>Merge the new configuration and old configuration and use the new value if <i>k</i> exists in the new configuration: <br><br> {@code     (k) -> ((o, n) -> n == null ? o : n)}: <br><br>as if merging two collections as follows:  {@code result.putAll(oldc); result.putAll(newc)}.<br></li> <li>Merge the new configuration and old configuration and use the old value if <i>k</i> exists in the old configuration: <br><br>  {@code     (k) -> ((o, n) -> o == null ? n : o)}: <br><br>as if merging two collections as follows:  {@code result.putAll(newc); result.putAll(oldc)}.<br></li> <li>Replace all properties with the new configuration except the handler property to configure Logger's handler that is not root logger: <br> <pre>  {@code (k) -> k.endsWith(".handlers")}{@code     ? ((o, n) -> (o == null ? n : o))}{@code     : ((o, n) -> n)}</pre> </li> </ul> <p> To completely reinitialize a configuration, an application can first call  {@link #reset() reset} to fully remove the old configuration, followed by{@code updateConfiguration} to initialize the new configuration.
 * @param ins    a stream to read properties from
 * @param mapper a functional interface that takes a configurationkey <i>k</i> and returns a function <i>f(o,n)</i> whose returned value will be applied to the resulting configuration. The function <i>f</i> may return  {@code null} to indicate that the property<i>k</i> will not be added to the resulting configuration. <br> If  {@code mapper} is {@code null} then {@code (k) -> ((o, n) -> n)} isassumed. <br> For each <i>k</i>, the mapped function <i>f</i> will be invoked with the value associated with <i>k</i> in the old configuration (i.e <i>o</i>) and the value associated with <i>k</i> in the new configuration (i.e. <i>n</i>). <br>A  {@code null} value for <i>o</i> or <i>n</i> indicates that novalue was present for <i>k</i> in the corresponding configuration.
 * @throws SecurityException if a security manager exists and ifthe caller does not have LoggingPermission("control"), or does not have the permissions required to set up the configuration (e.g. open files specified for FileHandlers)
 * @throws NullPointerException if {@code ins} is null or if{@code mapper} returns a null function when invoked.
 * @throws IOException if there are problems reading from the stream,or the given stream is not in the {@linkplain java.util.Properties properties file} format.
 * @since 9
 */
public void updateConfiguration(InputStream ins,Function<String,BiFunction<String,String,String>> mapper) throws IOException {
  checkPermission();
  ensureLogManagerInitialized();
  drainLoggerRefQueueBounded();
  final Properties previous;
  final Set<String> updatePropertyNames;
  List<LoggerContext> cxs=Collections.emptyList();
  final VisitedLoggers visited=new VisitedLoggers();
  final Properties next=new Properties();
  try {
    next.load(ins);
  }
 catch (  IllegalArgumentException x) {
    throw new IOException(x.getMessage(),x);
  }
  if (globalHandlersState == STATE_SHUTDOWN)   return;
  configurationLock.lock();
  try {
    if (globalHandlersState == STATE_SHUTDOWN)     return;
    previous=props;
    updatePropertyNames=Stream.concat(previous.stringPropertyNames().stream(),next.stringPropertyNames().stream()).collect(Collectors.toCollection(TreeSet::new));
    if (mapper != null) {
      updatePropertyNames.stream().forEachOrdered(k -> ConfigProperty.merge(k,previous,next,Objects.requireNonNull(mapper.apply(k))));
    }
    props=next;
    final Stream<String> allKeys=updatePropertyNames.stream().filter(ConfigProperty::matches).filter(k -> ConfigProperty.needsUpdating(k,previous,next));
    final Map<String,TreeSet<String>> loggerConfigs=allKeys.collect(Collectors.groupingBy(ConfigProperty::getLoggerName,TreeMap::new,Collectors.toCollection(TreeSet::new)));
    if (!loggerConfigs.isEmpty()) {
      cxs=contexts();
    }
    final List<Logger> loggers=cxs.isEmpty() ? Collections.emptyList() : new ArrayList<>(cxs.size());
    for (    Map.Entry<String,TreeSet<String>> e : loggerConfigs.entrySet()) {
      final String name=e.getKey();
      final Set<String> properties=e.getValue();
      loggers.clear();
      for (      LoggerContext cx : cxs) {
        Logger l=cx.findLogger(name);
        if (l != null && !visited.test(l)) {
          loggers.add(l);
        }
      }
      if (loggers.isEmpty())       continue;
      for (      String pk : properties) {
        ConfigProperty cp=ConfigProperty.find(pk).get();
        String p=previous.getProperty(pk,null);
        String n=next.getProperty(pk,null);
        ModType mod=ModType.of(p,n);
        if (mod == ModType.SAME)         continue;
switch (cp) {
case LEVEL:
          if (mod == ModType.REMOVED)           continue;
        Level level=Level.findLevel(trim(n));
      if (level != null) {
        if (name.isEmpty()) {
          rootLogger.setLevel(level);
        }
        for (        Logger l : loggers) {
          if (!name.isEmpty() || l != rootLogger) {
            l.setLevel(level);
          }
        }
      }
    break;
case USEPARENT:
  if (!name.isEmpty()) {
    boolean useParent=getBooleanProperty(pk,true);
    if (n != null || p != null) {
      for (      Logger l : loggers) {
        l.setUseParentHandlers(useParent);
      }
    }
  }
break;
case HANDLERS:
List<Handler> hdls=null;
if (name.isEmpty()) {
globalHandlersState=STATE_READING_CONFIG;
try {
closeHandlers(rootLogger);
globalHandlersState=STATE_UNINITIALIZED;
}
 catch (Throwable t) {
globalHandlersState=STATE_INITIALIZED;
throw t;
}
}
for (Logger l : loggers) {
if (l == rootLogger) continue;
closeHandlers(l);
if (mod == ModType.REMOVED) {
closeOnResetLoggers.removeIf(c -> c.logger == l);
continue;
}
if (hdls == null) {
hdls=name.isEmpty() ? Arrays.asList(rootLogger.getHandlers()) : createLoggerHandlers(name,pk);
}
setLoggerHandlers(l,name,pk,hdls);
}
break;
default :
break;
}
}
}
}
  finally {
configurationLock.unlock();
visited.clear();
}
drainLoggerRefQueueBounded();
for (LoggerContext cx : cxs) {
for (Enumeration<String> names=cx.getLoggerNames(); names.hasMoreElements(); ) {
String name=names.nextElement();
if (name.isEmpty()) continue;
Logger l=cx.findLogger(name);
if (l != null && !visited.test(l)) {
cx.processParentHandlers(l,name,visited);
}
}
}
invokeConfigurationListeners();
}