diff --git a/net-http-htmlflow/build.gradle b/net-http-htmlflow/build.gradle
new file mode 100644
index 0000000..16a18a3
--- /dev/null
+++ b/net-http-htmlflow/build.gradle
@@ -0,0 +1,4 @@
+dependencies {
+ api project(':net-http-server')
+ api libs.htmlflow
+}
diff --git a/net-http-htmlflow/src/main/java/module-info.java b/net-http-htmlflow/src/main/java/module-info.java
new file mode 100644
index 0000000..b2b20dc
--- /dev/null
+++ b/net-http-htmlflow/src/main/java/module-info.java
@@ -0,0 +1,8 @@
+module org.xbib.net.http.htmlflow {
+ exports org.xbib.net.http.htmlflow;
+ requires org.xbib.net;
+ requires org.xbib.net.http;
+ requires org.xbib.net.http.server;
+ requires org.xbib.config;
+ requires java.logging;
+}
\ No newline at end of file
diff --git a/net-http-htmlflow/src/main/java/org/xbib/net/http/htmlflow/HtmlFlowResourceHandler.java b/net-http-htmlflow/src/main/java/org/xbib/net/http/htmlflow/HtmlFlowResourceHandler.java
new file mode 100644
index 0000000..992c090
--- /dev/null
+++ b/net-http-htmlflow/src/main/java/org/xbib/net/http/htmlflow/HtmlFlowResourceHandler.java
@@ -0,0 +1,60 @@
+package org.xbib.net.http.htmlflow;
+
+import org.xbib.net.Attributes;
+import org.xbib.net.Resource;
+import org.xbib.net.buffer.DataBuffer;
+import org.xbib.net.http.HttpResponseStatus;
+import org.xbib.net.http.server.application.Application;
+import org.xbib.net.http.server.resource.HtmlTemplateResource;
+import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
+import org.xbib.net.http.server.route.HttpRouterContext;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
+
+public class HtmlFlowResourceHandler extends HtmlTemplateResourceHandler {
+
+ public HtmlFlowResourceHandler(Path root, String suffix, String indexFileName) {
+ super(root, suffix, indexFileName);
+ }
+
+ @Override
+ protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException {
+ return new HtmlFlowResource(this, httpRouterContext);
+ }
+
+ protected static class HtmlFlowResource extends HtmlTemplateResource {
+
+ private static final Logger logger = Logger.getLogger(HtmlFlowResource.class.getName());
+
+ protected HtmlFlowResource(HtmlTemplateResourceHandler templateResourceHandler, HttpRouterContext httpRouterContext) throws IOException {
+ super(templateResourceHandler, httpRouterContext);
+ }
+
+ @Override
+ public void render(HttpRouterContext context) throws IOException {
+ Application application = context.getAttributes().get(Application.class, "application");
+ if (application == null) {
+ logger.log(Level.WARNING, "application is null");
+ return;
+ }
+ DataBuffer dataBuffer = context.getDataBufferFactory().allocateBuffer();
+ dataBuffer.write(render(application, context.getAttributes()), StandardCharsets.UTF_8);
+ HttpResponseStatus httpResponseStatus = context.getAttributes().get(HttpResponseStatus.class, "_status", HttpResponseStatus.OK);
+ context.status(httpResponseStatus)
+ .header("cache-control", "no-cache") // override default must-revalidate behavior
+ .header("content-length", Integer.toString(dataBuffer.writePosition()))
+ .header(CONTENT_TYPE, "text/html; charset=" + StandardCharsets.UTF_8.displayName())
+ .body(dataBuffer);
+ }
+
+ protected String render(Application application, Attributes attributes) {
+ return null;
+ }
+ }
+}
diff --git a/net-http-htmlflow/src/main/java/org/xbib/net/http/htmlflow/HtmlFlowService.java b/net-http-htmlflow/src/main/java/org/xbib/net/http/htmlflow/HtmlFlowService.java
new file mode 100644
index 0000000..36fd756
--- /dev/null
+++ b/net-http-htmlflow/src/main/java/org/xbib/net/http/htmlflow/HtmlFlowService.java
@@ -0,0 +1,15 @@
+package org.xbib.net.http.htmlflow;
+
+import org.xbib.net.http.server.service.BaseHttpService;
+import org.xbib.net.http.server.service.BaseHttpServiceBuilder;
+
+public class HtmlFlowService extends BaseHttpService {
+
+ protected HtmlFlowService(BaseHttpServiceBuilder builder) {
+ super(builder);
+ }
+
+ public static HtmlFlowServiceBuilder builder() {
+ return new HtmlFlowServiceBuilder();
+ }
+}
diff --git a/net-http-htmlflow/src/main/java/org/xbib/net/http/htmlflow/HtmlFlowServiceBuilder.java b/net-http-htmlflow/src/main/java/org/xbib/net/http/htmlflow/HtmlFlowServiceBuilder.java
new file mode 100644
index 0000000..3815cbc
--- /dev/null
+++ b/net-http-htmlflow/src/main/java/org/xbib/net/http/htmlflow/HtmlFlowServiceBuilder.java
@@ -0,0 +1,69 @@
+package org.xbib.net.http.htmlflow;
+
+import org.xbib.net.ParameterDefinition;
+import org.xbib.net.http.HttpMethod;
+import org.xbib.net.http.server.HttpHandler;
+import org.xbib.net.http.server.domain.HttpSecurityDomain;
+import org.xbib.net.http.server.service.BaseHttpServiceBuilder;
+
+import java.nio.file.Path;
+
+public class HtmlFlowServiceBuilder extends BaseHttpServiceBuilder {
+
+ protected Path prefix;
+
+ protected String suffix;
+
+ public HtmlFlowServiceBuilder() {
+ super();
+ this.prefix = null;
+ }
+
+ @Override
+ public HtmlFlowServiceBuilder setPath(String path) {
+ super.setPath(path);
+ return this;
+ }
+
+ @Override
+ public HtmlFlowServiceBuilder setMethod(HttpMethod... httpMethod) {
+ super.setMethod(httpMethod);
+ return this;
+ }
+
+ @Override
+ public HtmlFlowServiceBuilder setHandler(HttpHandler... handler) {
+ super.setHandler(handler);
+ return this;
+ }
+
+ @Override
+ public HtmlFlowServiceBuilder setParameterDefinition(ParameterDefinition... parameterDefinition) {
+ super.setParameterDefinition(parameterDefinition);
+ return this;
+ }
+
+ @Override
+ public HtmlFlowServiceBuilder setSecurityDomain(HttpSecurityDomain securityDomain) {
+ super.setSecurityDomain(securityDomain);
+ return this;
+ }
+
+ public HtmlFlowServiceBuilder setPrefix(Path prefix) {
+ this.prefix = prefix;
+ return this;
+ }
+
+ public HtmlFlowServiceBuilder setSuffix(String suffix) {
+ this.suffix = suffix;
+ return this;
+ }
+
+ public HtmlFlowService build() {
+ if (this.handlers == null) {
+ HttpHandler httpHandler = new HtmlFlowResourceHandler(prefix, suffix, "index.java");
+ setHandler(httpHandler);
+ }
+ return new HtmlFlowService(this);
+ }
+}
diff --git a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResourceHandler.java b/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResourceHandler.java
index 74d51dc..624c8bb 100644
--- a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResourceHandler.java
+++ b/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResourceHandler.java
@@ -1,10 +1,9 @@
package org.xbib.net.http.j2html;
-import org.xbib.net.Attributes;
import org.xbib.net.Resource;
import org.xbib.net.buffer.DataBuffer;
import org.xbib.net.http.HttpResponseStatus;
-import org.xbib.net.http.server.application.Application;
+import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.resource.HtmlTemplateResource;
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
import org.xbib.net.http.server.route.HttpRouterContext;
@@ -12,8 +11,7 @@ import org.xbib.net.http.server.route.HttpRouterContext;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import java.util.Objects;
import static j2html.TagCreator.body;
import static j2html.TagCreator.h1;
@@ -36,22 +34,24 @@ public class J2HtmlResourceHandler extends HtmlTemplateResourceHandler {
protected static class J2HtmlResource extends HtmlTemplateResource {
- private static final Logger logger = Logger.getLogger(J2HtmlResource.class.getName());
+ protected HttpRequest request;
- protected J2HtmlResource(HtmlTemplateResourceHandler templateResourceHandler, HttpRouterContext httpRouterContext) throws IOException {
+ protected J2HtmlResource(HtmlTemplateResourceHandler templateResourceHandler,
+ HttpRouterContext httpRouterContext) throws IOException {
super(templateResourceHandler, httpRouterContext);
}
@Override
public void render(HttpRouterContext context) throws IOException {
- Application application = context.getAttributes().get(Application.class, "application");
- if (application == null) {
- logger.log(Level.WARNING, "application is null");
- return;
- }
+ this.request = context.getRequest();
+ Objects.requireNonNull(responseBuilder);
DataBuffer dataBuffer = context.getDataBufferFactory().allocateBuffer();
- dataBuffer.write(render(application, context.getAttributes()), StandardCharsets.UTF_8);
- HttpResponseStatus httpResponseStatus = context.getAttributes().get(HttpResponseStatus.class, "_status", HttpResponseStatus.OK);
+ dataBuffer.write(renderBody(context), StandardCharsets.UTF_8);
+ HttpResponseStatus httpResponseStatus = responseBuilder.getResponseStatus();
+ if (httpResponseStatus == null) {
+ httpResponseStatus = HttpResponseStatus.OK;
+ }
+ //context.getAttributes().get(HttpResponseStatus.class, "_status", HttpResponseStatus.OK);
context.status(httpResponseStatus)
.header("cache-control", "no-cache") // override default must-revalidate behavior
.header("content-length", Integer.toString(dataBuffer.writePosition()))
@@ -59,7 +59,7 @@ public class J2HtmlResourceHandler extends HtmlTemplateResourceHandler {
.body(dataBuffer);
}
- protected String render(Application application, Attributes attributes) {
+ protected String renderBody(HttpRouterContext context) {
return body(
h1("Hello World")
).render();
diff --git a/net-http-server-application-web/build.gradle b/net-http-server-application-web/build.gradle
index dbab609..8d7f283 100644
--- a/net-http-server-application-web/build.gradle
+++ b/net-http-server-application-web/build.gradle
@@ -5,6 +5,7 @@ dependencies {
api project(':net-http-server-application-config')
api project(':net-http-template-groovy')
api project(':net-http-j2html')
+ api project(':net-http-htmlflow')
api libs.jdbc.query
implementation libs.webjars.bootstrap
implementation libs.webjars.jquery
diff --git a/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/Bootstrap.java b/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/Bootstrap.java
index d9b3bdc..23bdc6f 100644
--- a/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/Bootstrap.java
+++ b/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/Bootstrap.java
@@ -197,7 +197,6 @@ public final class Bootstrap {
return 0;
}
-
private static final String hexFavIcon =
"000001000100101000000100200068040000160000002800000010000000" +
"200000000100200000000000000000000000000000000000000000000000" +
diff --git a/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/InternalServerErrorHandler.java b/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/InternalServerErrorHandler.java
index be810fc..f86ec20 100644
--- a/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/InternalServerErrorHandler.java
+++ b/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/InternalServerErrorHandler.java
@@ -3,7 +3,6 @@ package org.xbib.net.http.server.application.web.j2html;
import org.xbib.net.Attributes;
import org.xbib.net.Resource;
import org.xbib.net.http.j2html.J2HtmlResourceHandler;
-import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.util.ExceptionFormatter;
@@ -30,7 +29,8 @@ public class InternalServerErrorHandler extends J2HtmlResourceHandler {
}
@Override
- protected String render(Application application, Attributes attributes) {
+ protected String renderBody(HttpRouterContext httpRouterContext) {
+ Attributes attributes = httpRouterContext.getAttributes();
String message = attributes.get(String.class, "_message");
Throwable throwable = attributes.get(Throwable.class, "_throwable");
String stackTrace = ExceptionFormatter.format(throwable);
diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/application/BaseApplication.java b/net-http-server/src/main/java/org/xbib/net/http/server/application/BaseApplication.java
index a17e366..3d636ce 100644
--- a/net-http-server/src/main/java/org/xbib/net/http/server/application/BaseApplication.java
+++ b/net-http-server/src/main/java/org/xbib/net/http/server/application/BaseApplication.java
@@ -13,6 +13,7 @@ import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
+
import org.xbib.net.http.HttpAddress;
import org.xbib.net.http.cookie.SameSite;
import org.xbib.net.http.server.route.BaseHttpRouterContext;
diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResource.java b/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResource.java
index 066d9bd..0b4d152 100644
--- a/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResource.java
+++ b/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResource.java
@@ -4,9 +4,14 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
+import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xbib.net.URL;
+import org.xbib.net.http.HttpHeaderNames;
+import org.xbib.net.http.HttpResponseStatus;
+import org.xbib.net.http.server.HttpRequest;
+import org.xbib.net.http.server.HttpResponseBuilder;
import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.application.Application;
@@ -40,12 +45,18 @@ public class HtmlTemplateResource implements HttpServerResource {
protected final boolean negotiateLocale;
+ protected final HttpResponseBuilder responseBuilder;
+
+ protected final Application application;
+
protected HtmlTemplateResource(HtmlTemplateResourceHandler templateResourceHandler,
HttpRouterContext httpRouterContext) throws IOException {
this.templateResourceHandler = templateResourceHandler;
- String indexFileName = templateResourceHandler.getIndexFileName();
- Application application = httpRouterContext.getAttributes().get(Application.class, "application");
+ this.application = httpRouterContext.getAttributes().get(Application.class, "application");
+ Objects.requireNonNull(application);
this.negotiateLocale = application.getSettings().getAsBoolean("negotiateLocale", false);
+ this.responseBuilder = httpRouterContext.getAttributes().get(HttpResponseBuilder.class, "response");
+ Objects.requireNonNull(responseBuilder);
Path root = templateResourceHandler.getRoot();
root = root != null ? root : application.getHome();
if (root == null) {
@@ -57,13 +68,13 @@ public class HtmlTemplateResource implements HttpServerResource {
" root = " + root +
" resource path = " + resourcePath +
" path = " + path +
- " index file name = " + indexFileName);
+ " index file name = " + templateResourceHandler.getIndexFileName());
this.name = path.getFileName().toString();
this.baseName = AbstractResourceHandler.basename(name);
this.suffix = AbstractResourceHandler.suffix(name);
if (Files.isDirectory(path)) {
if (getIndexFileName() != null) {
- Path indexPath = path.resolve(indexFileName);
+ Path indexPath = path.resolve(templateResourceHandler.getIndexFileName());
logger.log(Level.FINEST, "resolved to index path = " + indexPath);
if (Files.exists(indexPath)) {
logger.log(Level.FINEST, "index path exists");
@@ -137,7 +148,7 @@ public class HtmlTemplateResource implements HttpServerResource {
@Override
public String getIndexFileName() {
- return templateResourceHandler.getIndexFileName();
+ return templateResourceHandler != null ? templateResourceHandler.getIndexFileName() : null;
}
@Override
@@ -163,11 +174,77 @@ public class HtmlTemplateResource implements HttpServerResource {
",lastmodified=" + lastModified +
",length=" + length +
",isExists=" + isExists +
- ",isDirectory=" + isDirectory() + "]";
+ ",isDirectory=" + isDirectory + "]";
}
@Override
public void render(HttpRouterContext httpRouterContext) throws IOException {
// to be overriden
}
+
+ public String contextPath(HttpRequest request, String rel) {
+ return url(request, rel, false);
+ }
+
+ public String url(HttpRequest request, String rel) {
+ return url(request, rel, true);
+ }
+
+ public String url(HttpRequest request, String rel, boolean absolute) {
+ String prefix = application.getSettings().get("web.prefix", "/");
+ if (!prefix.endsWith("/")) {
+ prefix = prefix + "/";
+ }
+ URL url = request.getServerURL().resolve(prefix).resolve(rel);
+ return absolute ? url.toExternalForm() : toOrigin(url);
+ }
+
+ public void setResponseStatus(HttpResponseStatus responseStatus) {
+ this.responseBuilder.setResponseStatus(responseStatus);
+ }
+
+ public void movedPermanently(String url) {
+ this.responseBuilder.setResponseStatus(HttpResponseStatus.MOVED_PERMANENTLY);
+ this.responseBuilder.setHeader(HttpHeaderNames.LOCATION, url);
+ }
+
+ public void found(String url) {
+ this.responseBuilder.setResponseStatus(HttpResponseStatus.FOUND);
+ this.responseBuilder.setHeader(HttpHeaderNames.LOCATION, url);
+ }
+
+ public void seeOther(String url) {
+ this.responseBuilder.setResponseStatus(HttpResponseStatus.SEE_OTHER);
+ this.responseBuilder.setHeader(HttpHeaderNames.LOCATION, url);
+ }
+
+ public void temporaryRedirect(String url) {
+ this.responseBuilder.setResponseStatus(HttpResponseStatus.TEMPORARY_REDIRECT);
+ this.responseBuilder.setHeader(HttpHeaderNames.LOCATION, url);
+ }
+
+ public void notFound() {
+ this.responseBuilder.setResponseStatus(HttpResponseStatus.NOT_FOUND);
+ }
+
+ public void gone() {
+ this.responseBuilder.setResponseStatus(HttpResponseStatus.GONE);
+ }
+
+ private static String toOrigin(URL url) {
+ StringBuilder sb = new StringBuilder();
+ if (url.getPath() != null) {
+ sb.append(url.getPath());
+ }
+ if (url.getQuery() != null) {
+ sb.append('?').append(url.getQuery());
+ }
+ if (url.getFragment() != null) {
+ sb.append('#').append(url.getFragment());
+ }
+ if (sb.length() == 0) {
+ sb.append('/');
+ }
+ return sb.toString();
+ }
}
diff --git a/settings.gradle b/settings.gradle
index cdbda91..83e8b32 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -25,10 +25,11 @@ dependencyResolutionManagement {
library('jackson', 'com.fasterxml.jackson.core', 'jackson-databind').version('2.14.2')
library('jna', 'net.java.dev.jna', 'jna').version('5.13.0')
library('groovy-templates', 'org.apache.groovy', 'groovy-templates').versionRef('groovy')
+ library('j2html', 'com.j2html', 'j2html').version('1.6.0')
+ library('htmlflow', 'com.github.xmlet', 'htmlflow').version('4.0')
library('webjars-bootstrap', 'org.webjars', 'bootstrap').version('5.2.3')
library('webjars-jquery', 'org.webjars', 'jquery').version('3.6.4')
library('webjars-fontawesome', 'org.webjars', 'font-awesome').version('6.3.0')
- library('j2html', 'com.j2html', 'j2html').version('1.6.0')
library('net', 'org.xbib', 'net').versionRef('net')
library('net-mime', 'org.xbib', 'net-mime').versionRef('net')
library('net-security', 'org.xbib', 'net-security').versionRef('net')
@@ -62,6 +63,7 @@ include 'net-http-server-nio'
include 'net-http-server-simple'
include 'net-http-server-simple-secure'
include 'net-http-template-groovy'
+include 'net-http-htmlflow'
include 'net-http-j2html'
include 'net-http-server-application-web'
include 'net-http-server-application-config'