diff --git a/it/server/src/test/java/com/linecorp/centraldogma/it/AllReplicasPluginTest.java b/it/server/src/test/java/com/linecorp/centraldogma/it/AllReplicasPluginTest.java new file mode 100644 index 0000000000..39d036fb65 --- /dev/null +++ b/it/server/src/test/java/com/linecorp/centraldogma/it/AllReplicasPluginTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023 LINE Corporation + * + * LINE Corporation licenses this file to you 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: + * + * https://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.linecorp.centraldogma.it; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.linecorp.armeria.common.AggregatedHttpResponse; +import com.linecorp.armeria.common.HttpStatus; +import com.linecorp.centraldogma.testing.junit.CentralDogmaExtension; + +final class AllReplicasPluginTest { + + @RegisterExtension + static final CentralDogmaExtension dogma = new CentralDogmaExtension(); + + @Test + void hello() { + // hello service is registered by TestAllReplicasPlugin. + final AggregatedHttpResponse res = dogma.httpClient().get("/hello").aggregate().join(); + assertThat(res.status()).isSameAs(HttpStatus.OK); + } +} diff --git a/it/server/src/test/java/com/linecorp/centraldogma/it/TestAllReplicasPlugin.java b/it/server/src/test/java/com/linecorp/centraldogma/it/TestAllReplicasPlugin.java new file mode 100644 index 0000000000..21629fabf7 --- /dev/null +++ b/it/server/src/test/java/com/linecorp/centraldogma/it/TestAllReplicasPlugin.java @@ -0,0 +1,44 @@ +/* + * Copyright 2023 LINE Corporation + * + * LINE Corporation licenses this file to you 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: + * + * https://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.linecorp.centraldogma.it; + +import java.util.concurrent.CompletionStage; + +import com.linecorp.armeria.common.HttpResponse; +import com.linecorp.armeria.common.util.UnmodifiableFuture; +import com.linecorp.centraldogma.server.plugin.AllReplicasPlugin; +import com.linecorp.centraldogma.server.plugin.PluginContext; +import com.linecorp.centraldogma.server.plugin.PluginInitContext; + +public final class TestAllReplicasPlugin extends AllReplicasPlugin { + + @Override + public void init(PluginInitContext pluginInitContext) { + pluginInitContext.serverBuilder() + .service("/hello", (ctx, req) -> HttpResponse.of("Hello, world!")); + } + + @Override + public CompletionStage start(PluginContext context) { + return UnmodifiableFuture.completedFuture(null); + } + + @Override + public CompletionStage stop(PluginContext context) { + return UnmodifiableFuture.completedFuture(null); + } +} diff --git a/it/server/src/test/resources/META-INF/services/com.linecorp.centraldogma.server.plugin.Plugin b/it/server/src/test/resources/META-INF/services/com.linecorp.centraldogma.server.plugin.Plugin new file mode 100644 index 0000000000..3735914e37 --- /dev/null +++ b/it/server/src/test/resources/META-INF/services/com.linecorp.centraldogma.server.plugin.Plugin @@ -0,0 +1 @@ +com.linecorp.centraldogma.it.TestAllReplicasPlugin diff --git a/server/src/main/java/com/linecorp/centraldogma/server/CentralDogma.java b/server/src/main/java/com/linecorp/centraldogma/server/CentralDogma.java index f09c03112e..ca8a9fc41f 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/CentralDogma.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/CentralDogma.java @@ -145,7 +145,9 @@ import com.linecorp.centraldogma.server.internal.thrift.TokenlessClientLogger; import com.linecorp.centraldogma.server.metadata.MetadataService; import com.linecorp.centraldogma.server.metadata.MetadataServiceInjector; +import com.linecorp.centraldogma.server.plugin.AllReplicasPlugin; import com.linecorp.centraldogma.server.plugin.Plugin; +import com.linecorp.centraldogma.server.plugin.PluginInitContext; import com.linecorp.centraldogma.server.plugin.PluginTarget; import com.linecorp.centraldogma.server.storage.project.ProjectManager; @@ -364,7 +366,7 @@ private void doStart() throws Exception { } logger.info("Starting the RPC server."); - server = startServer(pm, executor, meterRegistry, sessionManager); + server = startServer(pm, executor, purgeWorker, meterRegistry, sessionManager); logger.info("Started the RPC server at: {}", server.activePorts()); logger.info("Started the Central Dogma successfully."); success = true; @@ -489,7 +491,8 @@ private SessionManager initializeSessionManager() throws Exception { } private Server startServer(ProjectManager pm, CommandExecutor executor, - MeterRegistry meterRegistry, @Nullable SessionManager sessionManager) { + ScheduledExecutorService purgeWorker, MeterRegistry meterRegistry, + @Nullable SessionManager sessionManager) { final ServerBuilder sb = Server.builder(); sb.verboseResponses(true); cfg.ports().forEach(sb::port); @@ -558,6 +561,18 @@ private Server startServer(ProjectManager pm, CommandExecutor executor, sb.accessLogFormat(accessLogFormat); } + if (pluginsForAllReplicas != null) { + final PluginInitContext pluginInitContext = + new PluginInitContext(config(), pm, executor, meterRegistry, purgeWorker, sb); + pluginsForAllReplicas.plugins() + .forEach(p -> { + if (!(p instanceof AllReplicasPlugin)) { + return; + } + final AllReplicasPlugin plugin = (AllReplicasPlugin) p; + plugin.init(pluginInitContext); + }); + } // Configure the uncaught exception handler just before starting the server so that override the // default exception handler set by third-party libraries such as NIOServerCnxnFactory. Thread.setDefaultUncaughtExceptionHandler((t, e) -> logger.warn("Uncaught exception: {}", t, e)); diff --git a/server/src/main/java/com/linecorp/centraldogma/server/plugin/AllReplicasPlugin.java b/server/src/main/java/com/linecorp/centraldogma/server/plugin/AllReplicasPlugin.java new file mode 100644 index 0000000000..7c4ecf1a20 --- /dev/null +++ b/server/src/main/java/com/linecorp/centraldogma/server/plugin/AllReplicasPlugin.java @@ -0,0 +1,32 @@ +/* + * Copyright 2023 LINE Corporation + * + * LINE Corporation licenses this file to you 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: + * + * https://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.linecorp.centraldogma.server.plugin; + +/** + * A Base class for {@link Plugin} whose {@link #target()} is {@link PluginTarget#ALL_REPLICAS}. + */ +public abstract class AllReplicasPlugin implements Plugin { + + /** + * Overrides this method to initialize the plugin using the {@link PluginInitContext}. + */ + public void init(PluginInitContext pluginInitContext) {} + + @Override + public final PluginTarget target() { + return PluginTarget.ALL_REPLICAS; + } +} diff --git a/server/src/main/java/com/linecorp/centraldogma/server/plugin/Plugin.java b/server/src/main/java/com/linecorp/centraldogma/server/plugin/Plugin.java index 9617af5769..4c2c8a9d01 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/plugin/Plugin.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/plugin/Plugin.java @@ -20,7 +20,8 @@ import com.linecorp.centraldogma.server.CentralDogmaConfig; /** - * An interface which defines callbacks for a plug-in. + * An interface which defines callbacks for a plug-in. If you want to initialize a {@link Plugin} by configuring + * the Central Dogma server (e.g. adding a service for your plugin), use {@link AllReplicasPlugin}. */ public interface Plugin { /** diff --git a/server/src/main/java/com/linecorp/centraldogma/server/plugin/PluginContext.java b/server/src/main/java/com/linecorp/centraldogma/server/plugin/PluginContext.java index 8cfbfe42ae..9e667ff7f2 100644 --- a/server/src/main/java/com/linecorp/centraldogma/server/plugin/PluginContext.java +++ b/server/src/main/java/com/linecorp/centraldogma/server/plugin/PluginContext.java @@ -30,7 +30,7 @@ /** * A class which is used to pass internally-created instances into the {@link Plugin}. */ -public final class PluginContext { +public class PluginContext { private final CentralDogmaConfig config; private final ProjectManager projectManager; diff --git a/server/src/main/java/com/linecorp/centraldogma/server/plugin/PluginInitContext.java b/server/src/main/java/com/linecorp/centraldogma/server/plugin/PluginInitContext.java new file mode 100644 index 0000000000..5c1e7770c9 --- /dev/null +++ b/server/src/main/java/com/linecorp/centraldogma/server/plugin/PluginInitContext.java @@ -0,0 +1,56 @@ +/* + * Copyright 2023 LINE Corporation + * + * LINE Corporation licenses this file to you 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: + * + * https://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.linecorp.centraldogma.server.plugin; + +import static java.util.Objects.requireNonNull; + +import java.util.concurrent.ScheduledExecutorService; + +import com.linecorp.armeria.server.ServerBuilder; +import com.linecorp.centraldogma.server.CentralDogmaConfig; +import com.linecorp.centraldogma.server.command.CommandExecutor; +import com.linecorp.centraldogma.server.storage.project.ProjectManager; + +import io.micrometer.core.instrument.MeterRegistry; + +/** + * A context that is used to pass when calling {@link AllReplicasPlugin#init(PluginInitContext)}. + */ +public final class PluginInitContext extends PluginContext { + + private final ServerBuilder serverBuilder; + + /** + * Creates a new instance. + */ + public PluginInitContext(CentralDogmaConfig config, + ProjectManager projectManager, + CommandExecutor commandExecutor, + MeterRegistry meterRegistry, + ScheduledExecutorService purgeWorker, + ServerBuilder serverBuilder) { + super(config, projectManager, commandExecutor, meterRegistry, purgeWorker); + this.serverBuilder = requireNonNull(serverBuilder, "serverBuilder"); + } + + /** + * Returns the {@link ServerBuilder} of the Central Dogma server. + */ + public ServerBuilder serverBuilder() { + return serverBuilder; + } +}