Skip to content

Commit

Permalink
Refactored the event dispatching mechanism.
Browse files Browse the repository at this point in the history
  • Loading branch information
nmihajlovski committed Aug 7, 2015
1 parent 006176a commit 5a890db
Show file tree
Hide file tree
Showing 22 changed files with 218 additions and 146 deletions.
15 changes: 10 additions & 5 deletions assets-ng/emit.js
Expand Up @@ -34,9 +34,9 @@ Rapidoid.initializer(function($scope) {
}

$.post(window.location.href, {
event : eventId,
args : eventArgs,
inputs : JSON.stringify(inputs),
_event : eventId,
_args : eventArgs,
_inputs : JSON.stringify(inputs),
__state : window.__state
}).done(function(data) {
if (data._redirect_) {
Expand Down Expand Up @@ -64,17 +64,22 @@ Rapidoid.initializer(function($scope) {
}
}
} else {
if (data._sel_ === undefined) {
swal("Application error!", "The command couldn't be executed!", "error");
return;
}

for ( var sel in data._sel_) {
if (sel == 'body') {
$scope.ajaxBodyContent = data._sel_[sel];
$scope.$apply();
} else {
alert('Selector not supported: ' + sel);
swal('Selector not supported: ' + sel);
}
}
}
}).fail(function(data) {
swal("Communication error", "Couldn't connect to the server!", "error");
swal("Communication error!", "Couldn't connect to the server!", "error");
console.log(data);
});
};
Expand Down
9 changes: 3 additions & 6 deletions rapidoid-app/src/main/java/org/rapidoid/app/AppClasses.java
Expand Up @@ -28,7 +28,6 @@
import org.rapidoid.annotation.Since;
import org.rapidoid.annotation.Web;
import org.rapidoid.beany.Metadata;
import org.rapidoid.dispatch.PojoDispatcher;
import org.rapidoid.util.U;

