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

for ( var sel in data._sel_) { for ( var sel in data._sel_) {
if (sel == 'body') { if (sel == 'body') {
$scope.ajaxBodyContent = data._sel_[sel]; $scope.ajaxBodyContent = data._sel_[sel];
$scope.$apply(); $scope.$apply();
} else { } else {
alert('Selector not supported: ' + sel); swal('Selector not supported: ' + sel);
} }
} }
} }
}).fail(function(data) { }).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); 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.Since;
import org.rapidoid.annotation.Web; import org.rapidoid.annotation.Web;
import org.rapidoid.beany.Metadata; import org.rapidoid.beany.Metadata;
import org.rapidoid.dispatch.PojoDispatcher;
import org.rapidoid.util.U; import org.rapidoid.util.U;


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


public final Class<?> main; public final Class<?> main;
public final Map<String, Class<?>> components; 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.main = main;
this.components = services; this.components = components;
this.dispatcher = new WebPojoDispatcher(services);
} }


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


@Override @Override
public String toString() { 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;
import java.util.Map.Entry;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;


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


@Authors("Nikolche Mihajlovski") @Authors("Nikolche Mihajlovski")
@Since("2.0.0") @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) { public Object processReq(HttpExchange x) {
HttpExchangeInternals xi = (HttpExchangeInternals) x; Object result = dispatch((HttpExchangeImpl) x);

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

Object result = dispatch(x, appCls);


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


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


// static files // static files


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


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


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


if (appCls.dispatcher != null) { // Prepare GUI state
try {
dispatchResult = appCls.dispatcher.dispatch(new WebReq(x)); x.loadState();
result = dispatchResult.getResult();
} catch (PojoHandlerNotFoundException e) { // if an event was emitted, process it
// / just ignore, will try to dispatch a page next...
} catch (PojoDispatchException e) { if (x.isPostReq()) {
return x.error(e); 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()) { // FIXME: call the command handler
return result;
}


// 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) { if (result == null) {
// try generic app screens // try generic app screens
result = genericScreen(); 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; return x;
} }


Expand All @@ -148,55 +181,89 @@ public Object dispatch(HttpExchange x, AppClasses appCls) {
throw x.notFound(); 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); Res resource = Res.from(filename);


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

} else if (result != null) {
String template = U.safe(resource.getContent()); model = U.map("result", result, "content", result, "navbar", true);

} else {
Map<String, Object> model = U.map("result", result); return false;

}
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("embedded", hasEvent || x.param("embedded", null) != null);
model.put("content", content); // content without the directive


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


return true; return true;
}


} else if (result != null) { private void serveEventResponse(HttpExchangeImpl x, String html) {
x.html(); x.startResponse(200);
Map<String, Object> model = U.map("result", result, "content", result, "navbar", true); x.json();
x.renderPage(model);
return true; if (x.redirectUrl() != null) {
x.writeJSON(U.map("_redirect_", x.redirectUrl()));
} else { } 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() { 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(); protected final Map<DispatchReq, DispatchTarget> mappings = U.map();


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


private void init(Map<String, Class<?>> 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.main.Rapidoid;
import org.rapidoid.plugins.templates.Templates; import org.rapidoid.plugins.templates.Templates;
import org.rapidoid.scan.ClasspathUtil; import org.rapidoid.scan.ClasspathUtil;
import org.rapidoid.util.D;
import org.rapidoid.util.U; import org.rapidoid.util.U;
import org.rapidoid.webapp.AppMode; import org.rapidoid.webapp.AppMode;
import org.rapidoid.webapp.WebApp; 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 = snippet.substring(pos).trim();
snippet = SnippetWidget.prettify(snippet, true); snippet = SnippetWidget.prettify(snippet, true);
D.print(snippet);


String titleInfo = ""; String titleInfo = "";
String fullTitle = title + 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); Iterable<Class<?>> clss = ClasspathUtil.scanClasses("org.rapidoid.docs.eg" + id, null, null, null, null);


Classes classes = Classes.from(clss); 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()); app.getRouter().generic(new AppHandler());


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

0 comments on commit 5a890db

Please sign in to comment.