add journal application module
This commit is contained in:
parent
e3adbd4369
commit
582e7dd895
13 changed files with 354 additions and 24 deletions
|
@ -1,5 +1,5 @@
|
||||||
group = org.xbib
|
group = org.xbib
|
||||||
name = net-http
|
name = net-http
|
||||||
version = 3.6.2
|
version = 3.7.0
|
||||||
|
|
||||||
org.gradle.warning.mode = ALL
|
org.gradle.warning.mode = ALL
|
||||||
|
|
3
net-http-server-application-journal/build.gradle
Normal file
3
net-http-server-application-journal/build.gradle
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
dependencies {
|
||||||
|
api project(':net-http-server')
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
module org.xbib.net.http.server.application.journal {
|
||||||
|
requires org.xbib.net;
|
||||||
|
requires org.xbib.net.http;
|
||||||
|
requires org.xbib.net.http.server;
|
||||||
|
requires org.xbib.settings.api;
|
||||||
|
requires java.logging;
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
package org.xbib.net.http.server.application.journal;
|
||||||
|
|
||||||
|
import org.xbib.net.util.ExceptionFormatter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.FileVisitOption;
|
||||||
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.PathMatcher;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.SimpleFileVisitor;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class Journal {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(Journal.class.getName());
|
||||||
|
|
||||||
|
private final Path journalPath;
|
||||||
|
|
||||||
|
private final ReentrantReadWriteLock lock;
|
||||||
|
|
||||||
|
public Journal(String journalPathName) throws IOException {
|
||||||
|
this.journalPath = createJournal(journalPathName);
|
||||||
|
this.lock = new ReentrantReadWriteLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Path createJournal(String logPathName) throws IOException {
|
||||||
|
Path logPath = Paths.get(logPathName);
|
||||||
|
Files.createDirectories(logPath);
|
||||||
|
if (!Files.exists(logPath) || !Files.isWritable(logPath)) {
|
||||||
|
throw new IOException("unable to write to log path = " + logPath);
|
||||||
|
}
|
||||||
|
return logPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logRequest(String stamp, String request) throws IOException {
|
||||||
|
logger.log(Level.FINE, stamp + " request = " + request);
|
||||||
|
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
|
||||||
|
writeLock.lock();
|
||||||
|
try (OutputStream outputStream = Files.newOutputStream(journalPath.resolve(stamp + ".log"), StandardOpenOption.CREATE)) {
|
||||||
|
outputStream.write(request.getBytes(StandardCharsets.UTF_8));
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logSuccess(String stamp, String response) throws IOException {
|
||||||
|
logger.log(Level.FINE, stamp + " response = " + response);
|
||||||
|
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
|
||||||
|
writeLock.lock();
|
||||||
|
Path path = journalPath.resolve("success").resolve(stamp + ".request");
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
Files.move(journalPath.resolve(stamp), path);
|
||||||
|
try (OutputStream outputStream = Files.newOutputStream(journalPath.resolve("success").resolve(stamp + ".response"), StandardOpenOption.CREATE)) {
|
||||||
|
outputStream.write(response.getBytes(StandardCharsets.UTF_8));
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logFail(String stamp, Throwable t) throws IOException {
|
||||||
|
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
|
||||||
|
writeLock.lock();
|
||||||
|
Path path = journalPath.resolve("fail").resolve(stamp + ".request");
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
Files.move(journalPath.resolve(stamp), path);
|
||||||
|
// save throwable in extra file
|
||||||
|
try (OutputStream outputStream = Files.newOutputStream(journalPath.resolve("fail").resolve(stamp + ".exception"), StandardOpenOption.CREATE)) {
|
||||||
|
outputStream.write(ExceptionFormatter.format(t).getBytes(StandardCharsets.UTF_8));
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void retry(Consumer<StampedEntry> consumer) throws IOException {
|
||||||
|
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
|
||||||
|
writeLock.lock();
|
||||||
|
PathMatcher pathMatcher = journalPath.getFileSystem().getPathMatcher("glob:*.log");
|
||||||
|
try {
|
||||||
|
Files.walkFileTree(journalPath, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor<>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path p, BasicFileAttributes a) throws IOException {
|
||||||
|
if ((Files.isRegularFile(p) && pathMatcher.matches(p.getFileName()))) {
|
||||||
|
String stamp = p.getFileName().toString();
|
||||||
|
String entry = Files.readString(p);
|
||||||
|
consumer.accept(new StampedEntry(stamp, entry));
|
||||||
|
Files.delete(p);
|
||||||
|
}
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void purgeSuccess(Instant instant) throws IOException {
|
||||||
|
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
|
||||||
|
writeLock.lock();
|
||||||
|
PathMatcher pathMatcher = journalPath.getFileSystem().getPathMatcher("glob:*.request");
|
||||||
|
try {
|
||||||
|
Files.walkFileTree(journalPath.resolve("success"), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor<>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path p, BasicFileAttributes a) throws IOException {
|
||||||
|
if ((Files.isRegularFile(p) && pathMatcher.matches(p.getFileName()))) {
|
||||||
|
if (Files.getLastModifiedTime(p).toInstant().isBefore(instant)) {
|
||||||
|
Files.delete(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void purgeFail(Instant instant) throws IOException {
|
||||||
|
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
|
||||||
|
writeLock.lock();
|
||||||
|
PathMatcher pathMatcher = journalPath.getFileSystem().getPathMatcher("glob:*.request");
|
||||||
|
try {
|
||||||
|
Files.walkFileTree(journalPath.resolve("fail"), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor<>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path p, BasicFileAttributes a) throws IOException {
|
||||||
|
if ((Files.isRegularFile(p) && pathMatcher.matches(p.getFileName()))) {
|
||||||
|
if (Files.getLastModifiedTime(p).toInstant().isBefore(instant)) {
|
||||||
|
Files.delete(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StampedEntry {
|
||||||
|
|
||||||
|
private final String stamp;
|
||||||
|
|
||||||
|
private final String entry;
|
||||||
|
|
||||||
|
public StampedEntry(String stamp, String entry) {
|
||||||
|
this.stamp = stamp;
|
||||||
|
this.entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStamp() {
|
||||||
|
return stamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEntry() {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package org.xbib.net.http.server.application.journal;
|
||||||
|
|
||||||
|
import org.xbib.net.http.server.HttpRequest;
|
||||||
|
import org.xbib.net.http.server.HttpResponseBuilder;
|
||||||
|
import org.xbib.net.http.server.application.Application;
|
||||||
|
import org.xbib.net.http.server.application.BaseApplicationModule;
|
||||||
|
import org.xbib.net.http.server.route.HttpRouterContext;
|
||||||
|
import org.xbib.net.http.server.service.HttpService;
|
||||||
|
import org.xbib.settings.Settings;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class JournalApplicationModule extends BaseApplicationModule {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(JournalApplicationModule.class.getName());
|
||||||
|
|
||||||
|
private final Journal journal;
|
||||||
|
|
||||||
|
public JournalApplicationModule(Application application, String name, Settings settings) throws IOException {
|
||||||
|
super(application, name, settings);
|
||||||
|
this.journal = new Journal(settings.get("application.journal", "/var/tmp/application/journal"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest) {
|
||||||
|
String stamp = createStamp(httpRequest);
|
||||||
|
httpRouterContext.getAttributes().put("_stamp", stamp);
|
||||||
|
try {
|
||||||
|
journal.logRequest(stamp, httpRequest.asJson());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest) {
|
||||||
|
String stamp = httpRouterContext.getAttributes().get(String.class, "_stamp");
|
||||||
|
HttpResponseBuilder httpResponseBuilder = httpRouterContext.getAttributes().get(HttpResponseBuilder.class, "response");
|
||||||
|
if (stamp != null && httpResponseBuilder != null) {
|
||||||
|
try {
|
||||||
|
journal.logSuccess(stamp, httpResponseBuilder.getResponseStatus().codeAsText());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFail(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest, Throwable throwable) {
|
||||||
|
String stamp = httpRouterContext.getAttributes().get(String.class, "_stamp");
|
||||||
|
if (stamp != null) {
|
||||||
|
try {
|
||||||
|
journal.logFail(stamp, throwable);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createStamp(HttpRequest httpRequest) {
|
||||||
|
return httpRequest.getLocalAddress().getAddress().getHostAddress() + "_" +
|
||||||
|
httpRequest.getLocalAddress().getPort() + "_" +
|
||||||
|
httpRequest.getRemoteAddress().getAddress().getHostAddress() + "_" +
|
||||||
|
httpRequest.getRemoteAddress().getPort() + "_" +
|
||||||
|
LocalDateTime.now();
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,13 +11,23 @@ public interface ApplicationModule {
|
||||||
|
|
||||||
void onOpen(HttpRouterContext httpRouterContext);
|
void onOpen(HttpRouterContext httpRouterContext);
|
||||||
|
|
||||||
|
void onSuccess(HttpRouterContext httpRouterContext);
|
||||||
|
|
||||||
|
void onFail(HttpRouterContext httpRouterContext, Throwable throwable);
|
||||||
|
|
||||||
void onOpen(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest);
|
void onOpen(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest);
|
||||||
|
|
||||||
void onClose(HttpRouterContext httpRouterContext);
|
void onSuccess(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest);
|
||||||
|
|
||||||
|
void onFail(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest, Throwable throwable);
|
||||||
|
|
||||||
void onOpen(Session session);
|
void onOpen(Session session);
|
||||||
|
|
||||||
void onClose(Session session);
|
void onSuccess(Session session);
|
||||||
|
|
||||||
void onClose();
|
void onFail(Session session, Throwable throwable);
|
||||||
|
|
||||||
|
void onSuccess();
|
||||||
|
|
||||||
|
void onFail(Throwable throwable);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,8 @@ public class BaseApplication implements Application {
|
||||||
|
|
||||||
protected List<ApplicationModule> applicationModuleList;
|
protected List<ApplicationModule> applicationModuleList;
|
||||||
|
|
||||||
|
private Throwable throwable;
|
||||||
|
|
||||||
protected BaseApplication(BaseApplicationBuilder builder) {
|
protected BaseApplication(BaseApplicationBuilder builder) {
|
||||||
this.builder = builder;
|
this.builder = builder;
|
||||||
this.sessionName = builder.settings.get("session.name", "SESS");
|
this.sessionName = builder.settings.get("session.name", "SESS");
|
||||||
|
@ -240,26 +242,38 @@ public class BaseApplication implements Application {
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy(Session session) {
|
public void onDestroy(Session session) {
|
||||||
logger.log(Level.FINER, "session name = " + sessionName + " destroyed = " + session);
|
logger.log(Level.FINER, "session name = " + sessionName + " destroyed = " + session);
|
||||||
applicationModuleList.forEach(module -> module.onClose(session));
|
if (throwable != null) {
|
||||||
|
applicationModuleList.forEach(module -> module.onFail(session, throwable));
|
||||||
|
} else {
|
||||||
|
applicationModuleList.forEach(module -> module.onSuccess(session));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(HttpRouterContext httpRouterContext) {
|
public void onOpen(HttpRouterContext httpRouterContext) {
|
||||||
|
this.throwable = null;
|
||||||
try {
|
try {
|
||||||
// call modules after request/cookie/session setup
|
// call modules after request/cookie/session setup
|
||||||
applicationModuleList.forEach(module -> module.onOpen(httpRouterContext));
|
applicationModuleList.forEach(module -> module.onOpen(httpRouterContext));
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
this.throwable = t;
|
||||||
|
applicationModuleList.forEach(module -> module.onFail(httpRouterContext, t));
|
||||||
builder.httpRouter.routeToErrorHandler(httpRouterContext, t);
|
builder.httpRouter.routeToErrorHandler(httpRouterContext, t);
|
||||||
httpRouterContext.fail();
|
httpRouterContext.fail(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose(HttpRouterContext httpRouterContext) {
|
public void onClose(HttpRouterContext httpRouterContext) {
|
||||||
try {
|
try {
|
||||||
// call modules before session/cookie
|
if (throwable != null) {
|
||||||
applicationModuleList.forEach(module -> module.onClose(httpRouterContext));
|
applicationModuleList.forEach(module -> module.onFail(httpRouterContext, throwable));
|
||||||
|
} else {
|
||||||
|
applicationModuleList.forEach(module -> module.onSuccess(httpRouterContext));
|
||||||
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
this.throwable = t;
|
||||||
|
applicationModuleList.forEach(module -> module.onFail(httpRouterContext, t));
|
||||||
builder.httpRouter.routeToErrorHandler(httpRouterContext, t);
|
builder.httpRouter.routeToErrorHandler(httpRouterContext, t);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
|
@ -307,7 +321,11 @@ public class BaseApplication implements Application {
|
||||||
// stop dispatching and stop dispatched requests
|
// stop dispatching and stop dispatched requests
|
||||||
applicationModuleList.forEach(module -> {
|
applicationModuleList.forEach(module -> {
|
||||||
logger.log(Level.FINE, "application closing module " + module);
|
logger.log(Level.FINE, "application closing module " + module);
|
||||||
module.onClose();
|
if (throwable != null) {
|
||||||
|
module.onFail(throwable);
|
||||||
|
} else {
|
||||||
|
module.onSuccess();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
logger.log(Level.INFO, "application closed");
|
logger.log(Level.INFO, "application closed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,24 @@ public abstract class BaseApplicationModule implements ApplicationModule {
|
||||||
public void onOpen(HttpRouterContext httpRouterContext) {
|
public void onOpen(HttpRouterContext httpRouterContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(HttpRouterContext httpRouterContext) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFail(HttpRouterContext httpRouterContext, Throwable throwable) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest) {
|
public void onOpen(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose(HttpRouterContext httpRouterContext) {
|
public void onSuccess(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFail(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest, Throwable throwable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,10 +54,18 @@ public abstract class BaseApplicationModule implements ApplicationModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose(Session session) {
|
public void onSuccess(Session session) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose() {
|
public void onFail(Session session, Throwable throwable) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFail(Throwable throwable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.xbib.net.http.server.HttpRequest;
|
||||||
import org.xbib.net.http.server.HttpRequestBuilder;
|
import org.xbib.net.http.server.HttpRequestBuilder;
|
||||||
import org.xbib.net.http.server.HttpResponseBuilder;
|
import org.xbib.net.http.server.HttpResponseBuilder;
|
||||||
import org.xbib.net.http.server.application.Application;
|
import org.xbib.net.http.server.application.Application;
|
||||||
|
import org.xbib.net.http.server.application.ApplicationModule;
|
||||||
import org.xbib.net.http.server.domain.HttpDomain;
|
import org.xbib.net.http.server.domain.HttpDomain;
|
||||||
import org.xbib.net.http.server.handler.InternalServerErrorHandler;
|
import org.xbib.net.http.server.handler.InternalServerErrorHandler;
|
||||||
import org.xbib.net.http.server.service.HttpService;
|
import org.xbib.net.http.server.service.HttpService;
|
||||||
|
@ -140,15 +141,19 @@ public class BaseHttpRouter implements HttpRouter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (HttpRouteResolver.Result<HttpService> httpRouteResolverResult : httpRouteResolverResults) {
|
for (HttpRouteResolver.Result<HttpService> httpRouteResolverResult : httpRouteResolverResults) {
|
||||||
|
HttpService httpService = null;
|
||||||
|
HttpRequest httpRequest = null;
|
||||||
try {
|
try {
|
||||||
// first: create the final request
|
// first: create the final request
|
||||||
setResolverResult(httpRouterContext, httpRouteResolverResult);
|
setResolverResult(httpRouterContext, httpRouteResolverResult);
|
||||||
HttpService httpService = httpRouteResolverResult.getValue();
|
httpService = httpRouteResolverResult.getValue();
|
||||||
HttpRequest httpRequest = httpRouterContext.getRequest();
|
httpRequest = httpRouterContext.getRequest();
|
||||||
application.getModules().forEach(module -> module.onOpen(httpRouterContext, httpService, httpRequest));
|
for (ApplicationModule module : application.getModules()) {
|
||||||
|
module.onOpen(httpRouterContext, httpService, httpRequest);
|
||||||
|
}
|
||||||
// second: security check, authentication etc.
|
// second: security check, authentication etc.
|
||||||
if (httpService.getSecurityDomain() != null) {
|
if (httpService.getSecurityDomain() != null) {
|
||||||
logger.log(Level.FINEST, () -> "handling security domain service " + httpService);
|
logger.log(Level.FINEST, "handling security domain service " + httpService);
|
||||||
for (HttpHandler httpHandler : httpService.getSecurityDomain().getHandlers()) {
|
for (HttpHandler httpHandler : httpService.getSecurityDomain().getHandlers()) {
|
||||||
logger.log(Level.FINEST, () -> "handling security domain handler " + httpHandler);
|
logger.log(Level.FINEST, () -> "handling security domain handler " + httpHandler);
|
||||||
httpHandler.handle(httpRouterContext);
|
httpHandler.handle(httpRouterContext);
|
||||||
|
@ -159,14 +164,26 @@ public class BaseHttpRouter implements HttpRouter {
|
||||||
}
|
}
|
||||||
// after security checks, accept service, open and execute service
|
// after security checks, accept service, open and execute service
|
||||||
httpRouterContext.getAttributes().put("service", httpService);
|
httpRouterContext.getAttributes().put("service", httpService);
|
||||||
logger.log(Level.FINEST, () -> "handling service " + httpService);
|
logger.log(Level.FINEST, "handling service " + httpService);
|
||||||
httpService.handle(httpRouterContext);
|
httpService.handle(httpRouterContext);
|
||||||
// if service signals that work is done, break
|
// if service signals that work is done, break
|
||||||
if (httpRouterContext.isDone() || httpRouterContext.isFailed()) {
|
if (httpRouterContext.isDone() || httpRouterContext.isFailed()) {
|
||||||
|
for (ApplicationModule module : application.getModules()) {
|
||||||
|
module.onSuccess(httpRouterContext, httpService, httpRequest);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (httpRouterContext.isFailed()) {
|
||||||
|
for (ApplicationModule module : application.getModules()) {
|
||||||
|
module.onFail(httpRouterContext, httpService, httpRequest, httpRouterContext.getFail());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (HttpException e) {
|
} catch (HttpException e) {
|
||||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
for (ApplicationModule module : application.getModules()) {
|
||||||
|
module.onFail(httpRouterContext, httpService, httpRequest, httpRouterContext.getFail());
|
||||||
|
}
|
||||||
routeException(e);
|
routeException(e);
|
||||||
break;
|
break;
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
@ -330,7 +347,7 @@ public class BaseHttpRouter implements HttpRouter {
|
||||||
@Override
|
@Override
|
||||||
public void routeToErrorHandler(HttpRouterContext httpRouterContext, Throwable t) {
|
public void routeToErrorHandler(HttpRouterContext httpRouterContext, Throwable t) {
|
||||||
httpRouterContext.getAttributes().put("_throwable", t);
|
httpRouterContext.getAttributes().put("_throwable", t);
|
||||||
httpRouterContext.fail();
|
httpRouterContext.fail(t);
|
||||||
routeStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR, httpRouterContext);
|
routeStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR, httpRouterContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class BaseHttpRouterContext implements HttpRouterContext {
|
||||||
|
|
||||||
private boolean done;
|
private boolean done;
|
||||||
|
|
||||||
private boolean failed;
|
private Throwable throwable;
|
||||||
|
|
||||||
private boolean next;
|
private boolean next;
|
||||||
|
|
||||||
|
@ -201,12 +201,17 @@ public class BaseHttpRouterContext implements HttpRouterContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFailed() {
|
public boolean isFailed() {
|
||||||
return failed;
|
return throwable != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail() {
|
public void fail(Throwable throwable) {
|
||||||
this.failed = true;
|
this.throwable = throwable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Throwable getFail() {
|
||||||
|
return throwable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void next() {
|
public void next() {
|
||||||
|
|
|
@ -49,7 +49,9 @@ public interface HttpRouterContext {
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void fail();
|
void fail(Throwable throwable);
|
||||||
|
|
||||||
|
Throwable getFail();
|
||||||
|
|
||||||
boolean isFailed();
|
boolean isFailed();
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,16 @@ public class GroovyTemplateApplicationModule extends BaseApplicationModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose(HttpRouterContext httpRouterContext) {
|
public void onSuccess(HttpRouterContext httpRouterContext) {
|
||||||
|
try {
|
||||||
|
groovyTemplateRenderer.handle(httpRouterContext);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFail(HttpRouterContext httpRouterContext, Throwable throwable) {
|
||||||
try {
|
try {
|
||||||
groovyTemplateRenderer.handle(httpRouterContext);
|
groovyTemplateRenderer.handle(httpRouterContext);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -68,3 +68,4 @@ include 'net-http-j2html'
|
||||||
include 'net-http-server-application-web'
|
include 'net-http-server-application-web'
|
||||||
include 'net-http-server-application-config'
|
include 'net-http-server-application-config'
|
||||||
include 'net-http-server-application-database'
|
include 'net-http-server-application-database'
|
||||||
|
include 'net-http-server-application-journal'
|
||||||
|
|
Loading…
Reference in a new issue