Skip to content

Commit

Permalink
Provide a way to configure server for a plugin (#883)
Browse files Browse the repository at this point in the history
Motivation:
Currently, there's no way to configure the Armeria server outside of the server module. We can perhaps do this by providing DI, SPI, or adding a method to `Plugin`.

Modification:
- Add `AllReplicasPlugin` class for configuring Central Dogma server

Result:
- You can now add configurations to the Central Dogma server for your plugin using `AllReplicasPlugin.init()` method.
  • Loading branch information
minwoox authored Sep 26, 2023
1 parent 75dfb2b commit 027f32e
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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<Void> start(PluginContext context) {
return UnmodifiableFuture.completedFuture(null);
}

@Override
public CompletionStage<Void> stop(PluginContext context) {
return UnmodifiableFuture.completedFuture(null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.linecorp.centraldogma.it.TestAllReplicasPlugin
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}

0 comments on commit 027f32e

Please sign in to comment.