diff --git a/avaje-jex-static-content/src/main/java/io/avaje/jex/staticcontent/StaticContent.java b/avaje-jex-static-content/src/main/java/io/avaje/jex/staticcontent/StaticContent.java new file mode 100644 index 0000000..d3baf45 --- /dev/null +++ b/avaje-jex-static-content/src/main/java/io/avaje/jex/staticcontent/StaticContent.java @@ -0,0 +1,127 @@ +package io.avaje.jex.staticcontent; + +import java.net.URLConnection; +import java.util.function.Predicate; + +import io.avaje.jex.Context; +import io.avaje.jex.spi.JexPlugin; + +/** + * Static content resource handler. + *
{@code + * + * var staticContent = StaticContent.createFile("src/test/resources/public") + * .directoryIndex("index.html") + * .preCompress() + * .build() + * + * Jex.create() + * .plugin(staticContent) + * .port(8080) + * .start(); + * + * }+ */ +public sealed interface StaticContent extends JexPlugin + permits StaticResourceHandlerBuilder { + + /** + * Create and return a new static content class path configuration. + * + * @param resourceRoot The file to serve, or the directory the files are located in. + */ + static Builder createCP(String resourceRoot) { + return StaticResourceHandlerBuilder.builder(resourceRoot); + } + + /** + * Create and return a new static content class path configuration with the + * `/public` directory as the root. + */ + static Builder createCP() { + return StaticResourceHandlerBuilder.builder("/public/"); + } + + /** + * Create and return a new static content configuration for a File. + * + * @param resourceRoot The path of the file to serve, or the directory the files are located in. + */ + static Builder createFile(String resourceRoot) { + return StaticResourceHandlerBuilder.builder(resourceRoot).file(); + } + + /** + * Builder for StaticContent. + */ + sealed interface Builder + permits StaticResourceHandlerBuilder { + + /** + * Sets the HTTP path for the static resource handler. + * + * @param path the HTTP path prefix + * @return the updated configuration + */ + Builder httpPath(String path); + + /** + * Sets the index file to be served when a directory is requests. + * + * @param directoryIndex the index file + * @return the updated configuration + */ + Builder directoryIndex(String directoryIndex); + + /** + * Sent resources will be pre-compressed and cached in memory when this is enabled + * + * @return the updated configuration + */ + Builder preCompress(); + + /** + * Sets a custom resource loader for loading class/module path resources. This is normally used + * when running the application on the module path when files cannot be discovered. + * + *
Example usage: {@code service.resourceLoader(ClassResourceLoader.create(getClass())) }
+ *
+ * @param resourceLoader the custom resource loader
+ * @return the updated configuration
+ */
+ Builder resourceLoader(ClassResourceLoader resourceLoader);
+
+ /**
+ * Adds a new MIME type mapping to the configuration. (Default: uses {@link
+ * URLConnection#getFileNameMap()}
+ *
+ * @param ext the file extension (e.g., "html", "css", "js")
+ * @param mimeType the corresponding MIME type (e.g., "text/html", "text/css",
+ * "application/javascript")
+ * @return the updated configuration
+ */
+ Builder putMimeTypeMapping(String ext, String mimeType);
+
+ /**
+ * Adds a new response header to the configuration.
+ *
+ * @param key the header name
+ * @param value the header value
+ * @return the updated configuration
+ */
+ Builder putResponseHeader(String key, String value);
+
+ /**
+ * Sets a predicate to filter files based on the request context.
+ *
+ * @param skipFilePredicate the predicate to use
+ * @return the updated configuration
+ */
+ Builder skipFilePredicate(Predicate Example usage: {@code service.resourceLoader(ClassResourceLoader.create(getClass())) }
- *
- * @param resourceLoader the custom resource loader
- * @return the updated configuration
- */
- StaticContentService resourceLoader(ClassResourceLoader resourceLoader);
-
- /**
- * Adds a new MIME type mapping to the configuration. (Default: uses {@link
- * URLConnection#getFileNameMap()}
- *
- * @param ext the file extension (e.g., "html", "css", "js")
- * @param mimeType the corresponding MIME type (e.g., "text/html", "text/css",
- * "application/javascript")
- * @return the updated configuration
- */
- StaticContentService putMimeTypeMapping(String ext, String mimeType);
-
- /**
- * Adds a new response header to the configuration.
- *
- * @param key the header name
- * @param value the header value
- * @return the updated configuration
- */
- StaticContentService putResponseHeader(String key, String value);
-
- /**
- * Sets a predicate to filter files based on the request context.
- *
- * @param skipFilePredicate the predicate to use
- * @return the updated configuration
- */
- StaticContentService skipFilePredicate(Predicate{@code
* var staticContent = StaticContentService.createCP("/public").httpPath("/").directoryIndex("index.html");
diff --git a/avaje-jex-static-content/src/main/java/module-info.java b/avaje-jex-static-content/src/main/java/module-info.java
index c2ff0de..e50bd8e 100644
--- a/avaje-jex-static-content/src/main/java/module-info.java
+++ b/avaje-jex-static-content/src/main/java/module-info.java
@@ -1,5 +1,5 @@
/**
- * Defines the Static Content API for serving static resources with Jex - see {@link io.avaje.jex.staticcontent.StaticContentService}.
+ * Defines the Static Content API for serving static resources with Jex - see {@link StaticContent}.
*
*
{@code
* var staticContent = StaticContentService.createCP("/public").httpPath("/").directoryIndex("index.html");
diff --git a/avaje-jex-static-content/src/test/java/io/avaje/jex/staticcontent/CompressedStaticFileTest.java b/avaje-jex-static-content/src/test/java/io/avaje/jex/staticcontent/CompressedStaticFileTest.java
index 15a4b26..86ab80b 100644
--- a/avaje-jex-static-content/src/test/java/io/avaje/jex/staticcontent/CompressedStaticFileTest.java
+++ b/avaje-jex-static-content/src/test/java/io/avaje/jex/staticcontent/CompressedStaticFileTest.java
@@ -19,28 +19,30 @@ static TestPair init() {
final Jex app =
Jex.create()
- .plugin(defaultCP().httpPath("/index"))
- .plugin(defaultFile().httpPath("/indexFile"))
- .plugin(defaultCP().httpPath("/indexWild/*"))
- .plugin(defaultFile().httpPath("/indexWildFile/*"))
- .plugin(defaultCP().httpPath("/sus/"))
- .plugin(defaultFile().httpPath("/susFile/*"))
- .plugin(StaticContentService.createCP("/logback.xml").httpPath("/single"))
+ .plugin(defaultCP().httpPath("/index").build())
+ .plugin(defaultFile().httpPath("/indexFile").build())
+ .plugin(defaultCP().httpPath("/indexWild/*").build())
+ .plugin(defaultFile().httpPath("/indexWildFile/*").build())
+ .plugin(defaultCP().httpPath("/sus/").build())
+ .plugin(defaultFile().httpPath("/susFile/*").build())
+ .plugin(StaticContent.createCP("/logback.xml").httpPath("/single").build())
.plugin(
- StaticContentService.createFile("src/test/resources/logback.xml")
- .httpPath("/singleFile"));
+ StaticContent.createFile("src/test/resources/logback.xml")
+ .httpPath("/singleFile").build());
return TestPair.create(app);
}
- private static StaticContentService defaultFile() {
- return StaticContentService.createFile("src/test/resources/public")
+ private static StaticContent.Builder defaultFile() {
+ return StaticContent.createFile("src/test/resources/public")
.directoryIndex("index.html")
.preCompress();
}
- private static StaticContentService defaultCP() {
- return StaticContentService.createCP("/public").directoryIndex("index.html").preCompress();
+ private static StaticContent.Builder defaultCP() {
+ return StaticContent.createCP("/public")
+ .directoryIndex("index.html")
+ .preCompress();
}
@AfterAll
diff --git a/avaje-jex-static-content/src/test/java/io/avaje/jex/staticcontent/StaticFileTest.java b/avaje-jex-static-content/src/test/java/io/avaje/jex/staticcontent/StaticFileTest.java
index 2f1cc8b..f7290eb 100644
--- a/avaje-jex-static-content/src/test/java/io/avaje/jex/staticcontent/StaticFileTest.java
+++ b/avaje-jex-static-content/src/test/java/io/avaje/jex/staticcontent/StaticFileTest.java
@@ -19,27 +19,27 @@ static TestPair init() {
final Jex app =
Jex.create()
- .plugin(defaultCP().httpPath("/index"))
- .plugin(defaultFile().httpPath("/indexFile"))
- .plugin(defaultCP().httpPath("/indexWild/*"))
- .plugin(defaultFile().httpPath("/indexWildFile/*"))
- .plugin(defaultCP().httpPath("/sus/"))
- .plugin(defaultFile().httpPath("/susFile/*"))
- .plugin(StaticContentService.createCP("/logback.xml").httpPath("/single"))
+ .plugin(defaultCP().httpPath("/index").build())
+ .plugin(defaultFile().httpPath("/indexFile").build())
+ .plugin(defaultCP().httpPath("/indexWild/*").build())
+ .plugin(defaultFile().httpPath("/indexWildFile/*").build())
+ .plugin(defaultCP().httpPath("/sus/").build())
+ .plugin(defaultFile().httpPath("/susFile/*").build())
+ .plugin(StaticContent.createCP("/logback.xml").httpPath("/single").build())
.plugin(
- StaticContentService.createFile("src/test/resources/logback.xml")
- .httpPath("/singleFile"));
+ StaticContent.createFile("src/test/resources/logback.xml")
+ .httpPath("/singleFile").build());
return TestPair.create(app);
}
- private static StaticContentService defaultFile() {
- return StaticContentService.createFile("src/test/resources/public")
+ private static StaticContent.Builder defaultFile() {
+ return StaticContent.createFile("src/test/resources/public")
.directoryIndex("index.html");
}
- private static StaticContentService defaultCP() {
- return StaticContentService.createCP("/public").directoryIndex("index.html");
+ private static StaticContent.Builder defaultCP() {
+ return StaticContent.createCP("/public").directoryIndex("index.html");
}
@AfterAll
diff --git a/avaje-jex/src/main/java/io/avaje/jex/Jex.java b/avaje-jex/src/main/java/io/avaje/jex/Jex.java
index af0afb6..d768e0d 100644
--- a/avaje-jex/src/main/java/io/avaje/jex/Jex.java
+++ b/avaje-jex/src/main/java/io/avaje/jex/Jex.java
@@ -30,6 +30,7 @@ public sealed interface Jex permits DJex {
* Create Jex.
*
*
{@code
+ *
* final Jex.Server app = Jex.create()
* .routing(routing -> routing
* .get("/", ctx -> ctx.text("hello world"))