LCOV - code coverage report
Current view: top level - server/config - ConfigUpdatedEvent.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 21 72 29.2 %
Date: 2022-11-19 15:00:39 Functions: 7 25 28.0 %

          Line data    Source code
       1             : // Copyright (C) 2018 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : package com.google.gerrit.server.config;
      15             : 
      16             : import com.google.common.collect.ArrayListMultimap;
      17             : import com.google.common.collect.ImmutableMultimap;
      18             : import com.google.common.collect.Multimap;
      19             : import java.util.Collections;
      20             : import java.util.LinkedHashSet;
      21             : import java.util.Objects;
      22             : import java.util.Set;
      23             : import org.apache.commons.lang3.StringUtils;
      24             : import org.eclipse.jgit.lib.Config;
      25             : 
      26             : /**
      27             :  * This event is produced by {@link GerritServerConfigReloader} and forwarded to callers
      28             :  * implementing {@link GerritConfigListener}.
      29             :  *
      30             :  * <p>The event intends to:
      31             :  *
      32             :  * <p>1. Help the callers figure out if any action should be taken, depending on which entries are
      33             :  * updated in gerrit.config.
      34             :  *
      35             :  * <p>2. Provide the callers with a mechanism to accept/reject the entries of interest: {@link
      36             :  * #accept(Set)}, {@link #accept(String)}, {@link #reject(Set)} (+ various overloaded versions of
      37             :  * these)
      38             :  */
      39             : public class ConfigUpdatedEvent {
      40           1 :   public static final ImmutableMultimap<UpdateResult, ConfigUpdateEntry> NO_UPDATES =
      41           1 :       new ImmutableMultimap.Builder<UpdateResult, ConfigUpdateEntry>().build();
      42             :   private final Config oldConfig;
      43             :   private final Config newConfig;
      44             : 
      45           1 :   public ConfigUpdatedEvent(Config oldConfig, Config newConfig) {
      46           1 :     this.oldConfig = oldConfig;
      47           1 :     this.newConfig = newConfig;
      48           1 :   }
      49             : 
      50             :   public Config getOldConfig() {
      51           0 :     return this.oldConfig;
      52             :   }
      53             : 
      54             :   public Config getNewConfig() {
      55           0 :     return this.newConfig;
      56             :   }
      57             : 
      58             :   private String getString(ConfigKey key, Config config) {
      59           0 :     return config.getString(key.section(), key.subsection(), key.name());
      60             :   }
      61             : 
      62             :   public Multimap<UpdateResult, ConfigUpdateEntry> accept(ConfigKey entry) {
      63           0 :     return accept(Collections.singleton(entry));
      64             :   }
      65             : 
      66             :   public Multimap<UpdateResult, ConfigUpdateEntry> accept(Set<ConfigKey> entries) {
      67           0 :     return createUpdate(entries, UpdateResult.APPLIED);
      68             :   }
      69             : 
      70             :   public Multimap<UpdateResult, ConfigUpdateEntry> accept(String section) {
      71           0 :     Set<ConfigKey> entries = getEntriesFromSection(oldConfig, section);
      72           0 :     entries.addAll(getEntriesFromSection(newConfig, section));
      73           0 :     return createUpdate(entries, UpdateResult.APPLIED);
      74             :   }
      75             : 
      76             :   public Multimap<UpdateResult, ConfigUpdateEntry> reject(ConfigKey entry) {
      77           0 :     return reject(Collections.singleton(entry));
      78             :   }
      79             : 
      80             :   public Multimap<UpdateResult, ConfigUpdateEntry> reject(Set<ConfigKey> entries) {
      81           0 :     return createUpdate(entries, UpdateResult.REJECTED);
      82             :   }
      83             : 
      84             :   private static Set<ConfigKey> getEntriesFromSection(Config config, String section) {
      85           1 :     Set<ConfigKey> res = new LinkedHashSet<>();
      86           1 :     for (String name : config.getNames(section, true)) {
      87           0 :       res.add(ConfigKey.create(section, name));
      88           0 :     }
      89           1 :     for (String sub : config.getSubsections(section)) {
      90           0 :       for (String name : config.getNames(section, sub, true)) {
      91           0 :         res.add(ConfigKey.create(section, sub, name));
      92           0 :       }
      93           0 :     }
      94           1 :     return res;
      95             :   }
      96             : 
      97             :   private Multimap<UpdateResult, ConfigUpdateEntry> createUpdate(
      98             :       Set<ConfigKey> entries, UpdateResult updateResult) {
      99           0 :     Multimap<UpdateResult, ConfigUpdateEntry> updates = ArrayListMultimap.create();
     100           0 :     entries.stream()
     101           0 :         .filter(this::isValueUpdated)
     102           0 :         .map(e -> new ConfigUpdateEntry(e, getString(e, oldConfig), getString(e, newConfig)))
     103           0 :         .forEach(e -> updates.put(updateResult, e));
     104           0 :     return updates;
     105             :   }
     106             : 
     107             :   public boolean isSectionUpdated(String section) {
     108           1 :     Set<ConfigKey> entries = getEntriesFromSection(oldConfig, section);
     109           1 :     entries.addAll(getEntriesFromSection(newConfig, section));
     110           1 :     return isEntriesUpdated(entries);
     111             :   }
     112             : 
     113             :   public boolean isValueUpdated(String section, String subsection, String name) {
     114           1 :     return !Objects.equals(
     115           1 :         oldConfig.getString(section, subsection, name),
     116           1 :         newConfig.getString(section, subsection, name));
     117             :   }
     118             : 
     119             :   public boolean isValueUpdated(ConfigKey key) {
     120           1 :     return isValueUpdated(key.section(), key.subsection(), key.name());
     121             :   }
     122             : 
     123             :   public boolean isValueUpdated(String section, String name) {
     124           0 :     return isValueUpdated(section, null, name);
     125             :   }
     126             : 
     127             :   public boolean isEntriesUpdated(Set<ConfigKey> entries) {
     128           1 :     for (ConfigKey entry : entries) {
     129           1 :       if (isValueUpdated(entry.section(), entry.subsection(), entry.name())) {
     130           0 :         return true;
     131             :       }
     132           1 :     }
     133           1 :     return false;
     134             :   }
     135             : 
     136           0 :   public enum UpdateResult {
     137           0 :     APPLIED,
     138           0 :     REJECTED;
     139             : 
     140             :     @Override
     141             :     public String toString() {
     142           0 :       return StringUtils.capitalize(name().toLowerCase());
     143             :     }
     144             :   }
     145             : 
     146           0 :   public enum ConfigEntryType {
     147           0 :     ADDED,
     148           0 :     REMOVED,
     149           0 :     MODIFIED,
     150           0 :     UNMODIFIED
     151             :   }
     152             : 
     153             :   public static class ConfigUpdateEntry {
     154             :     public final ConfigKey key;
     155             :     public final String oldVal;
     156             :     public final String newVal;
     157             : 
     158           0 :     public ConfigUpdateEntry(ConfigKey key, String oldVal, String newVal) {
     159           0 :       this.key = key;
     160           0 :       this.oldVal = oldVal;
     161           0 :       this.newVal = newVal;
     162           0 :     }
     163             : 
     164             :     /** Note: The toString() is used to format the output from @see ReloadConfig. */
     165             :     @Override
     166             :     public String toString() {
     167           0 :       switch (getUpdateType()) {
     168             :         case ADDED:
     169           0 :           return String.format("+ %s = %s", key, newVal);
     170             :         case MODIFIED:
     171           0 :           return String.format("* %s = [%s => %s]", key, oldVal, newVal);
     172             :         case REMOVED:
     173           0 :           return String.format("- %s = %s", key, oldVal);
     174             :         case UNMODIFIED:
     175           0 :           return String.format("  %s = %s", key, newVal);
     176             :         default:
     177           0 :           throw new IllegalStateException("Unexpected UpdateType: " + getUpdateType().name());
     178             :       }
     179             :     }
     180             : 
     181             :     public ConfigEntryType getUpdateType() {
     182           0 :       if (oldVal == null && newVal != null) {
     183           0 :         return ConfigEntryType.ADDED;
     184             :       }
     185           0 :       if (oldVal != null && newVal == null) {
     186           0 :         return ConfigEntryType.REMOVED;
     187             :       }
     188           0 :       if (Objects.equals(oldVal, newVal)) {
     189           0 :         return ConfigEntryType.UNMODIFIED;
     190             :       }
     191           0 :       return ConfigEntryType.MODIFIED;
     192             :     }
     193             :   }
     194             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750