Skip to content

Commit 9c6074e

Browse files
authored
Merge pull request #14 from dbos-inc/manoj/tomcat
Manoj/tomcat
2 parents d33acb4 + dcaf265 commit 9c6074e

9 files changed

Lines changed: 392 additions & 1 deletion

File tree

build.gradle.kts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ dependencies {
2929
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.0")
3030
implementation("com.cronutils:cron-utils:9.2.1") // cron for scheduled wf
3131

32+
// http + jersey
33+
implementation("org.apache.tomcat.embed:tomcat-embed-core:10.1.12")
34+
implementation("org.apache.tomcat.embed:tomcat-embed-jasper:10.1.12")
35+
implementation("jakarta.ws.rs:jakarta.ws.rs-api:3.1.0")
36+
implementation("jakarta.servlet:jakarta.servlet-api:6.0.0")
37+
implementation("org.glassfish.jersey.containers:jersey-container-servlet-core:3.1.0")
38+
implementation("org.glassfish.jersey.inject:jersey-hk2:3.1.1")
39+
implementation("org.glassfish.jersey.core:jersey-server:3.1.0")
40+
3241
testImplementation("ch.qos.logback:logback-classic:1.5.6")
3342
testImplementation("org.mockito:mockito-core:5.12.0")
3443
testImplementation(platform("org.junit:junit-bom:5.10.0"))

src/main/java/dev/dbos/transact/DBOS.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import dev.dbos.transact.config.DBOSConfig;
44
import dev.dbos.transact.database.SystemDatabase;
55
import dev.dbos.transact.execution.DBOSExecutor;
6+
import dev.dbos.transact.http.HttpServer;
67
import dev.dbos.transact.interceptor.AsyncInvocationHandler;
78
import dev.dbos.transact.interceptor.QueueInvocationHandler;
89
import dev.dbos.transact.interceptor.TransactInvocationHandler;
@@ -31,6 +32,7 @@ public class DBOS {
3132
private QueueService queueService ;
3233
private SchedulerService schedulerService ;
3334
private NotificationService notificationService ;
35+
private HttpServer httpServer ;
3436

3537
private final AtomicBoolean isShutdown = new AtomicBoolean(false);
3638

@@ -217,8 +219,24 @@ public void launch() {
217219
notificationService.start();
218220
}
219221

222+
if (config.isHttp()) {
223+
httpServer = HttpServer.getInstance(config.getHttpPort());
224+
if (config.isHttpAwaitOnStart()) {
225+
Thread httpThread = new Thread(() ->
226+
{ logger.info("Start http in background thread") ;
227+
httpServer.startAndBlock() ;
228+
}, "http-server-thread");
229+
httpThread.setDaemon(false); // Keep process alive
230+
httpThread.start();
231+
} else {
232+
httpServer.start();
233+
}
234+
}
235+
220236
}
221237

238+
239+
222240
public void shutdown() {
223241

224242
if (isShutdown.compareAndSet(false, true)) {
@@ -240,6 +258,10 @@ public void shutdown() {
240258
notificationService.stop();
241259
}
242260

261+
if (config.isHttp()) {
262+
httpServer.stop();
263+
}
264+
243265
instance = null;
244266
}
245267
}
Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,31 @@
11
package dev.dbos.transact;
22

3+
import dev.dbos.transact.config.DBOSConfig;
4+
35
public class Main {
46
public static void main(String[] args) {
5-
System.out.println("Hello DBOS Transact!");
7+
8+
try {
9+
DBOSConfig dbosConfig = new DBOSConfig
10+
.Builder()
11+
.name("systemdbtest")
12+
.dbHost("localhost")
13+
.dbPort(5432)
14+
.dbUser("postgres")
15+
.sysDbName("dbos_java_sys")
16+
.maximumPoolSize(2)
17+
.runAdminServer()
18+
.adminServerPort(8080)
19+
.build();
20+
21+
DBOS.initialize(dbosConfig);
22+
DBOS dbos = DBOS.getInstance();
23+
dbos.launch();
24+
25+
} catch(Exception e) {
26+
System.out.println(e);
27+
}
28+
29+
630
}
731
}

src/main/java/dev/dbos/transact/config/DBOSConfig.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import dev.dbos.transact.Constants;
66

77
import javax.sql.DataSource;
8+
import java.util.ArrayList;
9+
import java.util.Arrays;
10+
import java.util.List;
811

912
public class DBOSConfig {
1013
private final String name;
@@ -17,6 +20,10 @@ public class DBOSConfig {
1720
private final int connectionTimeout;
1821
private final String appDbName;
1922
private final String sysDbName;
23+
private final boolean http ;
24+
private final int httpPort ;
25+
private final boolean httpAwaitOnStart ;
26+
2027

2128
private DBOSConfig(Builder builder) {
2229
this.name = builder.name;
@@ -29,6 +36,9 @@ private DBOSConfig(Builder builder) {
2936
this.dbPassword = builder.dbPassword;
3037
this.dbHost = builder.dbHost;
3138
this.dbPort = builder.dbPort;
39+
this.http = builder.http ;
40+
this.httpPort = builder.httpPort ;
41+
this.httpAwaitOnStart = builder.httpAwaitOnStart;
3242

3343
}
3444

@@ -43,6 +53,9 @@ public static class Builder {
4353
private int connectionTimeout = 30000;
4454
private String appDbName;
4555
private String sysDbName;
56+
private boolean http = false ;
57+
private int httpPort ;
58+
private boolean httpAwaitOnStart = true ;
4659

4760
public Builder name(String name) {
4861
this.name = name;
@@ -94,6 +107,21 @@ public Builder sysDbName(String sysDbName) {
94107
return this;
95108
}
96109

110+
public Builder runAdminServer() {
111+
this.http = true ;
112+
return this;
113+
}
114+
115+
public Builder adminServerPort(int port) {
116+
this.httpPort = port;
117+
return this;
118+
}
119+
120+
public Builder adminAwaitOnStart(boolean wait) {
121+
this.httpAwaitOnStart = wait;
122+
return this;
123+
}
124+
97125
public DBOSConfig build() {
98126
if (name == null) throw new IllegalArgumentException("Name is required");
99127
if (dbPassword == null) {
@@ -144,6 +172,18 @@ public int getDbPort() {
144172
return dbPort;
145173
}
146174

175+
public boolean isHttp() {
176+
return http;
177+
}
178+
179+
public int getHttpPort() {
180+
return httpPort;
181+
}
182+
183+
public boolean isHttpAwaitOnStart() {
184+
return httpAwaitOnStart;
185+
}
186+
147187
@Override
148188
public String toString() {
149189
return "DBOSConfig{" +
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package dev.dbos.transact.http;
2+
3+
import dev.dbos.transact.http.controllers.AdminController;
4+
import jakarta.servlet.Servlet;
5+
import org.apache.catalina.Context;
6+
import org.apache.catalina.Wrapper;
7+
import org.apache.catalina.connector.Connector;
8+
import org.apache.catalina.core.StandardContext;
9+
import org.apache.catalina.core.StandardWrapper;
10+
import org.apache.catalina.startup.Tomcat;
11+
import org.glassfish.jersey.server.ResourceConfig;
12+
import org.glassfish.jersey.servlet.ServletContainer;
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
15+
16+
import java.io.File;
17+
import java.util.ArrayList;
18+
import java.util.List;
19+
20+
public class HttpServer {
21+
22+
private Tomcat tomcat;
23+
private int port;
24+
25+
Logger logger = LoggerFactory.getLogger(HttpServer.class);
26+
27+
private HttpServer(int port) {
28+
this.port = port == 0 ? 3001 : port;
29+
}
30+
31+
private void init() {
32+
tomcat = new Tomcat();
33+
setUpContext();
34+
}
35+
36+
public static HttpServer getInstance(int port) {
37+
HttpServer s = new HttpServer(port);
38+
s.init();
39+
return s;
40+
41+
}
42+
43+
public void start() {
44+
45+
try {
46+
tomcat.start();
47+
} catch(Exception e) {
48+
logger.error("Error starting http server", e) ;
49+
}
50+
}
51+
52+
public void startAndBlock() {
53+
start();
54+
tomcat.getServer().await();
55+
}
56+
57+
public void stop() {
58+
try {
59+
tomcat.stop();
60+
tomcat.destroy();
61+
} catch(Exception e) {
62+
logger.error("Error stopping httpserver", e) ;
63+
}
64+
}
65+
66+
67+
private void setUpContext() {
68+
69+
tomcat.setPort(port);
70+
tomcat.getConnector(); // default connector
71+
72+
String contextPath = "";
73+
String docBase = new File(".").getAbsolutePath();
74+
75+
Context context = tomcat.addContext(contextPath, docBase);
76+
77+
ResourceConfig resourceConfig = new ResourceConfig() ;
78+
resourceConfig.registerInstances(new AdminController()) ;
79+
80+
// In future if we need to scan from a package
81+
// resourceConfig.packages(pkg);
82+
83+
// Add the REST API servlet
84+
var jerseyservlet = tomcat.addServlet(contextPath, "jersey-servlet", new ServletContainer(resourceConfig));
85+
context.addServletMappingDecoded("/*", "jersey-servlet");
86+
87+
}
88+
89+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package dev.dbos.transact.http.controllers;
2+
3+
4+
import dev.dbos.transact.workflow.ListWorkflowsInput;
5+
import dev.dbos.transact.workflow.StepInfo;
6+
import dev.dbos.transact.workflow.WorkflowStatus;
7+
import jakarta.ws.rs.*;
8+
import jakarta.ws.rs.core.MediaType;
9+
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
13+
@Path("/")
14+
public class AdminController {
15+
16+
@GET
17+
@Path("/healthz")
18+
@Produces(MediaType.TEXT_PLAIN)
19+
public String health() {
20+
return "Healthy";
21+
}
22+
23+
@GET
24+
@Path("/deactivate")
25+
@Produces(MediaType.TEXT_PLAIN)
26+
public String deactivate() {
27+
return "deactivated";
28+
}
29+
30+
@GET
31+
@Path("/workflow-queues-metadata")
32+
@Produces(MediaType.APPLICATION_JSON)
33+
public Object workflowQueuesMetadata() {
34+
return "queuesMetadata";
35+
}
36+
37+
@GET
38+
@Path("/workflows/{workflowId}/steps")
39+
@Produces(MediaType.APPLICATION_JSON)
40+
public List<StepInfo> ListSteps(@PathParam("workflowId") String workflowId) {
41+
return new ArrayList<>() ;
42+
}
43+
44+
@GET
45+
@Path("/workflows/{workflowId}")
46+
@Produces(MediaType.APPLICATION_JSON)
47+
public List<WorkflowStatus> ListWorkflows(@PathParam("workflowId") String workflowId) {
48+
return new ArrayList<>() ;
49+
}
50+
51+
@POST
52+
@Path("/recovery")
53+
@Produces(MediaType.APPLICATION_JSON)
54+
public List<String> recovery() {
55+
56+
return new ArrayList<>();
57+
}
58+
59+
@POST
60+
@Path("/workflows")
61+
@Consumes(MediaType.APPLICATION_JSON)
62+
@Produces(MediaType.APPLICATION_JSON)
63+
public List<WorkflowStatus> workflows( ListWorkflowsInput input) {
64+
65+
return new ArrayList<>();
66+
}
67+
68+
@POST
69+
@Path("/workflows/{workflowId}/restart")
70+
@Produces(MediaType.APPLICATION_JSON)
71+
public void restart(@PathParam("workflowId") String workflowId) {
72+
73+
74+
}
75+
76+
@POST
77+
@Path("/workflows/{workflowId}/resume")
78+
@Produces(MediaType.APPLICATION_JSON)
79+
public void resume(@PathParam("workflowId") String workflowId) {
80+
81+
82+
}
83+
84+
@POST
85+
@Path("/workflows/{workflowId}/fork")
86+
@Produces(MediaType.APPLICATION_JSON)
87+
public void fork(@PathParam("workflowId") String workflowId) {
88+
89+
90+
}
91+
92+
@POST
93+
@Path("/workflows/{workflowId}/cancel")
94+
@Produces(MediaType.APPLICATION_JSON)
95+
public void cancel(@PathParam("workflowId") String workflowId) {
96+
97+
98+
}
99+
100+
101+
}

0 commit comments

Comments
 (0)