|
package example; |
|
|
|
import org.eclipse.jetty.server.Connector; |
|
import org.eclipse.jetty.server.Server; |
|
import org.eclipse.jetty.server.ServerConnector; |
|
import org.eclipse.jetty.util.thread.ThreadPool; |
|
import spark.Spark; |
|
import spark.embeddedserver.EmbeddedServers; |
|
import spark.embeddedserver.jetty.EmbeddedJettyFactory; |
|
import spark.embeddedserver.jetty.JettyServerFactory; |
|
|
|
import java.util.concurrent.ExecutorService; |
|
import java.util.concurrent.Executors; |
|
import java.util.concurrent.TimeUnit; |
|
|
|
public class SparkWithLoom { |
|
|
|
public static void main(String... args) { |
|
// We specify the host and address because Spark#ipAddress and Spark#port |
|
// won't set the host or port in this implementation right now, subject to further research... |
|
EmbeddedJettyFactory factory = createEmbeddedFactory("localhost", 4567); |
|
EmbeddedServers.add(EmbeddedServers.Identifiers.JETTY, factory); |
|
|
|
Spark.redirect.any("/", "index.html"); |
|
|
|
Spark.get("/index.html", (request, response) -> { |
|
response.type("text/html;charset=utf-8"); |
|
String htmlPage = """ |
|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Hello SparkJava + Project Loom Virtual Threads</title> |
|
</head> |
|
<body> |
|
<div> |
|
<h1 id="awesome-header">Awesome</h1> |
|
<p>This is an HTML page served by SparkJava (Jetty) using Project Loom's Virtual Threads</p> |
|
|
|
<p id="hidden-message" style="display: none"> |
|
Maybe, you didn't notice but text block was made visible by JavaScript which is being served via <code>/js/generated.js</code> endpoint |
|
and implemented with the following code: |
|
<code><pre> |
|
Spark.get("/js/generated.js", (request, response) -> { |
|
response.type("application/javascript"); |
|
return ""\" |
|
document.addEventListener("DOMContentLoaded", (event) => { |
|
console.log("Some JavaScript generated by the server!"); |
|
let awEl = document.getElementById("awesome-header"); |
|
let hiddenEl = document.getElementById("hidden-message"); |
|
|
|
awEl.innerHTML = "Java is Awesome!"; |
|
hiddenEl.style = "display: block;"; |
|
}); |
|
""\"; |
|
}); |
|
</pre></code> |
|
</div> |
|
<script type="text/javascript" src="/js/generated.js"></script> |
|
</body> |
|
</html> |
|
"""; |
|
|
|
return htmlPage; |
|
}); |
|
|
|
Spark.get("/js/generated.js", (request, response) -> { |
|
response.type("application/javascript"); |
|
return """ |
|
document.addEventListener("DOMContentLoaded", (event) => { |
|
console.log("Some JavaScript generated by the server!"); |
|
let awEl = document.getElementById("awesome-header"); |
|
let hiddenEl = document.getElementById("hidden-message"); |
|
|
|
awEl.innerHTML = "Java is Awesome!"; |
|
hiddenEl.style = "display: block;"; |
|
}); |
|
"""; |
|
}); |
|
} |
|
|
|
public static EmbeddedJettyFactory createEmbeddedFactory(String ipAddress, int port) { |
|
return new EmbeddedJettyFactory(new JettyServerFactory() { |
|
@Override |
|
public Server create(int i, int i1, int i2) { |
|
var server = new Server(new LoomThreadPool()); |
|
ServerConnector connector = new ServerConnector(server); |
|
connector.setHost(ipAddress); |
|
connector.setPort(port); |
|
server.setConnectors(new Connector[]{connector}); |
|
// server.setRequestLog(requestLog); |
|
return server; |
|
} |
|
|
|
@Override |
|
public Server create(ThreadPool threadPool) { |
|
return create(1, 1, 1); |
|
} |
|
}); |
|
} |
|
|
|
// Copied from: https://github.com/rodrigovedovato/jetty-loom |
|
public static class LoomThreadPool implements ThreadPool { |
|
ExecutorService executorService = Executors.newVirtualThreadExecutor(); |
|
|
|
@Override |
|
public void join() throws InterruptedException { |
|
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); |
|
} |
|
|
|
@Override |
|
public int getThreads() { |
|
return 1; |
|
} |
|
|
|
@Override |
|
public int getIdleThreads() { |
|
return 1; |
|
} |
|
|
|
@Override |
|
public boolean isLowOnThreads() { |
|
return false; |
|
} |
|
|
|
@Override |
|
public void execute(Runnable command) { |
|
executorService.submit(command); |
|
} |
|
} |
|
} |