Skip to content

Commit acdbcee

Browse files
feat: add http service framework (#50)
* feat: add http service framework * refactor: add functional interface
1 parent 732e53b commit acdbcee

12 files changed

+418
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
plugins {
2+
`java-library`
3+
id("org.hypertrace.publish-plugin")
4+
}
5+
6+
dependencies {
7+
api(project(":platform-service-framework"))
8+
api("org.hypertrace.core.grpcutils:grpc-client-utils:0.7.6")
9+
api("com.typesafe:config:1.4.2")
10+
api("javax.servlet:javax.servlet-api:4.0.1")
11+
api("com.google.inject:guice:5.1.0")
12+
api(project(":service-framework-spi"))
13+
14+
implementation("org.slf4j:slf4j-api:1.7.36")
15+
implementation("com.google.inject.extensions:guice-servlet:5.1.0")
16+
implementation("com.google.guava:guava:31.1-jre")
17+
implementation("org.eclipse.jetty:jetty-servlet:9.4.48.v20220622")
18+
implementation("org.eclipse.jetty:jetty-server:9.4.48.v20220622")
19+
implementation("org.eclipse.jetty:jetty-servlets:9.4.48.v20220622")
20+
21+
annotationProcessor("org.projectlombok:lombok:1.18.24")
22+
compileOnly("org.projectlombok:lombok:1.18.24")
23+
24+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.hypertrace.core.serviceframework.http;
2+
3+
public interface HttpContainer {
4+
void start();
5+
6+
void blockUntilStopped();
7+
8+
void stop();
9+
10+
boolean isStopped();
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.hypertrace.core.serviceframework.http;
2+
3+
import com.typesafe.config.Config;
4+
import org.hypertrace.core.grpcutils.client.GrpcChannelRegistry;
5+
import org.hypertrace.core.serviceframework.spi.PlatformServiceLifecycle;
6+
7+
public interface HttpContainerEnvironment {
8+
GrpcChannelRegistry getChannelRegistry();
9+
10+
Config getConfig(String serviceName);
11+
12+
PlatformServiceLifecycle getLifecycle();
13+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.hypertrace.core.serviceframework.http;
2+
3+
import com.google.inject.Injector;
4+
import java.util.List;
5+
import javax.servlet.MultipartConfigElement;
6+
import javax.servlet.Servlet;
7+
import lombok.Builder;
8+
import lombok.Value;
9+
import lombok.experimental.Accessors;
10+
11+
@Value
12+
@Builder
13+
public class HttpHandlerDefinition {
14+
String name;
15+
int port;
16+
String contextPath;
17+
Servlet servlet;
18+
int maxHeaderSizeBytes;
19+
CorsConfig corsConfig;
20+
Injector injector;
21+
MultipartConfigElement multipartConfig;
22+
23+
@Accessors(fluent = true)
24+
boolean useSessions;
25+
26+
@Value
27+
@Builder
28+
public static class CorsConfig {
29+
List<String> allowedHeaders;
30+
List<String> allowedOrigins;
31+
}
32+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.hypertrace.core.serviceframework.http;
2+
3+
import java.util.List;
4+
5+
@FunctionalInterface
6+
public interface HttpHandlerFactory {
7+
List<HttpHandlerDefinition> buildHandlers(HttpContainerEnvironment containerEnvironment);
8+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.hypertrace.core.serviceframework.http;
2+
3+
import java.util.List;
4+
import java.util.concurrent.ExecutorService;
5+
6+
public interface ServerBuilder<T extends ServerBuilder> {
7+
T addHandler(HttpHandlerDefinition handlerDefinition);
8+
9+
T addHandlers(List<HttpHandlerDefinition> handlerDefinitions);
10+
11+
T setExecutor(ExecutorService executorService);
12+
13+
HttpContainer build();
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.hypertrace.core.serviceframework.http;
2+
3+
import com.typesafe.config.Config;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Getter;
6+
import org.hypertrace.core.grpcutils.client.GrpcChannelRegistry;
7+
import org.hypertrace.core.serviceframework.config.ConfigClient;
8+
import org.hypertrace.core.serviceframework.spi.PlatformServiceLifecycle;
9+
10+
@AllArgsConstructor
11+
public class StandAloneHttpContainerEnvironment implements HttpContainerEnvironment {
12+
@Getter private final GrpcChannelRegistry channelRegistry;
13+
@Getter private final PlatformServiceLifecycle lifecycle;
14+
private final ConfigClient configClient;
15+
16+
@Override
17+
public Config getConfig(String serviceName) {
18+
return this.configClient.getConfig(serviceName, null, null, null);
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package org.hypertrace.core.serviceframework.http;
2+
3+
import static io.grpc.Deadline.after;
4+
import static java.util.concurrent.TimeUnit.SECONDS;
5+
6+
import java.util.List;
7+
import java.util.stream.Collectors;
8+
import lombok.extern.slf4j.Slf4j;
9+
import org.hypertrace.core.grpcutils.client.GrpcChannelRegistry;
10+
import org.hypertrace.core.serviceframework.PlatformService;
11+
import org.hypertrace.core.serviceframework.config.ConfigClient;
12+
import org.hypertrace.core.serviceframework.http.jetty.JettyHttpServerBuilder;
13+
14+
@Slf4j
15+
public abstract class StandAloneHttpPlatformServiceContainer extends PlatformService {
16+
private HttpContainer container;
17+
private final GrpcChannelRegistry grpcChannelRegistry = new GrpcChannelRegistry();
18+
19+
public StandAloneHttpPlatformServiceContainer(ConfigClient config) {
20+
super(config);
21+
}
22+
23+
protected abstract List<HttpHandlerFactory> getHandlerFactories();
24+
25+
@Override
26+
protected void doInit() {
27+
this.container =
28+
new JettyHttpServerBuilder().addHandlers(this.buildHandlerDefinitions()).build();
29+
}
30+
31+
@Override
32+
protected void doStart() {
33+
log.info("Starting service {}", this.getServiceName());
34+
this.container.start();
35+
this.container.blockUntilStopped();
36+
}
37+
38+
@Override
39+
protected void doStop() {
40+
log.info("Stopping service {}", this.getServiceName());
41+
grpcChannelRegistry.shutdown(after(10, SECONDS));
42+
this.container.stop();
43+
}
44+
45+
@Override
46+
public boolean healthCheck() {
47+
return true;
48+
}
49+
50+
private List<HttpHandlerDefinition> buildHandlerDefinitions() {
51+
HttpContainerEnvironment environment =
52+
new StandAloneHttpContainerEnvironment(
53+
this.grpcChannelRegistry, this.getLifecycle(), this.configClient);
54+
return this.getHandlerFactories().stream()
55+
.flatMap(handlerFactory -> handlerFactory.buildHandlers(environment).stream())
56+
.collect(Collectors.toUnmodifiableList());
57+
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.hypertrace.core.serviceframework.http.guice;
2+
3+
import com.google.inject.Injector;
4+
import com.google.inject.servlet.GuiceServletContextListener;
5+
import lombok.RequiredArgsConstructor;
6+
7+
@RequiredArgsConstructor
8+
public class SimpleGuiceServletContextListener extends GuiceServletContextListener {
9+
private final Injector injector;
10+
11+
@Override
12+
protected Injector getInjector() {
13+
return injector;
14+
}
15+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.hypertrace.core.serviceframework.http.jetty;
2+
3+
import static java.util.concurrent.TimeUnit.SECONDS;
4+
5+
import java.util.concurrent.ExecutorService;
6+
import java.util.concurrent.Future;
7+
import lombok.RequiredArgsConstructor;
8+
import lombok.SneakyThrows;
9+
import org.eclipse.jetty.server.Server;
10+
import org.hypertrace.core.serviceframework.http.HttpContainer;
11+
12+
@RequiredArgsConstructor
13+
class JettyHttpContainer implements HttpContainer {
14+
private final Server server;
15+
private final ExecutorService executorService;
16+
private Future<?> future;
17+
18+
@Override
19+
public void start() {
20+
this.future = this.executorService.submit(this::startAndWaitUnchecked);
21+
}
22+
23+
@SneakyThrows
24+
@Override
25+
public void stop() {
26+
this.executorService.shutdown();
27+
this.executorService.awaitTermination(30, SECONDS);
28+
}
29+
30+
@SneakyThrows
31+
@Override
32+
public void blockUntilStopped() {
33+
this.future.get();
34+
}
35+
36+
@Override
37+
public boolean isStopped() {
38+
return this.server.isStopped();
39+
}
40+
41+
@SneakyThrows
42+
private void startAndWaitUnchecked() {
43+
this.server.start();
44+
this.server.join();
45+
}
46+
}

0 commit comments

Comments
 (0)