Skip to content

Commit

Permalink
Migrate GlobalInterceptors to ConfiguratorRegistry
Browse files Browse the repository at this point in the history
This should preserve all the existing behavior of GlobalInterceptors as
used by grpc-gcp-observability, including it disabling the implicit
OpenCensus integration.

Both the old and new API are internal. I hid Configurator and
ConfiguratorRegistry behind Internal-prefixed classes, like had been
done with GlobalInterceptors to further discourage use until the API is
ready.

GlobalInterceptorsTest was modified to become ConfiguratorRegistryTest.
  • Loading branch information
ejona86 committed May 8, 2024
1 parent f16b6f2 commit 18cf46e
Show file tree
Hide file tree
Showing 16 changed files with 309 additions and 413 deletions.
3 changes: 1 addition & 2 deletions api/src/main/java/io/grpc/Configurator.java
Expand Up @@ -19,8 +19,7 @@
/**
* Provides hooks for modifying gRPC channels and servers during their construction.
*/
@Internal
public interface Configurator {
interface Configurator {
/**
* Allows implementations to modify the channel builder.
*
Expand Down
25 changes: 18 additions & 7 deletions api/src/main/java/io/grpc/ConfiguratorRegistry.java
Expand Up @@ -19,17 +19,22 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.concurrent.GuardedBy;

/**
* A registry for {@link Configurator} instances.
*
* <p>This class is responsible for maintaining a list of configurators and providing access to
* them. The default registry can be obtained using {@link #getDefaultRegistry()}.
*/
@Internal
public final class ConfiguratorRegistry {
final class ConfiguratorRegistry {
private static ConfiguratorRegistry instance;
private static boolean isConfiguratorsSet;

@GuardedBy("this")
private boolean wasConfiguratorsSet;
@GuardedBy("this")
private boolean configFrozen;
@GuardedBy("this")
private List<Configurator> configurators = Collections.emptyList();

ConfiguratorRegistry() {}
Expand All @@ -50,18 +55,24 @@ public static synchronized ConfiguratorRegistry getDefaultRegistry() {
* @param configurators the configurators to set
* @throws IllegalStateException if this method is called more than once
*/
public synchronized void setConfigurators(List<Configurator> configurators) {
if (isConfiguratorsSet) {
public synchronized void setConfigurators(List<? extends Configurator> configurators) {
if (configFrozen) {
throw new IllegalStateException("Configurators are already set");
}
configurators = Collections.unmodifiableList(new ArrayList<>(configurators));
isConfiguratorsSet = true;
this.configurators = Collections.unmodifiableList(new ArrayList<>(configurators));
configFrozen = true;
wasConfiguratorsSet = true;
}

/**
* Returns a list of the configurators in this registry.
*/
public synchronized List<Configurator> getConfigurators() {
configFrozen = true;
return configurators;
}

public synchronized boolean wasSetConfiguratorsCalled() {
return wasConfiguratorsSet;
}
}
93 changes: 0 additions & 93 deletions api/src/main/java/io/grpc/GlobalInterceptors.java

This file was deleted.

23 changes: 23 additions & 0 deletions api/src/main/java/io/grpc/InternalConfigurator.java
@@ -0,0 +1,23 @@
/*
* Copyright 2024 The gRPC Authors
*
* 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 io.grpc;

/**
* Internal access to Configurator API.
*/
@Internal
public interface InternalConfigurator extends Configurator {}
51 changes: 51 additions & 0 deletions api/src/main/java/io/grpc/InternalConfiguratorRegistry.java
@@ -0,0 +1,51 @@
/*
* Copyright 2024 The gRPC Authors
*
* 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 io.grpc;

import java.util.List;

/**
* Access internal global configurators.
*/
@Internal
public final class InternalConfiguratorRegistry {
private InternalConfiguratorRegistry() {}

public static void setConfigurators(List<InternalConfigurator> configurators) {
ConfiguratorRegistry.getDefaultRegistry().setConfigurators(configurators);
}

public static List<?> getConfigurators() {
return ConfiguratorRegistry.getDefaultRegistry().getConfigurators();
}

public static void configureChannelBuilder(ManagedChannelBuilder<?> channelBuilder) {
for (Configurator configurator : ConfiguratorRegistry.getDefaultRegistry().getConfigurators()) {
configurator.configureChannelBuilder(channelBuilder);
}
}

public static void configureServerBuilder(ServerBuilder<?> serverBuilder) {
for (Configurator configurator : ConfiguratorRegistry.getDefaultRegistry().getConfigurators()) {
configurator.configureServerBuilder(serverBuilder);
}
}

public static boolean wasSetConfiguratorsCalled() {
return ConfiguratorRegistry.getDefaultRegistry().wasSetConfiguratorsCalled();
}
}
46 changes: 0 additions & 46 deletions api/src/main/java/io/grpc/InternalGlobalInterceptors.java

This file was deleted.

100 changes: 100 additions & 0 deletions api/src/test/java/io/grpc/ConfiguratorRegistryTest.java
@@ -0,0 +1,100 @@
/*
* Copyright 2022 The gRPC Authors
*
* 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 io.grpc;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class ConfiguratorRegistryTest {

private final StaticTestingClassLoader classLoader =
new StaticTestingClassLoader(
getClass().getClassLoader(), Pattern.compile("io\\.grpc\\.[^.]+"));

@Test
public void setConfigurators() throws Exception {
Class<?> runnable = classLoader.loadClass(StaticTestingClassLoaderSet.class.getName());
((Runnable) runnable.getDeclaredConstructor().newInstance()).run();
}

@Test
public void setGlobalConfigurators_twice() throws Exception {
Class<?> runnable = classLoader.loadClass(StaticTestingClassLoaderSetTwice.class.getName());
((Runnable) runnable.getDeclaredConstructor().newInstance()).run();
}

@Test
public void getBeforeSet() throws Exception {
Class<?> runnable =
classLoader.loadClass(
StaticTestingClassLoaderGetBeforeSet.class.getName());
((Runnable) runnable.getDeclaredConstructor().newInstance()).run();
}

// UsedReflectively
public static final class StaticTestingClassLoaderSet implements Runnable {
@Override
public void run() {
List<Configurator> configurators = Arrays.asList(new NoopConfigurator());

ConfiguratorRegistry.getDefaultRegistry().setConfigurators(configurators);

assertThat(ConfiguratorRegistry.getDefaultRegistry().getConfigurators())
.isEqualTo(configurators);
}
}

public static final class StaticTestingClassLoaderSetTwice implements Runnable {
@Override
public void run() {
ConfiguratorRegistry.getDefaultRegistry()
.setConfigurators(Arrays.asList(new NoopConfigurator()));
try {
ConfiguratorRegistry.getDefaultRegistry()
.setConfigurators(Arrays.asList(new NoopConfigurator()));
fail("should have failed for calling setConfigurators() again");
} catch (IllegalStateException e) {
assertThat(e).hasMessageThat().isEqualTo("Configurators are already set");
}
}
}

public static final class StaticTestingClassLoaderGetBeforeSet implements Runnable {
@Override
public void run() {
assertThat(ConfiguratorRegistry.getDefaultRegistry().getConfigurators()).isEmpty();

try {
ConfiguratorRegistry.getDefaultRegistry()
.setConfigurators(Arrays.asList(new NoopConfigurator()));
fail("should have failed for invoking set call after get is already called");
} catch (IllegalStateException e) {
assertThat(e).hasMessageThat().isEqualTo("Configurators are already set");
}
}
}

private static class NoopConfigurator implements Configurator {}
}

0 comments on commit 18cf46e

Please sign in to comment.