@Authors("Nikolche Mihajlovski")
Expand All @@ -37,12 +36,10 @@ public class AppClasses {

public final Class<?> main;
public final Map<String, Class<?>> components;
public final PojoDispatcher dispatcher;

public AppClasses(Class<?> main, Map<String, Class<?>> services) {
public AppClasses(Class<?> main, Map<String, Class<?>> components) {
this.main = main;
this.components = services;
this.dispatcher = new WebPojoDispatcher(services);
this.components = components;
}

public static AppClasses from(Class<?>... classes) {
Expand All @@ -69,7 +66,7 @@ public static AppClasses from(Collection<Class<?>> classes) {

@Override
public String toString() {
return "AppClasses [main=" + main + ", services=" + components + ", dispatcher=" + dispatcher + "]";
return "AppClasses [main=" + main + ", components=" + components + "]";
}

}
199 changes: 133 additions & 66 deletions rapidoid-app/src/main/java/org/rapidoid/app/AppHandler.java
Expand Up @@ -21,24 +21,32 @@
*/

import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.dispatch.DispatchResult;
import org.rapidoid.dispatch.PojoDispatchException;
import org.rapidoid.dispatch.PojoDispatcher;
import org.rapidoid.dispatch.PojoHandlerNotFoundException;
import org.rapidoid.http.Handler;
import org.rapidoid.http.HttpExchange;
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.jackson.JSON;
import org.rapidoid.log.Log;
import org.rapidoid.plugins.templates.Templates;
import org.rapidoid.util.Constants;
import org.rapidoid.util.U;
import org.rapidoid.util.UTILS;
import org.rapidoid.webapp.AppCtx;
import org.rapidoid.webapp.WebApp;
import org.rapidoid.webapp.WebReq;

@Authors("Nikolche Mihajlovski")
@Since("2.0.0")
Expand Down Expand Up @@ -80,11 +88,7 @@ public Object handle(final HttpExchange x) throws Exception {
}

public Object processReq(HttpExchange x) {
HttpExchangeInternals xi = (HttpExchangeInternals) x;

final AppClasses appCls = Apps.getAppClasses(x, xi.getClassLoader());

Object result = dispatch(x, appCls);
Object result = dispatch((HttpExchangeImpl) x);

if (result != null) {
return result;
Expand All @@ -93,51 +97,80 @@ public Object processReq(HttpExchange x) {
}
}

public Object dispatch(HttpExchange x, AppClasses appCls) {
HttpExchangeInternals xi = (HttpExchangeInternals) x;
@SuppressWarnings("unchecked")
public Object dispatch(HttpExchangeImpl x) {

// static files

if (x.isGetReq() && x.serveStaticFile()) {
return x;
}

// dispatch REST services or views (as POJO methods)
WebApp app = AppCtx.app();
PojoDispatcher dispatcher = app.getDispatcher();

Object result = null;
DispatchResult dispatchResult = null;
boolean hasEvent = false;

if (appCls.dispatcher != null) {
try {
dispatchResult = appCls.dispatcher.dispatch(new WebReq(x));
result = dispatchResult.getResult();
} catch (PojoHandlerNotFoundException e) {
// / just ignore, will try to dispatch a page next...
} catch (PojoDispatchException e) {
return x.error(e);
// Prepare GUI state

x.loadState();

// if an event was emitted, process it

if (x.isPostReq()) {
String event = x.posted("_event", null);
if (!U.isEmpty(event)) {
hasEvent = true;

String evArgs = x.posted("_args", null);
Object[] args = evArgs != null ? JSON.jacksonParse(evArgs, Object[].class) : Constants.EMPTY_ARRAY;

String inputstr = x.posted("_inputs");
U.notNull(inputstr, "inputs");
Map<String, Object> inputs = JSON.parse(inputstr, Map.class);

// bind inputs
for (Entry<String, Object> e : inputs.entrySet()) {
String inputId = e.getKey();
Object value = e.getValue();

x.locals().put(inputId, UTILS.serializable(value + ":"));
}

DispatchResult dispatchResult = doDispatch(x, dispatcher);
U.must(dispatchResult != null && !dispatchResult.isService());

// in case of binding or validation errors
if (x.hasErrors()) {
x.json();
return U.map("!errors", x.errors());
}
}
}

if (dispatchResult != null && dispatchResult.isService()) {
return result;
}
// FIXME: call the command handler

// Prepare GUI state
// dispatch REST services or views (as POJO methods)

xi.loadState();
DispatchResult dispatchResult = doDispatch(x, dispatcher);

// Instantiate main app object (if possible)
Object result = null;
if (dispatchResult != null) {
result = dispatchResult.getResult();

Object app = Apps.instantiate(appCls.main, x);
if (dispatchResult.isService()) {
return result;
}
}

if (result == null) {
// try generic app screens
result = genericScreen();
}

// serve pages from file templates
// serve dynamic pages from file templates

if (smartServeFromFile(x, "dynamic/" + x.resourceName() + ".html", app, result)) {
if (serveDynamicPage(x, result, hasEvent)) {
return x;
}

Expand All @@ -148,55 +181,89 @@ public Object dispatch(HttpExchange x, AppClasses appCls) {
throw x.notFound();
}

public static boolean smartServeFromFile(HttpExchange x, String filename, Object app, Object result) {
private DispatchResult doDispatch(HttpExchange x, PojoDispatcher dispatcher) {
DispatchResult dispatchResult = null;

if (dispatcher != null) {
try {
dispatchResult = dispatcher.dispatch(new WebReq(x));
} catch (PojoHandlerNotFoundException e) {
// / just ignore, will try to dispatch a page next...
} catch (PojoDispatchException e) {
throw U.rte("Dispatch error!", e);
}
}
return dispatchResult;
}

public boolean serveDynamicPage(HttpExchangeImpl x, Object result, boolean hasEvent) {
String filename = "dynamic/" + x.resourceName() + ".html";
Res resource = Res.from(filename);

Map<String, Object> model;
if (resource.exists()) {
x.html();

String template = U.safe(resource.getContent());

Map<String, Object> model = U.map("result", result);

String[] contentParts = template.split("\n", 2);
if (contentParts.length == 2) {
String line = contentParts[0];

Matcher m = DIRECTIVE.matcher(line);
if (m.matches()) {
String directives = m.group(1);
for (String directive : directives.split(",")) {
directive = directive.trim();
if (!U.isEmpty(directive)) {
if (directive.startsWith("+")) {
model.put(directive.substring(1), true);
} else if (directive.startsWith("-")) {
model.put(directive.substring(1), false);
} else {
Log.warn("Unknown directive!", "directive", directive, "file", filename);
}
}
}

template = contentParts[1]; // without the directive
}
}
model = pageModel(filename, result, resource);
} else if (result != null) {
model = U.map("result", result, "content", result, "navbar", true);
} else {
return false;
}

String content = Templates.fromString(template).render(model, result);
model.put("content", content); // content without the directive
model.put("embedded", hasEvent || x.param("embedded", null) != null);

if (hasEvent) {
serveEventResponse(x, x.renderPageToHTML(model));
} else {
x.renderPage(model);
}

return true;
return true;
}

} else if (result != null) {
x.html();
Map<String, Object> model = U.map("result", result, "content", result, "navbar", true);
x.renderPage(model);
return true;
private void serveEventResponse(HttpExchangeImpl x, String html) {
x.startResponse(200);
x.json();

if (x.redirectUrl() != null) {
x.writeJSON(U.map("_redirect_", x.redirectUrl()));
} else {
return false;
Map<String, String> sel = U.map("body", html);
x.writeJSON(U.map("_sel_", sel, "_state_", x.serializeLocals()));
}
}

private static Map<String, Object> pageModel(String filename, Object result, Res resource) {
String template = U.safe(resource.getContent());

Map<String, Object> model = U.map("result", result);

String[] contentParts = template.split("\n", 2);
if (contentParts.length == 2) {
String line = contentParts[0];

Matcher m = DIRECTIVE.matcher(line);
if (m.matches()) {
String directives = m.group(1);
for (String directive : directives.split(",")) {
directive = directive.trim();
if (!U.isEmpty(directive)) {
if (directive.startsWith("+")) {
model.put(directive.substring(1), true);
} else if (directive.startsWith("-")) {
model.put(directive.substring(1), false);
} else {
Log.warn("Unknown directive!", "directive", directive, "file", filename);
}
}
}

template = contentParts[1]; // without the directive
}
}

String content = Templates.fromString(template).render(model, result);
model.put("content", content); // content without the directive
return model;
}

protected Object genericScreen() {
Expand Down
Expand Up @@ -57,7 +57,9 @@ public class PojoDispatcherImpl implements PojoDispatcher, Constants {
protected final Map<DispatchReq, DispatchTarget> mappings = U.map();

public PojoDispatcherImpl(Map<String, Class<?>> components) {
init(components);
if (components != null) {
init(components);
}
}

private void init(Map<String, Class<?>> components) {
Expand Down
4 changes: 1 addition & 3 deletions rapidoid-docs/src/main/java/org/rapidoid/docs/Docs.java
Expand Up @@ -35,7 +35,6 @@
import org.rapidoid.main.Rapidoid;
import org.rapidoid.plugins.templates.Templates;
import org.rapidoid.scan.ClasspathUtil;
import org.rapidoid.util.D;
import org.rapidoid.util.U;
import org.rapidoid.webapp.AppMode;
import org.rapidoid.webapp.WebApp;
Expand Down Expand Up @@ -133,7 +132,6 @@ private static void processIndex(IntWrap nn, List<Map<String, ?>> examples, Stri

snippet = snippet.substring(pos).trim();
snippet = SnippetWidget.prettify(snippet, true);
D.print(snippet);

String titleInfo = "";
String fullTitle = title + titleInfo;
Expand All @@ -142,7 +140,7 @@ private static void processIndex(IntWrap nn, List<Map<String, ?>> examples, Stri
Iterable<Class<?>> clss = ClasspathUtil.scanClasses("org.rapidoid.docs.eg" + id, null, null, null, null);

Classes classes = Classes.from(clss);
WebApp app = new WebApp("eg" + id, "App", null, null, U.set("/"), AppMode.PRODUCTION, null, classes);
WebApp app = new WebApp("eg" + id, "App", null, null, U.set("/"), AppMode.PRODUCTION, null, null, classes);
app.getRouter().generic(new AppHandler());

WebAppGroup.main().clear();
Expand Down

0 comments on commit 5a890db

Please sign in to comment.