• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #19702

18 Feb 2025 06:47PM UTC coverage: 88.587% (-0.005%) from 88.592%
#19702

push

github

web-flow
xds: Change how xDS filters are created by introducing Filter.Provider (#11883)

This is the first step towards supporting filter state retention in
Java. The mechanism will be similar to the one described in [A83]
(https://github.com/grpc/proposal/blob/master/A83-xds-gcp-authn-filter.md#filter-call-credentials-cache)
for C-core, and will serve the same purpose. However, the
implementation details are very different due to the different nature
of xDS HTTP filter support in C-core and Java.

In Java, xDS HTTP filters are backed by classes implementing
`io.grpc.xds.Filter`, from here just called "Filters". To support
Filter state retention (next PR), Java's xDS implementation must be
able to create unique Filter instances per:
- Per HCM
  `envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager`
- Per filter name as specified in
  `envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter.name`

This PR **does not** implements Filter state retention, but lays the
groundwork for it by changing how filters are registered and
instantiated. To achieve this, all existing Filter classes had to be
updated to the new instantiation mechanism described below.

Prior to these this PR, Filters had no livecycle. FilterRegistry
provided singleton instances for a given typeUrl. This PR introduces
a new interface `Filter.Provider`, which instantiates Filter classes.
All functionality that doesn't need an instance of a Filter is moved
to the Filter.Provider. This includes parsing filter config proto
into FilterConfig and determining the filter kind
(client-side, server-side, or both).

This PR is limited to refactoring, and there's no changes to the
existing behavior. Note that all Filter Providers still return
singleton Filter instances. However, with this PR, it is now possible
to create Providers that return a new Filter instance each time
`newInstance` is called.

34252 of 38665 relevant lines covered (88.59%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.0
/../xds/src/main/java/io/grpc/xds/Filter.java
1
/*
2
 * Copyright 2021 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.xds;
18

19
import com.google.common.base.MoreObjects;
20
import com.google.protobuf.Message;
21
import io.grpc.ClientInterceptor;
22
import io.grpc.ServerInterceptor;
23
import java.util.Objects;
24
import java.util.concurrent.ScheduledExecutorService;
25
import javax.annotation.Nullable;
26

27
/**
28
 * Defines the parsing functionality of an HTTP filter.
29
 *
30
 * <p>A Filter may optionally implement either {@link Filter#buildClientInterceptor} or
31
 * {@link Filter#buildServerInterceptor} or both, and return true from corresponding
32
 * {@link Provider#isClientFilter()}, {@link Provider#isServerFilter()} to indicate that the filter
33
 * is capable of working on the client side or server side or both, respectively.
34
 */
35
interface Filter {
36

37
  /** Represents an opaque data structure holding configuration for a filter. */
38
  interface FilterConfig {
39
    String typeUrl();
40
  }
41

42
  /**
43
   * Common interface for filter providers.
44
   */
45
  interface Provider {
46
    /**
47
     * The proto message types supported by this filter. A filter will be registered by each of its
48
     * supported message types.
49
     */
50
    String[] typeUrls();
51

52
    /**
53
     * Whether the filter can be installed on the client side.
54
     *
55
     * <p>Returns true if the filter implements {@link Filter#buildClientInterceptor}.
56
     */
57
    default boolean isClientFilter() {
58
      return false;
1✔
59
    }
60

61
    /**
62
     * Whether the filter can be installed into xDS-enabled servers.
63
     *
64
     * <p>Returns true if the filter implements {@link Filter#buildServerInterceptor}.
65
     */
66
    default boolean isServerFilter() {
67
      return false;
1✔
68
    }
69

70
    /**
71
     * Creates a new instance of the filter.
72
     *
73
     * <p>Returns a filter instance registered with the same typeUrls as the provider,
74
     * capable of working with the same FilterConfig type returned by provider's parse functions.
75
     */
76
    Filter newInstance();
77

78
    /**
79
     * Parses the top-level filter config from raw proto message. The message may be either a {@link
80
     * com.google.protobuf.Any} or a {@link com.google.protobuf.Struct}.
81
     */
82
    ConfigOrError<? extends FilterConfig> parseFilterConfig(Message rawProtoMessage);
83

84
    /**
85
     * Parses the per-filter override filter config from raw proto message. The message may be
86
     * either a {@link com.google.protobuf.Any} or a {@link com.google.protobuf.Struct}.
87
     */
88
    ConfigOrError<? extends FilterConfig> parseFilterConfigOverride(Message rawProtoMessage);
89
  }
90

91
  /** Uses the FilterConfigs produced above to produce an HTTP filter interceptor for clients. */
92
  @Nullable
93
  default ClientInterceptor buildClientInterceptor(
94
      FilterConfig config, @Nullable FilterConfig overrideConfig,
95
      ScheduledExecutorService scheduler) {
96
    return null;
1✔
97
  }
98

99
  /** Uses the FilterConfigs produced above to produce an HTTP filter interceptor for the server. */
100
  @Nullable
101
  default ServerInterceptor buildServerInterceptor(
102
      FilterConfig config, @Nullable FilterConfig overrideConfig) {
103
    return null;
1✔
104
  }
105

106
  /** Filter config with instance name. */
107
  final class NamedFilterConfig {
108
    // filter instance name
109
    final String name;
110
    final FilterConfig filterConfig;
111

112
    NamedFilterConfig(String name, FilterConfig filterConfig) {
1✔
113
      this.name = name;
1✔
114
      this.filterConfig = filterConfig;
1✔
115
    }
1✔
116

117
    @Override
118
    public boolean equals(Object o) {
119
      if (this == o) {
1✔
120
        return true;
×
121
      }
122
      if (o == null || getClass() != o.getClass()) {
1✔
123
        return false;
×
124
      }
125
      NamedFilterConfig that = (NamedFilterConfig) o;
1✔
126
      return Objects.equals(name, that.name)
1✔
127
          && Objects.equals(filterConfig, that.filterConfig);
1✔
128
    }
129

130
    @Override
131
    public int hashCode() {
132
      return Objects.hash(name, filterConfig);
1✔
133
    }
134

135
    @Override
136
    public String toString() {
137
      return MoreObjects.toStringHelper(this)
1✔
138
          .add("name", name)
1✔
139
          .add("filterConfig", filterConfig)
1✔
140
          .toString();
1✔
141
    }
142
  }
143
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc