Skip to content

Commit

Permalink
Enabled async request handling by default.
Browse files Browse the repository at this point in the history
  • Loading branch information
nmihajlovski committed Sep 28, 2015
1 parent c644a31 commit 227fc98
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 58 deletions.
53 changes: 10 additions & 43 deletions rapidoid-app/src/main/java/org/rapidoid/app/AppHandler.java
Expand Up @@ -38,9 +38,6 @@
import org.rapidoid.http.Handler; import org.rapidoid.http.Handler;
import org.rapidoid.http.HttpExchange; import org.rapidoid.http.HttpExchange;
import org.rapidoid.http.HttpExchangeImpl; import org.rapidoid.http.HttpExchangeImpl;
import org.rapidoid.http.HttpExchangeInternals;
import org.rapidoid.http.HttpNotFoundException;
import org.rapidoid.io.CustomizableClassLoader;
import org.rapidoid.io.Res; import org.rapidoid.io.Res;
import org.rapidoid.jackson.JSON; import org.rapidoid.jackson.JSON;
import org.rapidoid.plugins.templates.Templates; import org.rapidoid.plugins.templates.Templates;
Expand All @@ -59,49 +56,12 @@ public class AppHandler implements Handler {


private static final Pattern DIRECTIVE = Pattern.compile("\\s*\\Q<!--#\\E\\s*(\\{.+\\})\\s*\\Q-->\\E\\s*"); private static final Pattern DIRECTIVE = Pattern.compile("\\s*\\Q<!--#\\E\\s*(\\{.+\\})\\s*\\Q-->\\E\\s*");


private CustomizableClassLoader classLoader;

public AppHandler() {
this(null);
}

public AppHandler(CustomizableClassLoader classLoader) {
this.classLoader = classLoader;
}

@Override @Override
public Object handle(final HttpExchange x) throws Exception { public Object handle(final HttpExchange x) throws Exception {

return dispatch((HttpExchangeImpl) x);
HttpExchangeInternals xi = (HttpExchangeInternals) x;
xi.setClassLoader(classLoader);

Object result;

try {
result = processReq(x);
} catch (Exception e) {
if (UTILS.rootCause(e) instanceof HttpNotFoundException) {
throw U.rte(e);
} else {
// Log.error("Exception occured while processing request!", UTILS.rootCause(e));
throw U.rte(e);
}
}

return result;
}

public Object processReq(HttpExchange x) {
Object result = dispatch((HttpExchangeImpl) x);

if (result != null) {
return result;
} else {
throw x.notFound();
}
} }


public Object dispatch(HttpExchangeImpl x) { private Object dispatch(HttpExchangeImpl x) {


// static files // static files


Expand Down Expand Up @@ -140,7 +100,7 @@ public Object dispatch(HttpExchangeImpl x) {


Map<String, Object> config = null; Map<String, Object> config = null;


// dispatch REST services or views (as POJO methods) // dispatch REST services or PAGES (as POJO methods)


if (result == null) { if (result == null) {
DispatchResult dres = doDispatch(dispatcher, new WebReq(x)); DispatchResult dres = doDispatch(dispatcher, new WebReq(x));
Expand Down Expand Up @@ -189,6 +149,12 @@ private void bindInputs(HttpExchangeImpl x) {
public static Object view(HttpExchange x, Object result, boolean hasEvent, Map<String, Object> config) { public static Object view(HttpExchange x, Object result, boolean hasEvent, Map<String, Object> config) {
// serve dynamic pages from file templates // serve dynamic pages from file templates


// FIXME enable
// if (Cls.bool(config.get("raw"))) {
// x.html();
// return result;
// }

if (serveDynamicPage(x, result, hasEvent, config)) { if (serveDynamicPage(x, result, hasEvent, config)) {
return x; return x;
} }
Expand Down Expand Up @@ -236,6 +202,7 @@ public static boolean serveDynamicPage(HttpExchange x, Object result, boolean ha
model.put("embedded", hasEvent || x.param("_embedded", null) != null); model.put("embedded", hasEvent || x.param("_embedded", null) != null);


// the @Page configuration overrides the previous // the @Page configuration overrides the previous

if (config != null) { if (config != null) {
model.putAll(config); model.putAll(config);
} }
Expand Down
Expand Up @@ -27,6 +27,7 @@
import org.rapidoid.annotation.Since; import org.rapidoid.annotation.Since;
import org.rapidoid.http.Handler; import org.rapidoid.http.Handler;
import org.rapidoid.http.HttpExchange; import org.rapidoid.http.HttpExchange;
import org.rapidoid.http.HttpExchangeImpl;
import org.rapidoid.io.CustomizableClassLoader; import org.rapidoid.io.CustomizableClassLoader;
import org.rapidoid.io.IO; import org.rapidoid.io.IO;
import org.rapidoid.lambda.Mapper; import org.rapidoid.lambda.Mapper;
Expand Down Expand Up @@ -62,7 +63,9 @@ public Object handle(HttpExchange x) throws Exception {
CustomizableClassLoader classLoader = new CustomizableClassLoader(this, CustomizableClassLoader classLoader = new CustomizableClassLoader(this,
(Predicate<String>) Predicate.ALWAYS_TRUE, true); (Predicate<String>) Predicate.ALWAYS_TRUE, true);


AppHandler handler = new AppHandler(classLoader); ((HttpExchangeImpl) x).setClassLoader(classLoader);

AppHandler handler = new AppHandler();
return handler.handle(x); return handler.handle(x);
} }


Expand Down
2 changes: 1 addition & 1 deletion rapidoid-app/src/main/java/org/rapidoid/app/Apps.java
Expand Up @@ -86,7 +86,7 @@ public static HTTPServer serve(WebApp app, String[] args, Object... config) {
OAuth.register(app); OAuth.register(app);
HttpBuiltins.register(app); HttpBuiltins.register(app);


app.getRouter().serve(new AppHandler()); app.getRouter().serve(new AsyncAppHandler());


return server.start(); return server.start();
} }
Expand Down
58 changes: 58 additions & 0 deletions rapidoid-app/src/main/java/org/rapidoid/app/AsyncAppHandler.java
@@ -0,0 +1,58 @@
package org.rapidoid.app;

/*
* #%L
* rapidoid-app
* %%
* Copyright (C) 2014 - 2015 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%
*/

import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.http.Handler;
import org.rapidoid.http.HttpExchange;
import org.rapidoid.http.HttpExchangeInternals;
import org.rapidoid.io.CustomizableClassLoader;
import org.rapidoid.job.Jobs;

@Authors("Nikolche Mihajlovski")
@Since("2.0.0")
public class AsyncAppHandler implements Handler {

private final CustomizableClassLoader classLoader;

private final Handler handler;

public AsyncAppHandler() {
this(null);
}

public AsyncAppHandler(CustomizableClassLoader classLoader) {
this.classLoader = classLoader;
this.handler = new AppHandler();
}

@Override
public Object handle(final HttpExchange x) throws Exception {
HttpExchangeInternals xi = (HttpExchangeInternals) x;
xi.setClassLoader(classLoader);

Jobs.execute(x.asAsyncJob(handler));

return x;
}

}
Expand Up @@ -54,7 +54,7 @@ public ByteBuffer call() {
} }


public BufGroup(int factor) { public BufGroup(int factor) {
this(factor, false); this(factor, true);
} }


public Buf newBuf(String name) { public Buf newBuf(String name) {
Expand Down
Expand Up @@ -5,7 +5,7 @@


/* /*
* #%L * #%L
* rapidoid-http * rapidoid-http-api
* %% * %%
* Copyright (C) 2014 - 2015 Nikolche Mihajlovski and contributors * Copyright (C) 2014 - 2015 Nikolche Mihajlovski and contributors
* %% * %%
Expand Down
Expand Up @@ -35,7 +35,7 @@


@Authors("Nikolche Mihajlovski") @Authors("Nikolche Mihajlovski")
@Since("2.0.0") @Since("2.0.0")
public interface HttpExchange { public interface HttpExchange extends Runnable {


/* REQUEST METHODS: */ /* REQUEST METHODS: */


Expand Down Expand Up @@ -266,4 +266,6 @@ HttpExchange response(@P("httpResponseCode") int httpResponseCode, @P("response"


Object model(); Object model();


Runnable asAsyncJob(Handler handler);

} }
Expand Up @@ -149,6 +149,7 @@ public class HttpExchangeImpl extends DefaultExchange<HttpExchangeImpl> implemen


private ClassLoader classLoader; private ClassLoader classLoader;
private SessionStore sessionStore; private SessionStore sessionStore;
private Handler handler;


private final Callable<Map<String, Object>> lazyData = new Callable<Map<String, Object>>() { private final Callable<Map<String, Object>> lazyData = new Callable<Map<String, Object>>() {
@Override @Override
Expand Down Expand Up @@ -232,6 +233,7 @@ public synchronized void reset() {


classLoader = null; classLoader = null;
sessionStore = null; sessionStore = null;
handler = null;


session = null; session = null;
cookiepack = null; cookiepack = null;
Expand Down Expand Up @@ -756,6 +758,7 @@ public synchronized HttpExchange sendFile(File file) {
U.must(file.exists()); U.must(file.exists());
setContentType(MediaType.getByFileName(file.getAbsolutePath())); setContentType(MediaType.getByFileName(file.getAbsolutePath()));
write(file); write(file);
done();
return this; return this;
} }


Expand All @@ -764,13 +767,15 @@ public synchronized HttpExchange sendFile(Res resource) {
U.must(resource.exists()); U.must(resource.exists());
setContentType(MediaType.getByFileName(resource.getShortName())); setContentType(MediaType.getByFileName(resource.getShortName()));
write(resource.getBytes()); write(resource.getBytes());
done();
return this; return this;
} }


@Override @Override
public synchronized HttpExchange sendFile(MediaType mediaType, byte[] bytes) { public synchronized HttpExchange sendFile(MediaType mediaType, byte[] bytes) {
setContentType(mediaType); setContentType(mediaType);
write(bytes); write(bytes);
done();
return this; return this;
} }


Expand Down Expand Up @@ -1315,7 +1320,8 @@ public HttpExchange renderPage(Object model) {
} }


pageTemplate().render(this.outputStream(), model, model()); pageTemplate().render(this.outputStream(), model, model());
return this;
return done();
} }


@Override @Override
Expand Down Expand Up @@ -1384,7 +1390,7 @@ public synchronized HttpExchangeImpl setHome(String home) {
return this; return this;
} }


public String renderState() { public synchronized String renderState() {
try { try {
return JSON.jacksonStringify(serializeLocals()); return JSON.jacksonStringify(serializeLocals());
} catch (Exception e) { } catch (Exception e) {
Expand All @@ -1393,4 +1399,31 @@ public String renderState() {
} }
} }


@Override
public synchronized Runnable asAsyncJob(Handler handler) {
this.handler = handler;
return this.async();
}

@Override
public synchronized void run() {
runInAsyncContext();
}

private void runInAsyncContext() {
Object result;

try {
U.notNull(handler, "async handler");
result = handler.handle(this);
} catch (Throwable e) {
HttpProtocol.handleError(this, e);
return;
}

if (result != null && !(result instanceof HttpExchange)) {
HttpProtocol.processResponse(this, result);
}
}

} }
12 changes: 8 additions & 4 deletions rapidoid-http/src/main/java/org/rapidoid/http/HttpProtocol.java
Expand Up @@ -219,23 +219,27 @@ public static void handleError(HttpExchangeImpl x, Throwable e) {
x.error(e); x.error(e);
x.completeResponse(); x.completeResponse();
} }

x.done();
} }


public static void processResponse(HttpExchange xch, Object res) { public static void processResponse(HttpExchange xch, Object res) {


HttpExchangeImpl x = (HttpExchangeImpl) xch; HttpExchangeImpl x = (HttpExchangeImpl) xch;


if (x.isLowLevelProcessing() || x.isAsync() || res == xch) { if (x.isLowLevelProcessing() || res instanceof HttpExchange) {
return; return;
} }


if (res != null) { if (res != null) {
x.result(res); x.result(res);
} else { } else {
if (!x.hasContentType()) { if (!x.isAsync()) {
x.html(); if (!x.hasContentType()) {
x.html();
}
throw x.notFound();
} }
throw x.notFound();
} }
} }


Expand Down
5 changes: 3 additions & 2 deletions rapidoid-http/src/test/java/org/rapidoid/webapp/JobsTest.java
@@ -1,6 +1,7 @@
package org.rapidoid.webapp; package org.rapidoid.webapp;


import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;


import org.junit.Test; import org.junit.Test;
Expand Down Expand Up @@ -55,13 +56,13 @@ public void run() {
Ctxs.ctx().setApp(app); Ctxs.ctx().setApp(app);
ensureProperContext(user, app); ensureProperContext(user, app);


ScheduledFuture<?> future = Jobs.execute(new Runnable() { ScheduledFuture<?> future = Jobs.schedule(new Runnable() {
@Override @Override
public void run() { public void run() {
ensureProperContext(user, app); ensureProperContext(user, app);
counter.incrementAndGet(); counter.incrementAndGet();
} }
}); }, 100, TimeUnit.MILLISECONDS);


try { try {
future.get(); future.get();
Expand Down
4 changes: 2 additions & 2 deletions rapidoid-main/src/main/java/org/rapidoid/main/AppTool.java
Expand Up @@ -25,7 +25,7 @@


import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since; import org.rapidoid.annotation.Since;
import org.rapidoid.app.AppHandler; import org.rapidoid.app.AsyncAppHandler;
import org.rapidoid.config.Conf; import org.rapidoid.config.Conf;
import org.rapidoid.io.Res; import org.rapidoid.io.Res;
import org.rapidoid.jackson.YAML; import org.rapidoid.jackson.YAML;
Expand All @@ -44,7 +44,7 @@ public class AppTool {


public static WebApp createRootApp() { public static WebApp createRootApp() {
RootWebApp app = WebAppGroup.root(); RootWebApp app = WebAppGroup.root();
app.getRouter().generic(new AppHandler()); app.getRouter().generic(new AsyncAppHandler());


String menufile = "menu.yaml"; String menufile = "menu.yaml";
String firstMenuFile = Conf.configPath() + "/" + menufile; String firstMenuFile = Conf.configPath() + "/" + menufile;
Expand Down

0 comments on commit 227fc98

Please sign in to comment.