diff --git a/asciidoc/examples/httpresp.adoc b/asciidoc/examples/httpresp.adoc index dff3cc1608..49991829f6 100644 --- a/asciidoc/examples/httpresp.adoc +++ b/asciidoc/examples/httpresp.adoc @@ -15,7 +15,7 @@ public class Main { public static void main(String[] args) { - /* Returning the request or response object means the response was constructed */ + /* Returning the request or response object means the response was constructed */ On.get("/").html((Req req) -> { Resp resp = req.response(); diff --git a/asciidoc/examples/jpascaffold.adoc b/asciidoc/examples/jpascaffold.adoc index 9f50bb2e37..38654195fb 100644 --- a/asciidoc/examples/jpascaffold.adoc +++ b/asciidoc/examples/jpascaffold.adoc @@ -40,6 +40,7 @@ import java.util.List; public class Main extends GUI { + @SuppressWarnings("unchecked") public static void main(String[] args) { On.page("/").mvc("Welcome!"); diff --git a/commons/rapidoid-commons/src/main/resources/rapidoid-classes.txt b/commons/rapidoid-commons/src/main/resources/rapidoid-classes.txt index 5629f99c9c..190cc41a32 100644 --- a/commons/rapidoid-commons/src/main/resources/rapidoid-classes.txt +++ b/commons/rapidoid-commons/src/main/resources/rapidoid-classes.txt @@ -363,9 +363,15 @@ org.rapidoid.http.FastHttp org.rapidoid.http.FastHttpProtocol org.rapidoid.http.handler.AbstractDecoratingHttpHandler org.rapidoid.http.handler.AbstractHttpHandler +org.rapidoid.http.handler.AbstractHttpHandlerDecorator org.rapidoid.http.handler.HandlerInvocation org.rapidoid.http.handler.HandlerResultProcessor +org.rapidoid.http.handler.HttpAuthWrapper org.rapidoid.http.handler.HttpHandler +org.rapidoid.http.handler.HttpManagedHandlerDecorator +org.rapidoid.http.handler.HttpTxWrapper +org.rapidoid.http.handler.HttpUnmanagedHandlerDecorator +org.rapidoid.http.handler.HttpWrappers org.rapidoid.http.handler.lambda.FiveParamLambdaHandler org.rapidoid.http.handler.lambda.FourParamLambdaHandler org.rapidoid.http.handler.lambda.NParamLambdaHandler @@ -399,7 +405,6 @@ org.rapidoid.http.handler.PredefinedResponseHandler org.rapidoid.http.handler.ResourceHttpHandler org.rapidoid.http.handler.StaticHttpHandler org.rapidoid.http.handler.StaticResourcesHandler -org.rapidoid.http.handler.TxUtil org.rapidoid.http.Headers org.rapidoid.http.HTTP org.rapidoid.http.HttpClient @@ -435,6 +440,7 @@ org.rapidoid.http.impl.MVCModelImpl org.rapidoid.http.impl.PathPattern org.rapidoid.http.impl.RapidoidReqInfo org.rapidoid.http.impl.ReqImpl +org.rapidoid.http.impl.RespBodyBuffer org.rapidoid.http.impl.RespBodyBytes org.rapidoid.http.impl.RespImpl org.rapidoid.http.impl.ResponseRenderer diff --git a/networking/rapidoid-net/src/main/java/org/rapidoid/net/NetworkingParams.java b/networking/rapidoid-net/src/main/java/org/rapidoid/net/NetworkingParams.java index e01efd1255..ef7ef9de00 100644 --- a/networking/rapidoid-net/src/main/java/org/rapidoid/net/NetworkingParams.java +++ b/networking/rapidoid-net/src/main/java/org/rapidoid/net/NetworkingParams.java @@ -20,11 +20,12 @@ package org.rapidoid.net; +import org.rapidoid.RapidoidThing; import org.rapidoid.config.BasicConfig; import org.rapidoid.net.impl.DefaultExchange; import org.rapidoid.net.impl.RapidoidHelper; -public class NetworkingParams { +public class NetworkingParams extends RapidoidThing { private volatile String address; diff --git a/networking/rapidoid-net/src/main/java/org/rapidoid/net/TLSParams.java b/networking/rapidoid-net/src/main/java/org/rapidoid/net/TLSParams.java index c89f7356db..2578e5d7f2 100644 --- a/networking/rapidoid-net/src/main/java/org/rapidoid/net/TLSParams.java +++ b/networking/rapidoid-net/src/main/java/org/rapidoid/net/TLSParams.java @@ -20,13 +20,14 @@ package org.rapidoid.net; +import org.rapidoid.RapidoidThing; import org.rapidoid.config.Conf; import org.rapidoid.net.tls.TLSUtil; import org.rapidoid.util.MscOpts; import javax.net.ssl.SSLContext; -public class TLSParams { +public class TLSParams extends RapidoidThing { // auto-activate if TLS is enabled private volatile boolean tls = MscOpts.isTLSEnabled(); diff --git a/networking/rapidoid-net/src/main/java/org/rapidoid/net/impl/RapidoidConnection.java b/networking/rapidoid-net/src/main/java/org/rapidoid/net/impl/RapidoidConnection.java index 1bd20d1390..bda7de7a61 100644 --- a/networking/rapidoid-net/src/main/java/org/rapidoid/net/impl/RapidoidConnection.java +++ b/networking/rapidoid-net/src/main/java/org/rapidoid/net/impl/RapidoidConnection.java @@ -339,6 +339,11 @@ public void resume(final long expectedConnId, final long handle, final AsyncLogi public void run() { resume(expectedConnId, handle, asyncLogic); } + + @Override + public String toString() { + return U.frmt("RapidoidConnection.ResumeJob(handle=%s, expectedConnId=%s, logic=%s)", handle, expectedConnId, asyncLogic); + } }); } else if (seq == handle - 1) { diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/FastHttp.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/FastHttp.java index 04397da358..f713bdfb46 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/FastHttp.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/FastHttp.java @@ -70,6 +70,7 @@ public FastHttp(HttpRoutesImpl routes) { public FastHttp(HttpRoutesImpl routes, @SuppressWarnings("unused") Config serverConfig) { super(null); this.routes = routes; + routes.setHttp(this); } @Override @@ -198,7 +199,7 @@ private void serveCached(ReqImpl req, CachedResp resp) { req.cached(true); HttpIO.INSTANCE.respond(HttpUtils.req(req), channel, -1, -1, resp.statusCode, - req.isKeepAlive(), resp.contentType, resp.body.duplicate(), resp.headers, null); + req.isKeepAlive(), resp.contentType, new RespBodyBuffer(resp.body.duplicate()), resp.headers, null); channel.send().closeIf(!req.isKeepAlive()); } @@ -281,7 +282,7 @@ public ReqImpl createReq(Channel channel, boolean isGet, boolean isKeepAlive, private HttpStatus handleIfFound(Channel channel, boolean isKeepAlive, HttpHandler handler, Req req) { try { - return handler.handle(channel, isKeepAlive, req, null); + return handler.handle(channel, isKeepAlive, req); } catch (NotFound nf) { return HttpStatus.NOT_FOUND; } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/HttpUtils.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/HttpUtils.java index cacdcb6570..7e1e3b5d2e 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/HttpUtils.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/HttpUtils.java @@ -305,7 +305,7 @@ public static TokenAuthData getAuth(Req req) { } public static String inferRealIpAddress(Req req) { - // // FIXME if CloudFlare is detected, use req.header("cf-connecting-ip") + // TODO if CloudFlare is detected, use req.header("cf-connecting-ip")? return req.clientIpAddress(); } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/RespBody.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/RespBody.java index 0e28d47cb0..8929cb44b5 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/RespBody.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/RespBody.java @@ -22,11 +22,14 @@ import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Since; +import org.rapidoid.net.abstracts.Channel; @Authors("Nikolche Mihajlovski") @Since("5.5.1") public interface RespBody { - byte[] toBytes(); + int length(); + + void writeTo(Channel channel); } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/customize/Customization.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/customize/Customization.java index 2be4c51594..ef9f2b008e 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/customize/Customization.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/customize/Customization.java @@ -125,13 +125,11 @@ public static Customization of(Req req) { private static boolean inValidContext(Req req) { Ctx ctx = Ctxs.get(); Req ctxReq = ctx != null ? (Req) ctx.exchange() : null; + + U.must(ctx == null || !ctx.isClosed(), "The context for request (%s) is closed!"); U.must(req == ctxReq, "The customization request (%s) doesn't match the context request (%s)!", req, ctxReq); - return true; - } - public static Customization current() { - Ctx ctx = Ctxs.get(); - return of(ctx != null ? (Req) ctx.exchange() : null); + return true; } public String name() { diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/AbstractDecoratingHttpHandler.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/AbstractDecoratingHttpHandler.java index 5339c64608..90f3f7970c 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/AbstractDecoratingHttpHandler.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/AbstractDecoratingHttpHandler.java @@ -22,45 +22,27 @@ import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Since; -import org.rapidoid.annotation.TransactionMode; -import org.rapidoid.ctx.With; -import org.rapidoid.http.*; -import org.rapidoid.http.customize.Customization; -import org.rapidoid.http.impl.MaybeReq; -import org.rapidoid.http.impl.ReqImpl; -import org.rapidoid.http.impl.RespImpl; +import org.rapidoid.http.FastHttp; +import org.rapidoid.http.HttpStatus; +import org.rapidoid.http.Req; import org.rapidoid.http.impl.RouteOptions; -import org.rapidoid.http.impl.lowlevel.HttpIO; -import org.rapidoid.jpa.JPA; -import org.rapidoid.lambda.Mapper; -import org.rapidoid.log.Log; -import org.rapidoid.log.LogLevel; import org.rapidoid.net.abstracts.Channel; -import org.rapidoid.security.Secure; import org.rapidoid.u.U; -import org.rapidoid.util.TokenAuthData; - -import java.util.Collections; -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; - @Authors("Nikolche Mihajlovski") @Since("4.3.0") public abstract class AbstractDecoratingHttpHandler extends AbstractHttpHandler { - private static final String CTX_TAG_INIT = "init"; - private static final String CTX_TAG_HANDLER = "handler"; - private static final String CTX_TAG_ERROR = "error"; + private final AbstractHttpHandlerDecorator decorator; - private static final HttpWrapper[] NO_WRAPPERS = {}; + public AbstractDecoratingHttpHandler(FastHttp http, RouteOptions options) { + super(options); - private final FastHttp http; + U.notNull(http, "http"); - @SuppressWarnings("UnusedParameters") - public AbstractDecoratingHttpHandler(FastHttp http, HttpRoutes routes, RouteOptions options) { - super(options); - this.http = http; + this.decorator = options.managed() + ? new HttpManagedHandlerDecorator(this, http, options) + : new HttpUnmanagedHandlerDecorator(this, http, options.contentType()); } @Override @@ -69,301 +51,10 @@ public boolean needsParams() { } @Override - public final HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req, Object extra) { - return options.managed() - ? handleDecorating(ctx, isKeepAlive, req, extra) - : handleNonDecorating(ctx, isKeepAlive, req, extra); - } - - private HttpStatus handleNonDecorating(Channel ctx, boolean isKeepAlive, Req req, Object extra) { - Object result; - MaybeReq maybeReq = HttpUtils.maybe(req); - - ReqImpl reqq = (ReqImpl) req; - - // handle & post-process - result = handleReqAndPostProcess(ctx, isKeepAlive, req, extra); - - // the response properties might be overwritten - int code = -1; - MediaType ctype = contentType; - if (req != null && reqq.hasResponseAttached()) { - Resp resp = req.response(); - ctype = resp.contentType(); - code = resp.code(); - } - - if (result == HttpStatus.NOT_FOUND) { - http.notFound(ctx, isKeepAlive, ctype, this, req); - return HttpStatus.NOT_FOUND; - } - - if (result == HttpStatus.ASYNC) { - return HttpStatus.ASYNC; - } - - if (result instanceof Throwable) { - Throwable err = (Throwable) result; - HttpIO.INSTANCE.writeHttpResp(maybeReq, ctx, isKeepAlive, 500, MediaType.PLAIN_TEXT_UTF_8, "Internal server error!".getBytes()); - - Log.error("Error occurred during unmanaged request processing", "request", req, "error", err); - return HttpStatus.DONE; - } - - int respCode = code > 0 ? code : 200; // default code is 200 - HttpIO.INSTANCE.writeHttpResp(maybeReq, ctx, isKeepAlive, respCode, ctype, result); - - return HttpStatus.DONE; - } - - private HttpStatus handleDecorating(Channel ctx, boolean isKeepAlive, Req req, Object extra) { - - if (!ctx.isAsync()) { - // first checks if not async, to avoid exceptions when running the second time from non-IO thread - ctx.async(); - } - - execHandlerJob(ctx, isKeepAlive, options.contentType(), req, extra); - - return HttpStatus.ASYNC; - } - - private Set userRoles(Req req, String username) { - if (username != null) { - try { - return Customization.of(req).rolesProvider().getRolesForUser(req, username); - } catch (Exception e) { - throw U.rte(e); - } - } else { - return Collections.emptySet(); - } - } - - private void before(final Req req, String username, Set roles) { - if (U.notEmpty(options.roles()) && !Secure.hasAnyRole(username, roles, options.roles())) { - throw new SecurityException("The user doesn't have the required roles!"); - } - - req.response().view(options.view()).contentType(options.contentType()).mvc(options.mvc()); - } - - private void execHandlerJob(final Channel channel, final boolean isKeepAlive, final MediaType contentType, - final Req req, final Object extra) { - - With.tag(CTX_TAG_INIT).exchange(req).run(new Runnable() { - - volatile String username = null; - volatile Set roles = null; - volatile Set scope = null; - - @Override - public void run() { - try { - - TokenAuthData auth = HttpUtils.getAuth(req); - - if (auth != null) username = auth.user; - - if (U.isEmpty(username)) { - HttpUtils.clearUserData(req); - } - - roles = userRoles(req, username); - scope = auth != null ? auth.scope : null; - - before(req, username, roles); - - TransactionMode txMode = TxUtil.txModeOf(req, options.transaction()); - U.notNull(txMode, "txMode"); - - HttpWrapper[] wrappers = httpWrappers != null ? httpWrappers : U.or(Customization.of(req).wrappers(), NO_WRAPPERS); - - Runnable handleRequest = handlerWithWrappers(channel, isKeepAlive, contentType, req, extra, wrappers, txMode); - - With.tag(CTX_TAG_HANDLER).exchange(req).username(username).roles(roles).scope(scope).run(handleRequest); - - } catch (Throwable e) { - // if there was an error in the job scheduling: - execErrorHandler(req, username, roles, scope, e); - } - } - }); - } - - private HttpStatus execErrorHandler(final Req req, String username, Set roles, Set scope, final Throwable error) { - With.tag(CTX_TAG_ERROR).exchange(req).username(username).roles(roles).scope(scope).run(new Runnable() { - @Override - public void run() { - handleError(req, error); - } - }); - - return HttpStatus.ASYNC; - } - - private Runnable handlerWithWrappers(final Channel channel, final boolean isKeepAlive, final MediaType contentType, - final Req req, final Object extra, final HttpWrapper[] wrappers, final TransactionMode txMode) { - - return new Runnable() { - - @Override - public void run() { - Object result; - try { - - if (!U.isEmpty(wrappers)) { - result = wrap(channel, isKeepAlive, req, 0, extra, wrappers, txMode); - } else { - result = handleReqMaybeInTx(channel, isKeepAlive, req, extra, txMode); - } - - } catch (Throwable e) { - result = e; - } - - complete(channel, isKeepAlive, contentType, req, result); - } - }; - } - - private Object handleReqMaybeInTx(final Channel channel, final boolean isKeepAlive, final Req req, - final Object extra, TransactionMode txMode) { - - if (txMode != null && txMode != TransactionMode.NONE) { - - final AtomicReference result = new AtomicReference<>(); - - try { - JPA.transaction(new Runnable() { - @Override - public void run() { - Object res = handleReqAndPostProcess(channel, isKeepAlive, req, extra); - - if (res instanceof Throwable) { - // throw to rollback - Throwable err = (Throwable) res; - throw U.rte("Error occurred inside the transactional web handler!", err); - - } else { - // serialize the result into a HTTP response body, while still inside tx (see #153) - RespImpl resp = (RespImpl) req.response(); // TODO find cleaner access - RespBody body = resp.resultToRespBody(res); - res = body; - } - - result.set(res); - } - }, txMode == TransactionMode.READ_ONLY); - - } catch (Throwable e) { - result.set(e); - } - - return result.get(); - - } else { - return handleReqAndPostProcess(channel, isKeepAlive, req, extra); - } - } - - private Object wrap(final Channel channel, final boolean isKeepAlive, final Req req, final int index, - final Object extra, final HttpWrapper[] wrappers, final TransactionMode txMode) throws Exception { - - HttpWrapper wrapper = wrappers[index]; - - HandlerInvocation invocation = new HandlerInvocation() { - - @Override - public Object invoke() throws Exception { - return invokeAndTransformResult(null); - } - - @Override - public Object invokeAndTransformResult(Mapper transformation) throws Exception { - try { - int next = index + 1; - - Object val; - if (next < wrappers.length) { - val = wrap(channel, isKeepAlive, req, next, extra, wrappers, txMode); - } else { - val = handleReqMaybeInTx(channel, isKeepAlive, req, extra, txMode); - } - - return transformation != null ? transformation.map(val) : val; - - } catch (Throwable e) { - return e; - } - } - }; - - return wrapper.wrap(req, invocation); - } - - private Object handleError(Req req, Throwable e) { - req.revert(); - req.async(); - - HttpIO.INSTANCE.error(req, e, LogLevel.ERROR); - // the Req object will do the rendering - req.done(); - - return req; - } - - protected abstract Object handleReq(Channel ctx, boolean isKeepAlive, Req req, Object extra) throws Throwable; - - private Object handleReqAndPostProcess(Channel ctx, boolean isKeepAlive, Req req, Object extra) { - Object result; - - try { - result = handleReq(ctx, isKeepAlive, req, extra); - - } catch (Throwable e) { - result = e; - } - - return HandlerResultProcessor.INSTANCE.postProcessResult(req, result); + public final HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req) { + return decorator.handle(ctx, isKeepAlive, req); } - public void complete(Channel ctx, boolean isKeepAlive, MediaType contentType, Req req, Object result) { - - U.must(result != null, "The post-processed result cannot be null!"); - U.must(!(result instanceof Req), "The post-processed result cannot be a Req instance!"); - U.must(!(result instanceof Resp), "The post-processed result cannot be a Resp instance!"); - - if (result instanceof Throwable) { - handleError(req, (Throwable) result); - return; - } - - if (result == HttpStatus.NOT_FOUND) { - http.notFound(ctx, isKeepAlive, contentType, this, req); - return; - } - - if (result == HttpStatus.ERROR) { - complete(ctx, isKeepAlive, contentType, req, U.rte("Handler error!")); - return; - } - - if (result == HttpStatus.ASYNC) { - return; - } - - processNormalResult(req, result); - } - - private void processNormalResult(Req req, Object result) { - - HttpUtils.resultToResponse(req, result); - - // the Req object will do the rendering - if (!req.isAsync()) { - req.done(); - } - } + protected abstract Object handleReq(Channel ctx, boolean isKeepAlive, Req req) throws Throwable; } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/AbstractHttpHandler.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/AbstractHttpHandler.java index 49711e7d18..79909c6ad2 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/AbstractHttpHandler.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/AbstractHttpHandler.java @@ -23,7 +23,6 @@ import org.rapidoid.RapidoidThing; import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Since; -import org.rapidoid.http.HttpWrapper; import org.rapidoid.http.MediaType; import org.rapidoid.http.Route; import org.rapidoid.http.impl.RouteOptions; @@ -40,14 +39,11 @@ public abstract class AbstractHttpHandler extends RapidoidThing implements HttpH protected final MediaType contentType; - protected final HttpWrapper[] httpWrappers; - protected volatile Route route; public AbstractHttpHandler(RouteOptions options) { this.options = options; this.contentType = options.contentType(); - this.httpWrappers = options.wrappers(); } @Override @@ -77,6 +73,7 @@ public RouteOptions options() { protected String contentTypeInfo(String inside) { String type; + if (contentType == MediaType.HTML_UTF_8) { type = options.mvc() ? "mvc" : "html"; diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/AbstractHttpHandlerDecorator.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/AbstractHttpHandlerDecorator.java new file mode 100644 index 0000000000..cab196c887 --- /dev/null +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/AbstractHttpHandlerDecorator.java @@ -0,0 +1,59 @@ +/*- + * #%L + * rapidoid-http-fast + * %% + * Copyright (C) 2014 - 2017 Nikolche Mihajlovski and contributors + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +package org.rapidoid.http.handler; + +import org.rapidoid.RapidoidThing; +import org.rapidoid.annotation.Authors; +import org.rapidoid.annotation.Since; +import org.rapidoid.http.FastHttp; +import org.rapidoid.http.HttpStatus; +import org.rapidoid.http.Req; +import org.rapidoid.net.abstracts.Channel; + +@Authors("Nikolche Mihajlovski") +@Since("5.5.1") +public abstract class AbstractHttpHandlerDecorator extends RapidoidThing { + + protected final AbstractDecoratingHttpHandler handler; + + protected final FastHttp http; + + AbstractHttpHandlerDecorator(AbstractDecoratingHttpHandler handler, FastHttp http) { + this.handler = handler; + this.http = http; + } + + Object handleReqAndPostProcess(Channel ctx, boolean isKeepAlive, Req req) { + Object result; + + try { + result = handler.handleReq(ctx, isKeepAlive, req); + + } catch (Throwable e) { + result = e; + } + + return HandlerResultProcessor.INSTANCE.postProcessResult(req, result); + } + + abstract HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req); + +} diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpAuthWrapper.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpAuthWrapper.java new file mode 100644 index 0000000000..732a9b776b --- /dev/null +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpAuthWrapper.java @@ -0,0 +1,85 @@ +/*- + * #%L + * rapidoid-http-fast + * %% + * Copyright (C) 2014 - 2017 Nikolche Mihajlovski and contributors + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +package org.rapidoid.http.handler; + +import org.rapidoid.RapidoidThing; +import org.rapidoid.annotation.Authors; +import org.rapidoid.annotation.Since; +import org.rapidoid.ctx.Ctx; +import org.rapidoid.ctx.Ctxs; +import org.rapidoid.ctx.UserInfo; +import org.rapidoid.http.HttpUtils; +import org.rapidoid.http.HttpWrapper; +import org.rapidoid.http.Req; +import org.rapidoid.http.customize.Customization; +import org.rapidoid.security.Secure; +import org.rapidoid.u.U; +import org.rapidoid.util.TokenAuthData; + +import java.util.Collections; +import java.util.Set; + +@Authors("Nikolche Mihajlovski") +@Since("5.5.1") +public class HttpAuthWrapper extends RapidoidThing implements HttpWrapper { + + private final Set requiredRoles; + + public HttpAuthWrapper(Set requiredRoles) { + this.requiredRoles = requiredRoles; + } + + @Override + public Object wrap(final Req req, final HandlerInvocation invocation) throws Exception { + TokenAuthData auth = HttpUtils.getAuth(req); + + String username = auth != null ? auth.user : null; + + if (U.isEmpty(username)) { + HttpUtils.clearUserData(req); + } + + Set roles = userRoles(req, username); + Set scope = auth != null ? auth.scope : null; + + if (U.notEmpty(requiredRoles) && !Secure.hasAnyRole(username, roles, requiredRoles)) { + throw new SecurityException("The user doesn't have the required roles!"); + } + + Ctx ctx = Ctxs.required(); + ctx.setUser(new UserInfo(username, roles, scope)); + + return invocation.invoke(); + } + + private Set userRoles(Req req, String username) { + if (username != null) { + try { + return Customization.of(req).rolesProvider().getRolesForUser(req, username); + } catch (Exception e) { + throw U.rte(e); + } + } else { + return Collections.emptySet(); + } + } + +} diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpHandler.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpHandler.java index 0f1c9bb99f..60c53a2b07 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpHandler.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpHandler.java @@ -35,7 +35,7 @@ @Since("4.3.0") public interface HttpHandler extends HandlerMatch { - HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req, Object extra); + HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req); boolean needsParams(); diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpManagedHandlerDecorator.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpManagedHandlerDecorator.java new file mode 100644 index 0000000000..8fbc380b3f --- /dev/null +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpManagedHandlerDecorator.java @@ -0,0 +1,195 @@ +/*- + * #%L + * rapidoid-http-fast + * %% + * Copyright (C) 2014 - 2017 Nikolche Mihajlovski and contributors + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +package org.rapidoid.http.handler; + +import org.rapidoid.annotation.Authors; +import org.rapidoid.annotation.Since; +import org.rapidoid.ctx.With; +import org.rapidoid.http.*; +import org.rapidoid.http.impl.RouteOptions; +import org.rapidoid.http.impl.lowlevel.HttpIO; +import org.rapidoid.lambda.Mapper; +import org.rapidoid.log.LogLevel; +import org.rapidoid.net.abstracts.Channel; +import org.rapidoid.u.U; +import org.rapidoid.util.LazyInit; + +import java.util.concurrent.Callable; + +@Authors("Nikolche Mihajlovski") +@Since("5.5.1") +public class HttpManagedHandlerDecorator extends AbstractHttpHandlerDecorator { + + private static final String CTX_TAG_HANDLER = "handler"; + + private final RouteOptions options; + + private final LazyInit wrappers; + + HttpManagedHandlerDecorator(AbstractDecoratingHttpHandler handler, final FastHttp http, final RouteOptions options) { + super(handler, http); + + this.options = options; + this.wrappers = new LazyInit<>(new Callable() { + @Override + public HttpWrapper[] call() { + return HttpWrappers.assembleWrappers(http, options); + } + }); + } + + @Override + public final HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req) { + if (!ctx.isAsync()) { + // first checks if not async, to avoid exceptions when running the second time from non-IO thread + ctx.async(); + } + + execHandlerJob(ctx, isKeepAlive, options.contentType(), req); + + return HttpStatus.ASYNC; + } + + private void execHandlerJob(final Channel channel, final boolean isKeepAlive, final MediaType contentType, final Req req) { + + With.tag(CTX_TAG_HANDLER).exchange(req).run(new Runnable() { + + @Override + public void run() { + try { + req.response() + .view(options.view()) + .contentType(options.contentType()) + .mvc(options.mvc()); + + handleWithWrappers(channel, isKeepAlive, contentType, req, wrappers.get()); + + } catch (Throwable e) { + handleError(req, e); + } + } + + }); + } + + private void handleWithWrappers(Channel channel, boolean isKeepAlive, MediaType contentType, + Req req, HttpWrapper[] wrappers) { + Object result; + + try { + + if (!U.isEmpty(wrappers)) { + result = wrap(channel, isKeepAlive, req, 0, wrappers); + } else { + result = handleReqAndPostProcess(channel, isKeepAlive, req); + } + + } catch (Throwable e) { + result = e; + } + + complete(channel, isKeepAlive, contentType, req, result); + } + + private Object wrap(final Channel channel, final boolean isKeepAlive, final Req req, final int index, + final HttpWrapper[] wrappers) throws Exception { + + HttpWrapper wrapper = wrappers[index]; + + HandlerInvocation invocation = new HandlerInvocation() { + + @Override + public Object invoke() { + return invokeAndTransformResult(null); + } + + @Override + public Object invokeAndTransformResult(Mapper transformation) { + try { + int next = index + 1; + + Object val; + if (next < wrappers.length) { + val = wrap(channel, isKeepAlive, req, next, wrappers); + } else { + val = handleReqAndPostProcess(channel, isKeepAlive, req); + } + + return transformation != null ? transformation.map(val) : val; + + } catch (Throwable e) { + return e; + } + } + }; + + return wrapper.wrap(req, invocation); + } + + private void handleError(Req req, Throwable e) { + req.revert(); + req.async(); + + HttpIO.INSTANCE.error(req, e, LogLevel.ERROR); + + // the Req object will do the rendering + req.done(); + } + + private void complete(Channel ctx, boolean isKeepAlive, MediaType contentType, Req req, Object result) { + + U.must(result != null, "The post-processed result cannot be null!"); + U.must(!(result instanceof Req), "The post-processed result cannot be a Req instance!"); + U.must(!(result instanceof Resp), "The post-processed result cannot be a Resp instance!"); + + if (result instanceof Throwable) { + handleError(req, (Throwable) result); + return; + } + + if (result == HttpStatus.ERROR) { + complete(ctx, isKeepAlive, contentType, req, U.rte("Handler error!")); + return; + } + + if (result == HttpStatus.NOT_FOUND) { + http.notFound(ctx, isKeepAlive, contentType, handler, req); + return; + } + + if (result == HttpStatus.ASYNC) { + return; + } + + processNormalResult(req, result); + } + + private void processNormalResult(Req req, Object result) { + + HttpUtils.resultToResponse(req, result); + + // the Req object will do the rendering + if (!req.isAsync()) { + req.done(); + } + } + +} diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpTxWrapper.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpTxWrapper.java new file mode 100644 index 0000000000..ae2423d91d --- /dev/null +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpTxWrapper.java @@ -0,0 +1,89 @@ +/*- + * #%L + * rapidoid-http-fast + * %% + * Copyright (C) 2014 - 2017 Nikolche Mihajlovski and contributors + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +package org.rapidoid.http.handler; + +import org.rapidoid.RapidoidThing; +import org.rapidoid.annotation.Authors; +import org.rapidoid.annotation.Since; +import org.rapidoid.annotation.TransactionMode; +import org.rapidoid.http.HttpUtils; +import org.rapidoid.http.HttpWrapper; +import org.rapidoid.http.Req; +import org.rapidoid.http.RespBody; +import org.rapidoid.http.impl.RespImpl; +import org.rapidoid.jpa.JPA; +import org.rapidoid.u.U; + +import java.util.concurrent.atomic.AtomicReference; + +@Authors("Nikolche Mihajlovski") +@Since("5.5.1") +public class HttpTxWrapper extends RapidoidThing implements HttpWrapper { + + private final TransactionMode txMode; + + public HttpTxWrapper(TransactionMode txMode) { + this.txMode = txMode; + } + + @Override + public Object wrap(final Req req, final HandlerInvocation invocation) { + final AtomicReference result = new AtomicReference<>(); + + U.must(txMode != null && txMode != TransactionMode.NONE); + + boolean readOnly = (txMode == TransactionMode.AUTO) + ? HttpUtils.isGetReq(req) + : txMode == TransactionMode.READ_ONLY; + + try { + JPA.transaction(new Runnable() { + @Override + public void run() { + try { + Object res = invocation.invoke(); + + if (res instanceof Throwable) { + // throw to rollback + Throwable err = (Throwable) res; + throw U.rte("Error occurred inside the transactional web handler!", err); + } + + // serialize the result into a HTTP response body, while still inside tx (see #153) + RespImpl resp = (RespImpl) req.response(); // TODO find a cleaner access + RespBody body = resp.resultToRespBody(res); + result.set(body); + + } catch (Exception e) { + // throw to rollback + throw U.rte("Error occurred inside the transactional web handler!", e); + } + } + }, readOnly); + + } catch (Throwable e) { + result.set(e); + } + + return result.get(); + } + +} diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpUnmanagedHandlerDecorator.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpUnmanagedHandlerDecorator.java new file mode 100644 index 0000000000..4bd80ac807 --- /dev/null +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpUnmanagedHandlerDecorator.java @@ -0,0 +1,89 @@ +/*- + * #%L + * rapidoid-http-fast + * %% + * Copyright (C) 2014 - 2017 Nikolche Mihajlovski and contributors + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +package org.rapidoid.http.handler; + +import org.rapidoid.annotation.Authors; +import org.rapidoid.annotation.Since; +import org.rapidoid.http.*; +import org.rapidoid.http.impl.MaybeReq; +import org.rapidoid.http.impl.ReqImpl; +import org.rapidoid.http.impl.lowlevel.HttpIO; +import org.rapidoid.log.Log; +import org.rapidoid.net.abstracts.Channel; + +@Authors("Nikolche Mihajlovski") +@Since("5.5.1") +public class HttpUnmanagedHandlerDecorator extends AbstractHttpHandlerDecorator { + + private final MediaType contentType; + + HttpUnmanagedHandlerDecorator(AbstractDecoratingHttpHandler handler, FastHttp http, MediaType contentType) { + super(handler, http); + this.contentType = contentType; + } + + @Override + public final HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req) { + Object result; + MaybeReq maybeReq = HttpUtils.maybe(req); + + ReqImpl reqq = (ReqImpl) req; + + // handle & post-process + result = handleReqAndPostProcess(ctx, isKeepAlive, req); + + // the response properties might be overwritten + int code; + MediaType ctype; + + if (req != null && reqq.hasResponseAttached()) { + Resp resp = req.response(); + ctype = resp.contentType(); + code = resp.code(); + + } else { + ctype = contentType; + code = 200; + } + + if (result == HttpStatus.NOT_FOUND) { + http.notFound(ctx, isKeepAlive, ctype, handler, req); + return HttpStatus.NOT_FOUND; + } + + if (result == HttpStatus.ASYNC) { + return HttpStatus.ASYNC; + } + + if (result instanceof Throwable) { + Throwable err = (Throwable) result; + HttpIO.INSTANCE.writeHttpResp(maybeReq, ctx, isKeepAlive, 500, MediaType.PLAIN_TEXT_UTF_8, "Internal server error!".getBytes()); + + Log.error("Error occurred during unmanaged request processing", "request", req, "error", err); + return HttpStatus.DONE; + } + + HttpIO.INSTANCE.writeHttpResp(maybeReq, ctx, isKeepAlive, code, ctype, result); + + return HttpStatus.DONE; + } + +} diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpWrappers.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpWrappers.java new file mode 100644 index 0000000000..9b701f6286 --- /dev/null +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/HttpWrappers.java @@ -0,0 +1,61 @@ +/*- + * #%L + * rapidoid-http-fast + * %% + * Copyright (C) 2014 - 2017 Nikolche Mihajlovski and contributors + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +package org.rapidoid.http.handler; + +import org.rapidoid.RapidoidThing; +import org.rapidoid.annotation.Authors; +import org.rapidoid.annotation.Since; +import org.rapidoid.annotation.TransactionMode; +import org.rapidoid.http.FastHttp; +import org.rapidoid.http.HttpWrapper; +import org.rapidoid.http.impl.RouteOptions; +import org.rapidoid.u.U; + +import java.util.List; + +@Authors("Nikolche Mihajlovski") +@Since("5.5.1") +public class HttpWrappers extends RapidoidThing { + + static HttpWrapper[] assembleWrappers(FastHttp http, RouteOptions options) { + List wrappers = U.list(getConfiguredWrappers(http, options)); + + TransactionMode txMode = U.or(options.transaction(), TransactionMode.NONE); + if (txMode != TransactionMode.NONE) { + HttpWrapper txWrapper = new HttpTxWrapper(txMode); + wrappers.add(0, txWrapper); + } + + HttpWrapper authWrapper = new HttpAuthWrapper(options.roles()); + wrappers.add(0, authWrapper); + + return U.arrayOf(HttpWrapper.class, wrappers); + } + + private static HttpWrapper[] getConfiguredWrappers(FastHttp http, RouteOptions options) { + return U.or( + options.wrappers(), // wrappers specific to the route + http.custom().wrappers(), // or wrappers for the http setup + new HttpWrapper[0] // or no wrappers + ); + } + +} diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ParamsAwareReqHandler.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ParamsAwareReqHandler.java index 1e941cc255..a8934bd801 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ParamsAwareReqHandler.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ParamsAwareReqHandler.java @@ -37,12 +37,12 @@ public class ParamsAwareReqHandler extends AbstractDecoratingHttpHandler { private final ReqHandler handler; public ParamsAwareReqHandler(FastHttp http, HttpRoutes routes, RouteOptions options, ReqHandler handler) { - super(http, routes, options); + super(http, options); this.handler = handler; } @Override - protected Object handleReq(Channel ctx, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel ctx, boolean isKeepAlive, Req req) throws Exception { return handler.execute(req); } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ParamsAwareReqRespHandler.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ParamsAwareReqRespHandler.java index d3425d44b8..ceb838d559 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ParamsAwareReqRespHandler.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ParamsAwareReqRespHandler.java @@ -37,12 +37,12 @@ public class ParamsAwareReqRespHandler extends AbstractDecoratingHttpHandler { private final ReqRespHandler handler; public ParamsAwareReqRespHandler(FastHttp http, HttpRoutes routes, RouteOptions options, ReqRespHandler handler) { - super(http, routes, options); + super(http, options); this.handler = handler; } @Override - protected Object handleReq(Channel ctx, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel ctx, boolean isKeepAlive, Req req) throws Exception { return handler.execute(req, req.response()); } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/PredefinedResponseHandler.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/PredefinedResponseHandler.java index f8e8293845..da40d8ed72 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/PredefinedResponseHandler.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/PredefinedResponseHandler.java @@ -36,12 +36,12 @@ public class PredefinedResponseHandler extends AbstractDecoratingHttpHandler { private final Object response; public PredefinedResponseHandler(FastHttp http, HttpRoutes routes, RouteOptions options, Object response) { - super(http, routes, options); + super(http, options); this.response = response; } @Override - protected Object handleReq(Channel ctx, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel ctx, boolean isKeepAlive, Req req) throws Exception { return response; } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ResourceHttpHandler.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ResourceHttpHandler.java index 1543ec7d22..57f55ce5a2 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ResourceHttpHandler.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/ResourceHttpHandler.java @@ -44,7 +44,7 @@ public ResourceHttpHandler(RouteOptions options, Res resource) { } @Override - public HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req, Object extra) { + public HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req) { byte[] bytes = resource.getBytesOrNull(); if (bytes != null) { diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/StaticHttpHandler.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/StaticHttpHandler.java index a127f84704..8d029326b7 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/StaticHttpHandler.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/StaticHttpHandler.java @@ -43,7 +43,7 @@ public StaticHttpHandler(RouteOptions options, byte[] response) { } @Override - public HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req, Object extra) { + public HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req) { HttpIO.INSTANCE.write200(HttpUtils.maybe(req), ctx, isKeepAlive, contentType, response); return HttpStatus.DONE; } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/StaticResourcesHandler.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/StaticResourcesHandler.java index 255e297f94..73152ece99 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/StaticResourcesHandler.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/StaticResourcesHandler.java @@ -48,7 +48,7 @@ public StaticResourcesHandler(Customization customization) { } @Override - public HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req, Object extra) { + public HttpStatus handle(Channel ctx, boolean isKeepAlive, Req req) { if (!HttpUtils.isGetReq(req)) return HttpStatus.NOT_FOUND; diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/HttpRoutesImpl.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/HttpRoutesImpl.java index 8ac03aa647..89f3304d20 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/HttpRoutesImpl.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/HttpRoutesImpl.java @@ -107,6 +107,7 @@ public class HttpRoutesImpl extends RapidoidThing implements HttpRoutes { private volatile boolean stable; private volatile Date lastChangedAt = new Date(); + private volatile FastHttp http; public HttpRoutesImpl(String setupName, Customization customization) { this.id = ID_GEN.incrementAndGet(); @@ -446,13 +447,15 @@ public synchronized void on(String verb, String path, HttpHandler handler) { @Override public synchronized void on(String verb, String path, ReqHandler handler) { - HttpHandler hnd = new ParamsAwareReqHandler(null, null, new RouteOptions(), handler); + U.notNull(http, "http"); + HttpHandler hnd = new ParamsAwareReqHandler(http, null, new RouteOptions(), handler); addOrRemove(true, verb, path, hnd); } @Override public synchronized void on(String verb, String path, ReqRespHandler handler) { - HttpHandler hnd = new ParamsAwareReqRespHandler(null, null, new RouteOptions(), handler); + U.notNull(http, "http"); + HttpHandler hnd = new ParamsAwareReqRespHandler(http, null, new RouteOptions(), handler); addOrRemove(true, verb, path, hnd); } @@ -693,4 +696,8 @@ public String toString() { ", setup='" + setupName + '\'' + '}'; } + + public void setHttp(FastHttp http) { + this.http = http; + } } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/TxUtil.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/RespBodyBuffer.java similarity index 61% rename from rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/TxUtil.java rename to rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/RespBodyBuffer.java index 71d922b18b..b235e6c0b5 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/handler/TxUtil.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/RespBodyBuffer.java @@ -18,30 +18,39 @@ * #L% */ -package org.rapidoid.http.handler; +package org.rapidoid.http.impl; import org.rapidoid.RapidoidThing; import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Since; -import org.rapidoid.annotation.TransactionMode; -import org.rapidoid.http.HttpUtils; -import org.rapidoid.http.Req; +import org.rapidoid.http.RespBody; +import org.rapidoid.net.abstracts.Channel; import org.rapidoid.u.U; +import java.nio.ByteBuffer; @Authors("Nikolche Mihajlovski") @Since("5.5.1") -public class TxUtil extends RapidoidThing { +public class RespBodyBuffer extends RapidoidThing implements RespBody { - static TransactionMode txModeOf(Req req, TransactionMode configuredTxMode) { - TransactionMode txMode = U.or(configuredTxMode, TransactionMode.NONE); + private final ByteBuffer buffer; - if (txMode == TransactionMode.AUTO) { - txMode = HttpUtils.isGetReq(req) ? TransactionMode.READ_ONLY : TransactionMode.READ_WRITE; - } + public RespBodyBuffer(ByteBuffer buffer) { + this.buffer = buffer; + } - return txMode; + @Override + public int length() { + return buffer.remaining(); } + @Override + public void writeTo(Channel channel) { + channel.write(buffer); + } + @Override + public String toString() { + return U.frmt("RespBodyBuffer(%s bytes)", length()); + } } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/RespBodyBytes.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/RespBodyBytes.java index 1a70c2d12a..7cf264c951 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/RespBodyBytes.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/RespBodyBytes.java @@ -24,6 +24,8 @@ import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Since; import org.rapidoid.http.RespBody; +import org.rapidoid.net.abstracts.Channel; +import org.rapidoid.u.U; @Authors("Nikolche Mihajlovski") @Since("5.5.1") @@ -36,8 +38,17 @@ public RespBodyBytes(byte[] bytes) { } @Override - public byte[] toBytes() { - return bytes; + public int length() { + return bytes.length; } + @Override + public void writeTo(Channel channel) { + channel.write(bytes); + } + + @Override + public String toString() { + return U.frmt("RespBodyBytes(%s bytes)", length()); + } } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/RespImpl.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/RespImpl.java index ae0b226d7f..7fa012e067 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/RespImpl.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/RespImpl.java @@ -509,17 +509,21 @@ public String toString() { RespBody createRespBodyFromResult() { Object result = result(); + Object body = body(); if (result instanceof RespBody) { return (RespBody) result; + } else if (body instanceof RespBody) { + return (RespBody) body; + } else if (mvc()) { byte[] bytes = ResponseRenderer.renderMvc(req, this); HttpUtils.postProcessResponse(this); // the response might have been changed, so post-process again return new RespBodyBytes(bytes); - } else if (body() != null) { - return new RespBodyBytes(Msc.toBytes(body())); + } else if (body != null) { + return new RespBodyBytes(Msc.toBytes(body)); } else if (result != null) { return resultToRespBody(result); diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/lowlevel/HttpIO.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/lowlevel/HttpIO.java index c023d59b68..f39fcd8541 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/lowlevel/HttpIO.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/lowlevel/HttpIO.java @@ -35,7 +35,6 @@ import org.rapidoid.net.abstracts.Channel; import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; import java.util.Map; @@ -98,15 +97,8 @@ public void respond(MaybeReq maybeReq, Channel channel, long connId, long handle impl.respond(maybeReq, channel, connId, handle, code, isKeepAlive, contentType, body, headers, cookies); } - public void respond(MaybeReq maybeReq, Channel channel, long connId, long handle, - int code, boolean isKeepAlive, MediaType contentType, - ByteBuffer body, Map headers, Map cookies) { - - impl.respond(maybeReq, channel, connId, handle, code, isKeepAlive, contentType, body, headers, cookies); - } - - public void closeHeaders(MaybeReq req, Buf out) { impl.closeHeaders(req, out); } + } diff --git a/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/lowlevel/LowLevelHttpIO.java b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/lowlevel/LowLevelHttpIO.java index 40a29e702b..2239672dfe 100644 --- a/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/lowlevel/LowLevelHttpIO.java +++ b/rapidoid-http-fast/src/main/java/org/rapidoid/http/impl/lowlevel/LowLevelHttpIO.java @@ -25,7 +25,6 @@ import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Since; import org.rapidoid.buffer.Buf; -import org.rapidoid.cls.Cls; import org.rapidoid.commons.Dates; import org.rapidoid.config.Conf; import org.rapidoid.config.Config; @@ -50,7 +49,6 @@ import org.rapidoid.writable.ReusableWritable; import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; @@ -395,7 +393,7 @@ void writeBadRequest(Channel channel) { } void respond(final MaybeReq maybeReq, final Channel channel, long connId, long handle, - final int code, final boolean isKeepAlive, final MediaType contentType, final Object body, + final int code, final boolean isKeepAlive, final MediaType contentType, final RespBody body, final Map headers, final Map cookies) { final ReqImpl req = (ReqImpl) maybeReq.getReqOrNull(); @@ -422,8 +420,7 @@ void respond(final MaybeReq maybeReq, final Channel channel, long connId, long h @Override public String toString() { - String bb = (body instanceof byte[]) ? new String((byte[]) body) : U.str(body); - return U.str(U.join(":", "#" + id, channel, code, bb, isKeepAlive, contentType)); + return U.str(U.join(":", "#" + id, channel, code, body, isKeepAlive, contentType)); } @Override @@ -466,23 +463,9 @@ public boolean resumeAsync() { } else { - if (body instanceof RespBody) { - byte[] bytes = ((RespBody) body).toBytes(); - - writeContentLengthHeader(channel, bytes.length); - closeHeaders(maybeReq, output); - channel.write(bytes); - - } else if (body instanceof ByteBuffer) { - ByteBuffer buf = (ByteBuffer) body; - - writeContentLengthHeader(channel, buf.remaining()); - closeHeaders(maybeReq, output); - channel.write(buf); - - } else { - throw U.rte("Invalid response body type: %s", Cls.of(body)); - } + writeContentLengthHeader(channel, body.length()); + closeHeaders(maybeReq, output); + body.writeTo(channel); if (req != null) { req.completed(true); diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/MethodReqHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/MethodReqHandler.java index 67dfc288de..25a1f2b507 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/MethodReqHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/MethodReqHandler.java @@ -47,7 +47,7 @@ public MethodReqHandler(FastHttp http, HttpRoutes routes, RouteOptions options, } @Override - protected Object handleReq(Channel channel, boolean isKeepAlive, Req req, Object extra) throws Throwable { + protected Object handleReq(Channel channel, boolean isKeepAlive, Req req) throws Throwable { Object[] args = args(req); Object result = Cls.invokeRethrowing(method, instance, args); diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/FiveParamLambdaHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/FiveParamLambdaHandler.java index b994edd842..d248bbfef3 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/FiveParamLambdaHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/FiveParamLambdaHandler.java @@ -43,7 +43,7 @@ public FiveParamLambdaHandler(FastHttp http, HttpRoutes routes, RouteOptions opt } @Override - protected Object handleReq(Channel channel, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel channel, boolean isKeepAlive, Req req) throws Exception { return lambda.execute(arg(req, 0), arg(req, 1), arg(req, 2), arg(req, 3), arg(req, 4)); } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/FourParamLambdaHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/FourParamLambdaHandler.java index e5e4b368a5..779226c2ac 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/FourParamLambdaHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/FourParamLambdaHandler.java @@ -43,7 +43,7 @@ public FourParamLambdaHandler(FastHttp http, HttpRoutes routes, RouteOptions opt } @Override - protected Object handleReq(Channel channel, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel channel, boolean isKeepAlive, Req req) throws Exception { return lambda.execute(arg(req, 0), arg(req, 1), arg(req, 2), arg(req, 3)); } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/NParamMethodHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/NParamMethodHandler.java index a296783725..fde2a54dce 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/NParamMethodHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/NParamMethodHandler.java @@ -48,7 +48,7 @@ public abstract class NParamMethodHandler extends AbstractDecoratingHttpHandler private final String paramsAsStr; public NParamMethodHandler(FastHttp http, HttpRoutes routes, RouteOptions options, Method method, NParamLambda lambda) { - super(http, routes, options); + super(http, options); this.method = method; Class[] paramTypes = method.getParameterTypes(); diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/OneParamLambdaHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/OneParamLambdaHandler.java index ff6a287be7..7d9e0c387c 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/OneParamLambdaHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/OneParamLambdaHandler.java @@ -43,7 +43,7 @@ public OneParamLambdaHandler(FastHttp http, HttpRoutes routes, RouteOptions opti } @Override - protected Object handleReq(Channel channel, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel channel, boolean isKeepAlive, Req req) throws Exception { return lambda.execute(arg(req, 0)); } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/SevenParamLambdaHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/SevenParamLambdaHandler.java index 2353e0b21d..f185fed77f 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/SevenParamLambdaHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/SevenParamLambdaHandler.java @@ -43,7 +43,7 @@ public SevenParamLambdaHandler(FastHttp http, HttpRoutes routes, RouteOptions op } @Override - protected Object handleReq(Channel channel, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel channel, boolean isKeepAlive, Req req) throws Exception { return lambda.execute(arg(req, 0), arg(req, 1), arg(req, 2), arg(req, 3), arg(req, 4), arg(req, 5), arg(req, 6)); } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/SixParamLambdaHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/SixParamLambdaHandler.java index 64d15e1647..cd0b6b200c 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/SixParamLambdaHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/SixParamLambdaHandler.java @@ -43,7 +43,7 @@ public SixParamLambdaHandler(FastHttp http, HttpRoutes routes, RouteOptions opti } @Override - protected Object handleReq(Channel channel, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel channel, boolean isKeepAlive, Req req) throws Exception { return lambda.execute(arg(req, 0), arg(req, 1), arg(req, 2), arg(req, 3), arg(req, 4), arg(req, 5)); } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/ThreeParamLambdaHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/ThreeParamLambdaHandler.java index 352dcbcdd4..5e1762fb97 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/ThreeParamLambdaHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/ThreeParamLambdaHandler.java @@ -43,7 +43,7 @@ public ThreeParamLambdaHandler(FastHttp http, HttpRoutes routes, RouteOptions op } @Override - protected Object handleReq(Channel channel, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel channel, boolean isKeepAlive, Req req) throws Exception { return lambda.execute(arg(req, 0), arg(req, 1), arg(req, 2)); } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/TwoParamLambdaHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/TwoParamLambdaHandler.java index 940900f6b7..6d0cbb004a 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/TwoParamLambdaHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/lambda/TwoParamLambdaHandler.java @@ -43,7 +43,7 @@ public TwoParamLambdaHandler(FastHttp http, HttpRoutes routes, RouteOptions opti } @Override - protected Object handleReq(Channel channel, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel channel, boolean isKeepAlive, Req req) throws Exception { return lambda.execute(arg(req, 0), arg(req, 1)); } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/CallableHttpHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/CallableHttpHandler.java index 20075def93..7b234ec58f 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/CallableHttpHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/CallableHttpHandler.java @@ -39,12 +39,12 @@ public class CallableHttpHandler extends AbstractDecoratingHttpHandler { private final Callable handler; public CallableHttpHandler(FastHttp http, HttpRoutes routes, RouteOptions options, Callable handler) { - super(http, routes, options); + super(http, options); this.handler = handler; } @Override - protected Object handleReq(Channel ctx, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel ctx, boolean isKeepAlive, Req req) throws Exception { return handler.call(); } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareReqHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareReqHandler.java index 9a8e0c4d6d..3f78bc3a3b 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareReqHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareReqHandler.java @@ -39,12 +39,12 @@ public class DelegatingParamsAwareReqHandler extends AbstractDecoratingHttpHandl private final OneParamLambda handler; public DelegatingParamsAwareReqHandler(FastHttp http, HttpRoutes routes, RouteOptions options, OneParamLambda handler) { - super(http, routes, options); + super(http, options); this.handler = U.cast(handler); } @Override - protected Object handleReq(Channel channel, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel channel, boolean isKeepAlive, Req req) throws Exception { return handler.execute(req); } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareReqRespHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareReqRespHandler.java index 42f64129cd..70599fd336 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareReqRespHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareReqRespHandler.java @@ -40,12 +40,12 @@ public class DelegatingParamsAwareReqRespHandler extends AbstractDecoratingHttpH private final TwoParamLambda handler; public DelegatingParamsAwareReqRespHandler(FastHttp http, HttpRoutes routes, RouteOptions options, TwoParamLambda handler) { - super(http, routes, options); + super(http, options); this.handler = U.cast(handler); } @Override - protected Object handleReq(Channel channel, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel channel, boolean isKeepAlive, Req req) throws Exception { return handler.execute(req, req.response()); } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareRespHandler.java b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareRespHandler.java index 2fb8e6e8ef..8d6d46aa63 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareRespHandler.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/http/handler/optimized/DelegatingParamsAwareRespHandler.java @@ -40,12 +40,12 @@ public class DelegatingParamsAwareRespHandler extends AbstractDecoratingHttpHand private final OneParamLambda handler; public DelegatingParamsAwareRespHandler(FastHttp http, HttpRoutes routes, RouteOptions options, OneParamLambda handler) { - super(http, routes, options); + super(http, options); this.handler = U.cast(handler); } @Override - protected Object handleReq(Channel channel, boolean isKeepAlive, Req req, Object extra) throws Exception { + protected Object handleReq(Channel channel, boolean isKeepAlive, Req req) throws Exception { return handler.execute(req.response()); } diff --git a/rapidoid-integration-tests/src/test/java/org/rapidoid/docs/DocTest.java b/rapidoid-integration-tests/src/test/java/org/rapidoid/docs/DocTest.java index 9082340771..c46eea5c84 100644 --- a/rapidoid-integration-tests/src/test/java/org/rapidoid/docs/DocTest.java +++ b/rapidoid-integration-tests/src/test/java/org/rapidoid/docs/DocTest.java @@ -46,12 +46,12 @@ */ public abstract class DocTest extends IsolatedIntegrationTest { - private static final String LICENSE_HEADER = "(?sm)\\Q\n/*\n * #" + "%L\\E(.*?)\\Q * #L%\n */\n\\E"; + private static final String LICENSE_HEADER = "(?sm)(^|\\n)\\Q/*-\n * #" + "%L\\E(.*?)\\Q * #L%\n */\n\\E"; private final AtomicInteger order = new AtomicInteger(); @Test - public void docs() throws Exception { + public void docs() { if (this instanceof BlankTest) { return; // not a real test } @@ -120,6 +120,8 @@ private String cleanCode(String code, String ext) { code = code.replaceAll(LICENSE_HEADER, ""); } + code = code.replaceAll("(?s)\\n{3,}", "\n\n"); + return code.trim(); } diff --git a/rapidoid-integration-tests/src/test/java/org/rapidoid/http/HttpClientPipeliningTest.java b/rapidoid-integration-tests/src/test/java/org/rapidoid/http/HttpClientPipeliningTest.java index 366ac79fdc..480ff19a76 100644 --- a/rapidoid-integration-tests/src/test/java/org/rapidoid/http/HttpClientPipeliningTest.java +++ b/rapidoid-integration-tests/src/test/java/org/rapidoid/http/HttpClientPipeliningTest.java @@ -41,16 +41,16 @@ @Since("5.5.0") public class HttpClientPipeliningTest extends IsolatedIntegrationTest { - protected static final byte[] REQ = "GET /hello H\r\nasf:asf\r\n\r\n".getBytes(); + private static final byte[] REQ = "GET /hi H\r\nasf:asf\r\n\r\n".getBytes(); - protected static final byte[] RESP = "Hello".getBytes(); + private static final byte[] RESP = "Hello".getBytes(); @Test public void testHttpServerPipelining() { Conf.NET.set("workers", 1); - On.get("/hello").plain(() -> "Hello"); + On.get("/hi").plain(() -> "Hello"); final int connections = 100; final int pipelining = 10; diff --git a/rapidoid-integration-tests/src/test/java/org/rapidoid/http/HttpClientTest.java b/rapidoid-integration-tests/src/test/java/org/rapidoid/http/HttpClientTest.java index bbba835f85..8171f60863 100644 --- a/rapidoid-integration-tests/src/test/java/org/rapidoid/http/HttpClientTest.java +++ b/rapidoid-integration-tests/src/test/java/org/rapidoid/http/HttpClientTest.java @@ -39,7 +39,7 @@ public class HttpClientTest extends IsolatedIntegrationTest { private static final String GET_RAPIDOID_ORG = "GET / HTTP/1.1\nHost: www.rapidoid.org\n\n"; - protected static final String SIMPLE_RESPONSE = "AbC"; + private static final String SIMPLE_RESPONSE = "AbC"; @Test public void testHttpClientOnLocalServer() { @@ -52,7 +52,7 @@ public void testHttpClientOnLocalServer() { HttpClientCallback hcb = new HttpClientBodyCallback(cb); - org.rapidoid.http.client.HttpClient client = new org.rapidoid.http.client.HttpClient(); + HttpClient client = new HttpClient(); int count1 = 1000; for (int i = 0; i < count1; i++) { @@ -77,7 +77,7 @@ public void testHttpClientOnRealWebSites() { HttpClientCallback hcb = new HttpClientBodyCallback(cb); - org.rapidoid.http.client.HttpClient client = new HttpClient(); + HttpClient client = new HttpClient(); int count = 3; for (int i = 0; i < count; i++) { diff --git a/rapidoid-integration-tests/src/test/java/org/rapidoid/http/IsolatedIntegrationTest.java b/rapidoid-integration-tests/src/test/java/org/rapidoid/http/IsolatedIntegrationTest.java index 1ce14e05b9..047f5986ee 100644 --- a/rapidoid-integration-tests/src/test/java/org/rapidoid/http/IsolatedIntegrationTest.java +++ b/rapidoid-integration-tests/src/test/java/org/rapidoid/http/IsolatedIntegrationTest.java @@ -112,6 +112,9 @@ public void openContext() { @After public void closeContext() { + Jobs.shutdownNow(); + U.sleep(200); + if (Admin.setup().isRunning()) { if (Admin.setup().port() == On.setup().port()) { Admin.setup().reset(); diff --git a/rapidoid-jpa/src/main/java/org/rapidoid/jpa/JPA.java b/rapidoid-jpa/src/main/java/org/rapidoid/jpa/JPA.java index 7887e655fb..68776f9e99 100644 --- a/rapidoid-jpa/src/main/java/org/rapidoid/jpa/JPA.java +++ b/rapidoid-jpa/src/main/java/org/rapidoid/jpa/JPA.java @@ -207,6 +207,7 @@ public static void transaction(Runnable action) { transaction(action, false); } + // FIXME replace Runnable with Executable public static void transaction(Runnable action, boolean readOnly) { Ctx ctx = Ctxs.get(); boolean newContext = ctx == null;