add session name, fix netty request body retain, fix static suffixes, log throwables in the router dispatch

This commit is contained in:
Jörg Prante 2023-03-20 17:07:18 +01:00
parent 2f17616f1d
commit 1df5f884b1
13 changed files with 108 additions and 73 deletions

View file

@ -10,15 +10,11 @@ import org.xbib.net.http.server.session.IncomingSessionHandler;
import org.xbib.net.http.server.session.OutgoingSessionHandler; import org.xbib.net.http.server.session.OutgoingSessionHandler;
import org.xbib.net.http.server.session.Session; import org.xbib.net.http.server.session.Session;
import org.xbib.net.http.server.session.file.FileJsonSessionCodec; import org.xbib.net.http.server.session.file.FileJsonSessionCodec;
import org.xbib.settings.Settings;
public class WebApplication extends BaseApplication { public class WebApplication extends BaseApplication {
private final WebApplicationBuilder builder;
protected WebApplication(WebApplicationBuilder builder) { protected WebApplication(WebApplicationBuilder builder) {
super(builder); super(builder);
this.builder = builder;
} }
public static WebApplicationBuilder builder() { public static WebApplicationBuilder builder() {
@ -30,7 +26,7 @@ public class WebApplication extends BaseApplication {
} }
protected Codec<Session> buildSessionCodec(HttpServerContext httpServerContext) { protected Codec<Session> buildSessionCodec(HttpServerContext httpServerContext) {
return new FileJsonSessionCodec(this, 1024, Duration.ofDays(1), return new FileJsonSessionCodec(sessionName, this, 1024, Duration.ofDays(1),
Paths.get("/var/tmp/session")); Paths.get("/var/tmp/session"));
} }
@ -40,7 +36,7 @@ public class WebApplication extends BaseApplication {
return new IncomingSessionHandler( return new IncomingSessionHandler(
getSecret(), getSecret(),
"HmacSHA1", "HmacSHA1",
"SESSION", sessionName,
sessionCodec, sessionCodec,
getStaticFileSuffixes(), getStaticFileSuffixes(),
"user_id", "user_id",
@ -53,7 +49,7 @@ public class WebApplication extends BaseApplication {
return new OutgoingSessionHandler( return new OutgoingSessionHandler(
getSecret(), getSecret(),
"HmacSHA1", "HmacSHA1",
"SESSION", sessionName,
Duration.ofDays(1), Duration.ofDays(1),
sessionCodec, sessionCodec,
getStaticFileSuffixes(), getStaticFileSuffixes(),

View file

@ -15,16 +15,17 @@ import java.nio.charset.Charset;
public class HttpRequestBuilder extends BaseHttpRequestBuilder { public class HttpRequestBuilder extends BaseHttpRequestBuilder {
FullHttpRequest fullHttpRequest; protected FullHttpRequest fullHttpRequest;
ByteBuffer byteBuffer; protected ByteBuffer byteBuffer;
protected HttpRequestBuilder() { protected HttpRequestBuilder() {
} }
public HttpRequestBuilder setFullHttpRequest(FullHttpRequest fullHttpRequest) { public HttpRequestBuilder setFullHttpRequest(FullHttpRequest fullHttpRequest) {
if (fullHttpRequest != null) { if (fullHttpRequest != null) {
this.fullHttpRequest = fullHttpRequest; // retain request so we can read the body later without refCnt=0 error
this.fullHttpRequest = fullHttpRequest.retain();
setVersion(HttpVersion.valueOf(fullHttpRequest.protocolVersion().text())); setVersion(HttpVersion.valueOf(fullHttpRequest.protocolVersion().text()));
setMethod(HttpMethod.valueOf(fullHttpRequest.method().name())); setMethod(HttpMethod.valueOf(fullHttpRequest.method().name()));
setRequestURI(fullHttpRequest.uri()); setRequestURI(fullHttpRequest.uri());

View file

@ -41,6 +41,8 @@ public class BaseApplication implements Application {
private final HttpRequestValidator httpRequestValidator; private final HttpRequestValidator httpRequestValidator;
protected final String sessionName;
private final HttpHandler incomingCookieHandler; private final HttpHandler incomingCookieHandler;
private final HttpHandler outgoingCookieHandler; private final HttpHandler outgoingCookieHandler;
@ -59,6 +61,7 @@ public class BaseApplication implements Application {
new NamedThreadFactory("org-xbib-net-http-server-application")); new NamedThreadFactory("org-xbib-net-http-server-application"));
this.executor.setRejectedExecutionHandler((runnable, threadPoolExecutor) -> this.executor.setRejectedExecutionHandler((runnable, threadPoolExecutor) ->
logger.log(Level.SEVERE, "rejected " + runnable + " for thread pool executor = " + threadPoolExecutor)); logger.log(Level.SEVERE, "rejected " + runnable + " for thread pool executor = " + threadPoolExecutor));
this.sessionName = getSettings().get("session.name", "SESS");
this.httpRequestValidator = buildRequestValidator(); this.httpRequestValidator = buildRequestValidator();
this.incomingCookieHandler = buildIncomingCookieHandler(); this.incomingCookieHandler = buildIncomingCookieHandler();
this.outgoingCookieHandler = buildOutgoingCookieHandler(); this.outgoingCookieHandler = buildOutgoingCookieHandler();
@ -121,7 +124,14 @@ public class BaseApplication implements Application {
@Override @Override
public void dispatch(HttpRequestBuilder requestBuilder, HttpResponseBuilder responseBuilder) { public void dispatch(HttpRequestBuilder requestBuilder, HttpResponseBuilder responseBuilder) {
Future<?> future = executor.submit(() -> getRouter().route(requestBuilder, responseBuilder)); Future<?> future = executor.submit(() -> {
try {
getRouter().route(requestBuilder, responseBuilder);
} catch (Throwable t) {
logger.log(Level.SEVERE, t.getMessage(), t);
throw t;
}
});
logger.log(Level.FINE, "dispatching " + future); logger.log(Level.FINE, "dispatching " + future);
} }
@ -132,7 +142,12 @@ public class BaseApplication implements Application {
Future<?> future = executor.submit(() -> { Future<?> future = executor.submit(() -> {
HttpServerContext httpServerContext = createContext(null, httpRequestBuilder, httpResponseBuilder); HttpServerContext httpServerContext = createContext(null, httpRequestBuilder, httpResponseBuilder);
httpServerContext.attributes().put("responsebuilder", httpResponseBuilder); httpServerContext.attributes().put("responsebuilder", httpResponseBuilder);
try {
getRouter().routeStatus(httpResponseStatus, httpServerContext); getRouter().routeStatus(httpResponseStatus, httpServerContext);
} catch (Throwable t) {
logger.log(Level.SEVERE, t.getMessage(), t);
throw t;
}
}); });
logger.log(Level.FINE, "dispatching status " + future); logger.log(Level.FINE, "dispatching status " + future);
} }
@ -166,7 +181,7 @@ public class BaseApplication implements Application {
} }
protected Codec<Session> buildSessionCodec(HttpServerContext httpServerContext) { protected Codec<Session> buildSessionCodec(HttpServerContext httpServerContext) {
return new MemoryPropertiesSessionCodec(this, 1024, Duration.ofDays(1)); return new MemoryPropertiesSessionCodec(sessionName,this, 1024, Duration.ofDays(1));
} }
protected HttpHandler buildIncomingSessionHandler(HttpServerContext httpServerContext) { protected HttpHandler buildIncomingSessionHandler(HttpServerContext httpServerContext) {
@ -175,7 +190,7 @@ public class BaseApplication implements Application {
return new IncomingSessionHandler( return new IncomingSessionHandler(
getSecret(), getSecret(),
"HmacSHA1", "HmacSHA1",
"SESS", sessionName,
sessionCodec, sessionCodec,
getStaticFileSuffixes(), getStaticFileSuffixes(),
"user_id", "user_id",
@ -188,7 +203,7 @@ public class BaseApplication implements Application {
return new OutgoingSessionHandler( return new OutgoingSessionHandler(
getSecret(), getSecret(),
"HmacSHA1", "HmacSHA1",
"SESS", sessionName,
Duration.ofDays(1), Duration.ofDays(1),
sessionCodec, sessionCodec,
getStaticFileSuffixes(), getStaticFileSuffixes(),
@ -202,13 +217,13 @@ public class BaseApplication implements Application {
@Override @Override
public void onCreated(Session session) { public void onCreated(Session session) {
logger.log(Level.INFO, "session created = " + session); logger.log(Level.FINE, "session name = " + sessionName + " created = " + session);
builder.applicationModuleList.forEach(module -> module.onOpen(this, session)); builder.applicationModuleList.forEach(module -> module.onOpen(this, session));
} }
@Override @Override
public void onDestroy(Session session) { public void onDestroy(Session session) {
logger.log(Level.INFO, "session destroyed = " + session); logger.log(Level.FINE, "session name = " + sessionName + " destroyed = " + session);
builder.applicationModuleList.forEach(module -> module.onClose(this, session)); builder.applicationModuleList.forEach(module -> module.onClose(this, session));
} }

View file

@ -4,7 +4,6 @@ import org.xbib.config.ConfigLoader;
import org.xbib.config.ConfigLogger; import org.xbib.config.ConfigLogger;
import org.xbib.config.ConfigParams; import org.xbib.config.ConfigParams;
import org.xbib.config.SystemConfigLogger; import org.xbib.config.SystemConfigLogger;
import org.xbib.datastructures.common.ImmutableSet;
import org.xbib.net.http.server.route.HttpRouter; import org.xbib.net.http.server.route.HttpRouter;
import org.xbib.settings.Settings; import org.xbib.settings.Settings;
@ -136,12 +135,8 @@ public class BaseApplicationBuilder implements ApplicationBuilder {
return this; return this;
} }
public ApplicationBuilder addStaticSuffixes(String... suffixes) { public ApplicationBuilder setStaticSuffixes(String... suffixes) {
ImmutableSet.Builder<String> builder = ImmutableSet.builder(); this.staticFileSuffixes = Set.of(suffixes);
for (String suffix : suffixes) {
builder.add(suffix);
}
this.staticFileSuffixes = builder.build(new String[]{});
return this; return this;
} }
@ -152,12 +147,13 @@ public class BaseApplicationBuilder implements ApplicationBuilder {
@Override @Override
public Application build() { public Application build() {
prepareApplication();
Application application = new BaseApplication(this); Application application = new BaseApplication(this);
setupApplication(application); setupApplication(application);
return application; return application;
} }
protected void setupApplication(Application application) { protected void prepareApplication() {
String name = System.getProperty("application.name"); String name = System.getProperty("application.name");
if (name == null) { if (name == null) {
name = "application"; name = "application";
@ -176,6 +172,15 @@ public class BaseApplicationBuilder implements ApplicationBuilder {
this.configLoader = ConfigLoader.getInstance() this.configLoader = ConfigLoader.getInstance()
.withLogger(bootLogger); .withLogger(bootLogger);
this.settings = configLoader.load(configParams); this.settings = configLoader.load(configParams);
if (staticFileSuffixes == null) {
staticFileSuffixes = DEFAULT_SUFFIXES;
}
}
protected void setupApplication(Application application) {
if (router != null) {
router.setApplication(application);
}
for (Map.Entry<String, Settings> entry : settings.getGroups("module").entrySet()) { for (Map.Entry<String, Settings> entry : settings.getGroups("module").entrySet()) {
String moduleName = entry.getKey(); String moduleName = entry.getKey();
Settings moduleSettings = entry.getValue(); Settings moduleSettings = entry.getValue();
@ -197,22 +202,8 @@ public class BaseApplicationBuilder implements ApplicationBuilder {
logger.log(Level.WARNING, "disabled module: " + moduleName); logger.log(Level.WARNING, "disabled module: " + moduleName);
} }
} }
if (router != null) {
router.setApplication(application);
}
if (staticFileSuffixes == null) {
staticFileSuffixes = DEFAULT_SUFFIXES;
}
} }
private static final Set<String> DEFAULT_SUFFIXES = ImmutableSet.<String>builder() private static final Set<String> DEFAULT_SUFFIXES =
.add("css") Set.of("css", "js", "ico", "png", "jpg", "jpeg", "gif", "woff2");
.add("js")
.add("ico")
.add("png")
.add("jpg")
.add("jpeg")
.add("gif")
.add("woff2")
.build(new String[]{});
} }

View file

@ -59,8 +59,7 @@ public abstract class AbstractResourceHandler implements HttpHandler {
Resource resource = createResource(context); Resource resource = createResource(context);
logger.log(Level.FINE, "handle: resource = " + (resource != null ? resource.getClass().getName() + " " + resource : null)); logger.log(Level.FINE, "handle: resource = " + (resource != null ? resource.getClass().getName() + " " + resource : null));
if (resource instanceof HtmlTemplateResource) { if (resource instanceof HtmlTemplateResource) {
logger.log(Level.FINE, "handle: HTML template resource, generate cacheable resource, parameter = " + logger.log(Level.FINE, "handle: HTML template resource, generate cacheable resource");
context.httpRequest().getParameter());
generateCacheableResource(context, resource); generateCacheableResource(context, resource);
logger.log(Level.FINE, "handle: done"); logger.log(Level.FINE, "handle: done");
return; return;

View file

@ -49,23 +49,24 @@ public class HtmlTemplateResource implements HttpServerResource {
if (root == null) { if (root == null) {
throw new IllegalArgumentException("no home path set for template resource resolving"); throw new IllegalArgumentException("no home path set for template resource resolving");
} }
logger.log(Level.FINE, "class = " + getClass().getName());
logger.log(Level.FINE, "root = " + root); logger.log(Level.FINE, "root = " + root);
this.resourcePath = httpServerContext.request().getRequestPath().substring(1); this.resourcePath = httpServerContext.request().getRequestPath().substring(1);
logger.log(Level.FINE, "resource path = " + resourcePath); logger.log(Level.FINE, "resource path = " + resourcePath);
this.path = resourcePath.length() > 0 ? root.resolve(resourcePath) : root; this.path = resourcePath.length() > 0 ? root.resolve(resourcePath) : root;
logger.log(Level.FINE, "path = " + path); logger.log(Level.FINE, "path = " + path);
logger.log(Level.FINE, "index file name = " + indexFileName); logger.log(Level.FINE, "index file name = " + indexFileName);
this.url = URL.create(path.toUri().toString());
logger.log(Level.FINE, "uri = " + url);
this.name = path.getFileName().toString(); this.name = path.getFileName().toString();
this.baseName = AbstractResourceHandler.basename(name); this.baseName = AbstractResourceHandler.basename(name);
this.suffix = AbstractResourceHandler.suffix(name); this.suffix = AbstractResourceHandler.suffix(name);
if (Files.isDirectory(path)) { if (Files.isDirectory(path)) {
if (getIndexFileName() != null) { if (getIndexFileName() != null) {
Path indexPath = path.resolve(indexFileName); Path indexPath = path.resolve(indexFileName);
logger.log(Level.FINE, "index path = " + indexPath);
if (Files.exists(indexPath)) { if (Files.exists(indexPath)) {
this.isExistsIndexFile = true; this.isExistsIndexFile = true;
this.path = indexPath; this.path = indexPath;
logger.log(Level.FINE, "index file path found = " + path);
this.isDirectory = false; this.isDirectory = false;
} else { } else {
this.isExistsIndexFile = false; this.isExistsIndexFile = false;
@ -82,6 +83,8 @@ public class HtmlTemplateResource implements HttpServerResource {
this.isExists = Files.exists(path); this.isExists = Files.exists(path);
logger.log(Level.FINE, "exists = " + isExists); logger.log(Level.FINE, "exists = " + isExists);
logger.log(Level.FINE, "isDirectory = " + isDirectory); logger.log(Level.FINE, "isDirectory = " + isDirectory);
this.url = URL.create(path.toUri().toString());
logger.log(Level.FINE, "url = " + url);
if (isExists) { if (isExists) {
this.lastModified = Files.getLastModifiedTime(path).toInstant(); this.lastModified = Files.getLastModifiedTime(path).toInstant();
} else { } else {

View file

@ -18,6 +18,8 @@ public class BaseSession implements Session {
private final SessionListener sessionListener; private final SessionListener sessionListener;
private final String name;
private final String id; private final String id;
private final Duration lifetime; private final Duration lifetime;
@ -30,11 +32,13 @@ public class BaseSession implements Session {
public BaseSession(SessionListener sessionListener, public BaseSession(SessionListener sessionListener,
int cacheSize, int cacheSize,
String name,
String id, String id,
boolean create, boolean create,
Duration lifetime) { Duration lifetime) {
this.cacheSize = cacheSize; this.cacheSize = cacheSize;
this.sessionListener = sessionListener; this.sessionListener = sessionListener;
this.name = name;
this.id = id; this.id = id;
this.lifetime = lifetime; this.lifetime = lifetime;
this.map = new LinkedHashMap<>(); this.map = new LinkedHashMap<>();
@ -47,6 +51,12 @@ public class BaseSession implements Session {
} }
} }
} }
@Override
public String name() {
return name;
}
@Override @Override
public String id() { public String id() {
return id; return id;

View file

@ -5,6 +5,8 @@ import java.util.Map;
public interface Session extends Map<String, Object> { public interface Session extends Map<String, Object> {
String name();
String id(); String id();
void invalidate(); void invalidate();

View file

@ -27,6 +27,8 @@ public class FileJsonSessionCodec implements Codec<Session> {
private static final Logger logger = Logger.getLogger(FileJsonSessionCodec.class.getName()); private static final Logger logger = Logger.getLogger(FileJsonSessionCodec.class.getName());
private final String name;
private final ReentrantReadWriteLock lock; private final ReentrantReadWriteLock lock;
private final SessionListener sessionListener; private final SessionListener sessionListener;
@ -37,10 +39,13 @@ public class FileJsonSessionCodec implements Codec<Session> {
private final Duration sessionDuration; private final Duration sessionDuration;
public FileJsonSessionCodec(SessionListener sessionListener, public FileJsonSessionCodec(String name,
SessionListener sessionListener,
int sessionCacheSize, int sessionCacheSize,
Duration sessionDuration, Duration sessionDuration,
Path path) { Path path
) {
this.name = name;
this.sessionListener = sessionListener; this.sessionListener = sessionListener;
this.path = path; this.path = path;
this.sessionCacheSize = sessionCacheSize; this.sessionCacheSize = sessionCacheSize;
@ -56,7 +61,7 @@ public class FileJsonSessionCodec implements Codec<Session> {
@Override @Override
public Session create(String key) throws IOException { public Session create(String key) throws IOException {
return new BaseSession(sessionListener, sessionCacheSize, key, true, sessionDuration); return new BaseSession(sessionListener, sessionCacheSize, name, key, true, sessionDuration);
} }
@Override @Override
@ -66,7 +71,7 @@ public class FileJsonSessionCodec implements Codec<Session> {
try { try {
readLock.lock(); readLock.lock();
PercentEncoder percentEncoder = PercentEncoders.getUnreservedEncoder(StandardCharsets.UTF_8); PercentEncoder percentEncoder = PercentEncoders.getUnreservedEncoder(StandardCharsets.UTF_8);
session = new BaseSession(sessionListener, sessionCacheSize, key, false, sessionDuration); session = new BaseSession(sessionListener, sessionCacheSize, name, key, false, sessionDuration);
Map<String, Object> map = JsonUtil.toMap(Files.readString(path.resolve(percentEncoder.encode(key)))); Map<String, Object> map = JsonUtil.toMap(Files.readString(path.resolve(percentEncoder.encode(key))));
session.putAll(map); session.putAll(map);
return session; return session;

View file

@ -17,7 +17,6 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.xbib.net.http.server.HttpServerContext;
import org.xbib.net.http.server.persist.Codec; import org.xbib.net.http.server.persist.Codec;
import org.xbib.net.http.server.session.BaseSession; import org.xbib.net.http.server.session.BaseSession;
import org.xbib.net.http.server.session.Session; import org.xbib.net.http.server.session.Session;
@ -26,6 +25,8 @@ import org.xbib.net.util.JsonUtil;
public class JdbcSessionCodec implements Codec<Session>, Closeable { public class JdbcSessionCodec implements Codec<Session>, Closeable {
private final String name;
private final SessionListener sessionListener; private final SessionListener sessionListener;
private final int sessionCacheSize; private final int sessionCacheSize;
@ -44,7 +45,7 @@ public class JdbcSessionCodec implements Codec<Session>, Closeable {
private final ScheduledExecutorService scheduledExecutorService; private final ScheduledExecutorService scheduledExecutorService;
public JdbcSessionCodec(HttpServerContext httpServerContext, public JdbcSessionCodec(String name,
SessionListener sessionListener, SessionListener sessionListener,
int sessionCacheSize, int sessionCacheSize,
Duration sessionDuration, Duration sessionDuration,
@ -53,6 +54,7 @@ public class JdbcSessionCodec implements Codec<Session>, Closeable {
String writeSessionStringStatement, String writeSessionStringStatement,
String deleteSessionStringStatement, String deleteSessionStringStatement,
String purgeSessionStringStatement) { String purgeSessionStringStatement) {
this.name = name;
this.sessionListener = sessionListener; this.sessionListener = sessionListener;
this.sessionCacheSize = sessionCacheSize; this.sessionCacheSize = sessionCacheSize;
this.sessionDuration = sessionDuration; this.sessionDuration = sessionDuration;
@ -67,7 +69,7 @@ public class JdbcSessionCodec implements Codec<Session>, Closeable {
@Override @Override
public Session create(String key) throws IOException { public Session create(String key) throws IOException {
return new BaseSession(sessionListener, sessionCacheSize, key, true, sessionDuration); return new BaseSession(sessionListener, sessionCacheSize, name, key, true, sessionDuration);
} }
@Override @Override
@ -76,7 +78,7 @@ public class JdbcSessionCodec implements Codec<Session>, Closeable {
try { try {
Map<String, Object> map = JsonUtil.toMap(readString(key)); Map<String, Object> map = JsonUtil.toMap(readString(key));
if (map != null) { if (map != null) {
session = new BaseSession(sessionListener, sessionCacheSize, key, false, sessionDuration); session = new BaseSession(sessionListener, sessionCacheSize, name, key, false, sessionDuration);
session.putAll(map); session.putAll(map);
return session; return session;
} }

View file

@ -14,28 +14,32 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MemoryPropertiesSessionCodec implements Codec<Session> { public class MemoryPropertiesSessionCodec implements Codec<Session> {
private final ReentrantReadWriteLock lock;
private static final Map<String, Object> store = new HashMap<>(); private static final Map<String, Object> store = new HashMap<>();
private final String name;
private final ReentrantReadWriteLock lock;
private final SessionListener sessionListener; private final SessionListener sessionListener;
private final int sessionCacheSize; private final int sessionCacheSize;
private final Duration sessionDuration; private final Duration sessionDuration;
public MemoryPropertiesSessionCodec(SessionListener sessionListener, public MemoryPropertiesSessionCodec(String name,
SessionListener sessionListener,
int sessionCacheSize, int sessionCacheSize,
Duration sessionDuration) { Duration sessionDuration) {
this.lock = new ReentrantReadWriteLock(); this.name = name;
this.sessionListener = sessionListener; this.sessionListener = sessionListener;
this.sessionCacheSize = sessionCacheSize; this.sessionCacheSize = sessionCacheSize;
this.sessionDuration = sessionDuration; this.sessionDuration = sessionDuration;
this.lock = new ReentrantReadWriteLock();
} }
@Override @Override
public Session create(String key) throws IOException { public Session create(String key) throws IOException {
return new BaseSession(sessionListener, sessionCacheSize, key, true, sessionDuration); return new BaseSession(sessionListener, sessionCacheSize, name, key, true, sessionDuration);
} }
@Override @Override
@ -66,7 +70,7 @@ public class MemoryPropertiesSessionCodec implements Codec<Session> {
} }
private Session toSession(String key, Properties properties) { private Session toSession(String key, Properties properties) {
Session session = new BaseSession(sessionListener, sessionCacheSize, key, false, sessionDuration); Session session = new BaseSession(sessionListener, sessionCacheSize, name, key, false, sessionDuration);
properties.forEach((k, v) -> session.put(k.toString(), v)); properties.forEach((k, v) -> session.put(k.toString(), v));
return session; return session;
} }

View file

@ -5,6 +5,7 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.SynchronousQueue; import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
@ -26,7 +27,7 @@ public class BlockingThreadPoolExecutor extends ThreadPoolExecutor {
ThreadFactory threadFactory) { ThreadFactory threadFactory) {
super(nThreads, nThreads, keepAliveTime, timeUnit, createBlockingQueue(maxQueue), threadFactory); super(nThreads, nThreads, keepAliveTime, timeUnit, createBlockingQueue(maxQueue), threadFactory);
logger.log(Level.INFO, "blocking threadpool executor up with nThreads = " + nThreads + logger.log(Level.INFO, "blocking threadpool executor up with nThreads = " + nThreads +
" keepALiveTime = " + keepAliveTime + " keepAliveTime = " + keepAliveTime +
" time unit = " + timeUnit + " time unit = " + timeUnit +
" maxQueue = " + maxQueue + " maxQueue = " + maxQueue +
" thread factory = " + threadFactory); " thread factory = " + threadFactory);
@ -42,7 +43,7 @@ public class BlockingThreadPoolExecutor extends ThreadPoolExecutor {
@Override @Override
protected void afterExecute(Runnable runnable, Throwable terminationCause) { protected void afterExecute(Runnable runnable, Throwable terminationCause) {
super.afterExecute(runnable, terminationCause); super.afterExecute(runnable, terminationCause);
logger.log(Level.FINE, "after dispatching " + runnable); logger.log(Level.FINE, "after dispatching " + runnable + " terminationCause = " + terminationCause);
Throwable throwable = terminationCause; Throwable throwable = terminationCause;
if (throwable == null && runnable instanceof Future<?>) { if (throwable == null && runnable instanceof Future<?>) {
try { try {

View file

@ -3,6 +3,8 @@ package org.xbib.net.http.template.groovy;
import groovy.text.markup.BaseTemplate; import groovy.text.markup.BaseTemplate;
import groovy.text.markup.MarkupTemplateEngine; import groovy.text.markup.MarkupTemplateEngine;
import groovy.text.markup.TemplateConfiguration; import groovy.text.markup.TemplateConfiguration;
import java.util.Objects;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.xbib.net.URL; import org.xbib.net.URL;
@ -27,13 +29,13 @@ public abstract class DefaultMarkupTemplate extends BaseTemplate {
private static final Logger logger = Logger.getLogger(DefaultMarkupTemplate.class.getName()); private static final Logger logger = Logger.getLogger(DefaultMarkupTemplate.class.getName());
private final Application application; protected final Application application;
private final HttpRequest request; protected final Session session;
private final HttpResponseBuilder responseBuilder; protected final HttpRequest request;
private final Session session; protected final HttpResponseBuilder responseBuilder;
public DefaultMarkupTemplate(MarkupTemplateEngine templateEngine, public DefaultMarkupTemplate(MarkupTemplateEngine templateEngine,
Map<String,?> model, Map<String,?> model,
@ -41,9 +43,13 @@ public abstract class DefaultMarkupTemplate extends BaseTemplate {
TemplateConfiguration configuration) { TemplateConfiguration configuration) {
super(templateEngine, model, modelTypes, configuration); super(templateEngine, model, modelTypes, configuration);
this.application = (Application) model.get("application"); this.application = (Application) model.get("application");
this.request = (HttpRequest) model.get("request"); Objects.requireNonNull(this.application, "application must not be null");
this.responseBuilder = (HttpResponseBuilder) model.get("responsebuilder");
this.session = (Session) model.get("session"); this.session = (Session) model.get("session");
Objects.requireNonNull(this.session, "session must not be null");
this.request = (HttpRequest) model.get("request");
Objects.requireNonNull(this.request, "request must not be null");
this.responseBuilder = (HttpResponseBuilder) model.get("responsebuilder");
Objects.requireNonNull(this.responseBuilder, "response must not be null");
} }
public void responseStatus(HttpResponseStatus responseStatus) { public void responseStatus(HttpResponseStatus responseStatus) {
@ -67,23 +73,23 @@ public abstract class DefaultMarkupTemplate extends BaseTemplate {
responseBuilder.setHeader(HttpHeaderNames.CONTENT_LENGTH, Integer.toString(contentLength)); responseBuilder.setHeader(HttpHeaderNames.CONTENT_LENGTH, Integer.toString(contentLength));
} }
public void sendPermanentRedirect(String url) { public void movedPermanently(String url) {
responseBuilder.setResponseStatus(HttpResponseStatus.MOVED_PERMANENTLY); responseBuilder.setResponseStatus(HttpResponseStatus.MOVED_PERMANENTLY); // 301
responseBuilder.setHeader(HttpHeaderNames.LOCATION, url); responseBuilder.setHeader(HttpHeaderNames.LOCATION, url);
} }
public void sendRedirect(String url) { public void found(String url) {
responseBuilder.setResponseStatus(HttpResponseStatus.FOUND); responseBuilder.setResponseStatus(HttpResponseStatus.FOUND); // 302
responseBuilder.setHeader(HttpHeaderNames.LOCATION, url); responseBuilder.setHeader(HttpHeaderNames.LOCATION, url);
} }
public void seeOther(String url) { public void seeOther(String url) {
responseBuilder.setResponseStatus(HttpResponseStatus.SEE_OTHER); responseBuilder.setResponseStatus(HttpResponseStatus.SEE_OTHER); // 303
responseBuilder.setHeader(HttpHeaderNames.LOCATION, url); responseBuilder.setHeader(HttpHeaderNames.LOCATION, url);
} }
public void temporaryRedirect(String url) { public void temporaryRedirect(String url) {
responseBuilder.setResponseStatus(HttpResponseStatus.TEMPORARY_REDIRECT); responseBuilder.setResponseStatus(HttpResponseStatus.TEMPORARY_REDIRECT); // 307
responseBuilder.setHeader(HttpHeaderNames.LOCATION, url); responseBuilder.setHeader(HttpHeaderNames.LOCATION, url);
} }