Merge "Extract RequestConfig class from TraceRequestListener"
diff --git a/java/com/google/gerrit/server/RequestConfig.java b/java/com/google/gerrit/server/RequestConfig.java
new file mode 100644
index 0000000..bbefd7a
--- /dev/null
+++ b/java/com/google/gerrit/server/RequestConfig.java
@@ -0,0 +1,200 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.Account;
+import java.util.Optional;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
+
+/**
+ * Represents a configuration on request level that matches requests by request type, URI pattern,
+ * caller and/or project pattern.
+ */
+@AutoValue
+public abstract class RequestConfig {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ public static ImmutableList<RequestConfig> parseConfigs(Config cfg, String section) {
+ ImmutableList.Builder<RequestConfig> requestConfigs = ImmutableList.builder();
+
+ for (String id : cfg.getSubsections(section)) {
+ try {
+ RequestConfig.Builder requestConfig = RequestConfig.builder();
+ requestConfig.id(id);
+ requestConfig.requestTypes(parseRequestTypes(cfg, section, id));
+ requestConfig.requestUriPatterns(parseRequestUriPatterns(cfg, section, id));
+ requestConfig.accountIds(parseAccounts(cfg, section, id));
+ requestConfig.projectPatterns(parseProjectPatterns(cfg, section, id));
+ requestConfigs.add(requestConfig.build());
+ } catch (ConfigInvalidException e) {
+ logger.atWarning().log("Ignoring invalid %s configuration:\n %s", section, e.getMessage());
+ }
+ }
+
+ return requestConfigs.build();
+ }
+
+ private static ImmutableSet<String> parseRequestTypes(Config cfg, String section, String id) {
+ return ImmutableSet.copyOf(cfg.getStringList(section, id, "requestType"));
+ }
+
+ private static ImmutableSet<Pattern> parseRequestUriPatterns(
+ Config cfg, String section, String id) throws ConfigInvalidException {
+ return parsePatterns(cfg, section, id, "requestUriPattern");
+ }
+
+ private static ImmutableSet<Account.Id> parseAccounts(Config cfg, String section, String id)
+ throws ConfigInvalidException {
+ ImmutableSet.Builder<Account.Id> accountIds = ImmutableSet.builder();
+ String[] accounts = cfg.getStringList(section, id, "account");
+ for (String account : accounts) {
+ Optional<Account.Id> accountId = Account.Id.tryParse(account);
+ if (!accountId.isPresent()) {
+ throw new ConfigInvalidException(
+ String.format(
+ "Invalid request config ('%s.%s.account = %s'): invalid account ID",
+ section, id, account));
+ }
+ accountIds.add(accountId.get());
+ }
+ return accountIds.build();
+ }
+
+ private static ImmutableSet<Pattern> parseProjectPatterns(Config cfg, String section, String id)
+ throws ConfigInvalidException {
+ return parsePatterns(cfg, section, id, "projectPattern");
+ }
+
+ private static ImmutableSet<Pattern> parsePatterns(
+ Config cfg, String section, String id, String name) throws ConfigInvalidException {
+ ImmutableSet.Builder<Pattern> patterns = ImmutableSet.builder();
+ String[] patternRegExs = cfg.getStringList(section, id, name);
+ for (String patternRegEx : patternRegExs) {
+ try {
+ patterns.add(Pattern.compile(patternRegEx));
+ } catch (PatternSyntaxException e) {
+ throw new ConfigInvalidException(
+ String.format(
+ "Invalid request config ('%s.%s.%s = %s'): %s",
+ section, id, name, patternRegEx, e.getMessage()));
+ }
+ }
+ return patterns.build();
+ }
+
+ /** ID of the config */
+ abstract String id();
+
+ /** request types that should be matched */
+ abstract ImmutableSet<String> requestTypes();
+
+ /** pattern matching request URIs */
+ abstract ImmutableSet<Pattern> requestUriPatterns();
+
+ /** accounts IDs matching calling user */
+ abstract ImmutableSet<Account.Id> accountIds();
+
+ /** pattern matching projects names */
+ abstract ImmutableSet<Pattern> projectPatterns();
+
+ private static Builder builder() {
+ return new AutoValue_RequestConfig.Builder();
+ }
+
+ /**
+ * Whether this request config matches a given request.
+ *
+ * @param requestInfo request info
+ * @return whether this request config matches
+ */
+ boolean matches(RequestInfo requestInfo) {
+ // If in the request config request types are set and none of them matches, then the request is
+ // not matched.
+ if (!requestTypes().isEmpty()
+ && requestTypes().stream()
+ .noneMatch(type -> type.equalsIgnoreCase(requestInfo.requestType()))) {
+ return false;
+ }
+
+ // If in the request config request URI patterns are set and none of them matches, then the
+ // request is not matched.
+ if (!requestUriPatterns().isEmpty()) {
+ if (!requestInfo.requestUri().isPresent()) {
+ // The request has no request URI, hence it cannot match a request URI pattern.
+ return false;
+ }
+
+ if (requestUriPatterns().stream()
+ .noneMatch(p -> p.matcher(requestInfo.requestUri().get()).matches())) {
+ return false;
+ }
+ }
+
+ // If in the request config accounts are set and none of them matches, then the request is not
+ // matched.
+ if (!accountIds().isEmpty()) {
+ try {
+ if (accountIds().stream()
+ .noneMatch(id -> id.equals(requestInfo.callingUser().getAccountId()))) {
+ return false;
+ }
+ } catch (UnsupportedOperationException e) {
+ // The calling user is not logged in, hence it cannot match an account.
+ return false;
+ }
+ }
+
+ // If in the request config project patterns are set and none of them matches, then the request
+ // is not matched.
+ if (!projectPatterns().isEmpty()) {
+ if (!requestInfo.project().isPresent()) {
+ // The request is not for a project, hence it cannot match a project pattern.
+ return false;
+ }
+
+ if (projectPatterns().stream()
+ .noneMatch(p -> p.matcher(requestInfo.project().get().get()).matches())) {
+ return false;
+ }
+ }
+
+ // For any match criteria (request type, request URI pattern, account, project pattern) that
+ // was specified in the request config, at least one of the configured value matched the
+ // request.
+ return true;
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ abstract Builder id(String id);
+
+ abstract Builder requestTypes(ImmutableSet<String> requestTypes);
+
+ abstract Builder requestUriPatterns(ImmutableSet<Pattern> requestUriPatterns);
+
+ abstract Builder accountIds(ImmutableSet<Account.Id> accountIds);
+
+ abstract Builder projectPatterns(ImmutableSet<Pattern> projectPatterns);
+
+ abstract RequestConfig build();
+ }
+}
diff --git a/java/com/google/gerrit/server/TraceRequestListener.java b/java/com/google/gerrit/server/TraceRequestListener.java
index 20c9f57..7136e47 100644
--- a/java/com/google/gerrit/server/TraceRequestListener.java
+++ b/java/com/google/gerrit/server/TraceRequestListener.java
@@ -14,19 +14,11 @@
package com.google.gerrit.server;
-import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.Account;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.logging.RequestId;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import java.util.Optional;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
/**
@@ -36,15 +28,13 @@
*/
@Singleton
public class TraceRequestListener implements RequestListener {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ private static String SECTION_TRACING = "tracing";
- private final Config cfg;
- private final ImmutableList<TraceConfig> traceConfigs;
+ private final ImmutableList<RequestConfig> traceConfigs;
@Inject
TraceRequestListener(@GerritServerConfig Config cfg) {
- this.cfg = cfg;
- this.traceConfigs = parseTraceConfigs();
+ this.traceConfigs = RequestConfig.parseConfigs(cfg, SECTION_TRACING);
}
@Override
@@ -57,172 +47,6 @@
requestInfo
.traceContext()
.forceLogging()
- .addTag(RequestId.Type.TRACE_ID, traceConfig.traceId()));
- }
-
- private ImmutableList<TraceConfig> parseTraceConfigs() {
- ImmutableList.Builder<TraceConfig> traceConfigs = ImmutableList.builder();
-
- for (String traceId : cfg.getSubsections("tracing")) {
- try {
- TraceConfig.Builder traceConfig = TraceConfig.builder();
- traceConfig.traceId(traceId);
- traceConfig.requestTypes(parseRequestTypes(traceId));
- traceConfig.requestUriPatterns(parseRequestUriPatterns(traceId));
- traceConfig.accountIds(parseAccounts(traceId));
- traceConfig.projectPatterns(parseProjectPatterns(traceId));
- traceConfigs.add(traceConfig.build());
- } catch (ConfigInvalidException e) {
- logger.atWarning().log("Ignoring invalid tracing configuration:\n %s", e.getMessage());
- }
- }
-
- return traceConfigs.build();
- }
-
- private ImmutableSet<String> parseRequestTypes(String traceId) {
- return ImmutableSet.copyOf(cfg.getStringList("tracing", traceId, "requestType"));
- }
-
- private ImmutableSet<Pattern> parseRequestUriPatterns(String traceId)
- throws ConfigInvalidException {
- return parsePatterns(traceId, "requestUriPattern");
- }
-
- private ImmutableSet<Account.Id> parseAccounts(String traceId) throws ConfigInvalidException {
- ImmutableSet.Builder<Account.Id> accountIds = ImmutableSet.builder();
- String[] accounts = cfg.getStringList("tracing", traceId, "account");
- for (String account : accounts) {
- Optional<Account.Id> accountId = Account.Id.tryParse(account);
- if (!accountId.isPresent()) {
- throw new ConfigInvalidException(
- String.format(
- "Invalid tracing config ('tracing.%s.account = %s'): invalid account ID",
- traceId, account));
- }
- accountIds.add(accountId.get());
- }
- return accountIds.build();
- }
-
- private ImmutableSet<Pattern> parseProjectPatterns(String traceId) throws ConfigInvalidException {
- return parsePatterns(traceId, "projectPattern");
- }
-
- private ImmutableSet<Pattern> parsePatterns(String traceId, String name)
- throws ConfigInvalidException {
- ImmutableSet.Builder<Pattern> patterns = ImmutableSet.builder();
- String[] patternRegExs = cfg.getStringList("tracing", traceId, name);
- for (String patternRegEx : patternRegExs) {
- try {
- patterns.add(Pattern.compile(patternRegEx));
- } catch (PatternSyntaxException e) {
- throw new ConfigInvalidException(
- String.format(
- "Invalid tracing config ('tracing.%s.%s = %s'): %s",
- traceId, name, patternRegEx, e.getMessage()));
- }
- }
- return patterns.build();
- }
-
- @AutoValue
- abstract static class TraceConfig {
- /** ID for the trace */
- abstract String traceId();
-
- /** request types that should be traced */
- abstract ImmutableSet<String> requestTypes();
-
- /** pattern matching request URIs */
- abstract ImmutableSet<Pattern> requestUriPatterns();
-
- /** accounts IDs matching calling user */
- abstract ImmutableSet<Account.Id> accountIds();
-
- /** pattern matching projects names */
- abstract ImmutableSet<Pattern> projectPatterns();
-
- static Builder builder() {
- return new AutoValue_TraceRequestListener_TraceConfig.Builder();
- }
-
- /**
- * Whether this trace config matches a given request.
- *
- * @param requestInfo request info
- * @return whether this trace config matches
- */
- boolean matches(RequestInfo requestInfo) {
- // If in the trace config request types are set and none of them matches, then the request is
- // not matched.
- if (!requestTypes().isEmpty()
- && requestTypes().stream()
- .noneMatch(type -> type.equalsIgnoreCase(requestInfo.requestType()))) {
- return false;
- }
-
- // If in the trace config request URI patterns are set and none of them matches, then the
- // request is not matched.
- if (!requestUriPatterns().isEmpty()) {
- if (!requestInfo.requestUri().isPresent()) {
- // The request has no request URI, hence it cannot match a request URI pattern.
- return false;
- }
-
- if (requestUriPatterns().stream()
- .noneMatch(p -> p.matcher(requestInfo.requestUri().get()).matches())) {
- return false;
- }
- }
-
- // If in the trace config accounts are set and none of them matches, then the request is not
- // matched.
- if (!accountIds().isEmpty()) {
- try {
- if (accountIds().stream()
- .noneMatch(id -> id.equals(requestInfo.callingUser().getAccountId()))) {
- return false;
- }
- } catch (UnsupportedOperationException e) {
- // The calling user is not logged in, hence it cannot match an account.
- return false;
- }
- }
-
- // If in the trace config project patterns are set and none of them matches, then the request
- // is not matched.
- if (!projectPatterns().isEmpty()) {
- if (!requestInfo.project().isPresent()) {
- // The request is not for a project, hence it cannot match a project pattern.
- return false;
- }
-
- if (projectPatterns().stream()
- .noneMatch(p -> p.matcher(requestInfo.project().get().get()).matches())) {
- return false;
- }
- }
-
- // For any match criteria (request type, request URI pattern, account, project pattern) that
- // was specified in the trace config, at least one of the configured value matched the
- // request.
- return true;
- }
-
- @AutoValue.Builder
- abstract static class Builder {
- abstract Builder traceId(String traceId);
-
- abstract Builder requestTypes(ImmutableSet<String> requestTypes);
-
- abstract Builder requestUriPatterns(ImmutableSet<Pattern> requestUriPatterns);
-
- abstract Builder accountIds(ImmutableSet<Account.Id> accountIds);
-
- abstract Builder projectPatterns(ImmutableSet<Pattern> projectPatterns);
-
- abstract TraceConfig build();
- }
+ .addTag(RequestId.Type.TRACE_ID, traceConfig.id()));
}
}