diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fbadf58
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+\.idea/
+\.vertx/
+server/target
+*.iml
diff --git a/README.md b/README.md
index 3848072..d04b57b 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,29 @@
-stagemonitor-vertx-example
+# Stagemonitor Vertx Example
+
+This project is a example project for the stagemonitor-vertx plugin. The project is very basic it's only a login page and a book search page. The goal is to show how the plugin work in a Vertx environment. This project have a Vertx vanilla version and a version with the Vertx RxJava plugin.
+
+## Usage
+To use the plugin correctly you must enter a valid elasticsearch url in stagemonitor.properties.
+
+### Start vanilla version
+To start the vanilla version you must run the server module with those config:
+- Main Class: io.vertx.core.Starter
+- Vm Options: -Dvertx.logger-delegate-factory-class-name=io.vertx.core.logging.Log4jLogDelegateFactory
+- Program arguments: run org.stagemonitor.vertx.example.verticles.MainVerticle
+
+### Start RxJava version
+To start the vanilla version you must run the server module with those config:
+- Main Class: io.vertx.core.Starter
+- Vm Options: -Dvertx.logger-delegate-factory-class-name=io.vertx.core.logging.Log4jLogDelegateFactory
+- Program arguments: run org.stagemonitor.vertx.example.verticles.rxjava.MainVerticle
+
+### Use the app
+To use the app go on [localhost:8080](http://localhost:8080)
+
+The possible login option are:
+- User: test1 Password: test1
+- User: test2 Password: test2
+
+The books available are:
+- book1
+- book2
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..e840b5a
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+
+ org.stagemonitor
+ stagemonitor-vertx-example
+ pom
+ 0.1
+
+ server
+
+
+
+ UTF-8
+
+
+ false
+
+
+ false
+
+
+ ${project.groupId}~${project.artifactId}~${project.version}
+
+
+ target/mods
+
+
+ 3.0.0
+ 2.0.3-final
+
+
\ No newline at end of file
diff --git a/server/pom.xml b/server/pom.xml
new file mode 100644
index 0000000..507b5dc
--- /dev/null
+++ b/server/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+ stagemonitor-vertx-example
+ org.stagemonitor
+ 0.1
+
+ 4.0.0
+
+ server
+
+
+
+
+
+ maven-compiler-plugin
+ 3.3
+
+ 1.8
+ 1.8
+
+
+
+
+
+
+
+ io.vertx
+ vertx-core
+ ${vertx.version}
+
+
+ io.vertx
+ vertx-web
+ ${vertx.version}
+
+
+ io.vertx
+ vertx-rx-java
+ ${vertx.version}
+
+
+ org.stagemonitor
+ stagemonitor-vertx
+ 0.32.0-SNAPSHOT
+
+
+ log4j
+ log4j
+ 1.2.17
+
+
+ org.slf4j
+ slf4j-log4j12
+ 1.7.24
+
+
+
\ No newline at end of file
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/RequestNamerImpl.java b/server/src/main/java/org/stagemonitor/vertx/example/RequestNamerImpl.java
new file mode 100644
index 0000000..869dfe5
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/RequestNamerImpl.java
@@ -0,0 +1,13 @@
+package org.stagemonitor.vertx.example;
+
+import io.vertx.core.eventbus.Message;
+import io.vertx.core.json.JsonObject;
+import org.stagemonitor.vertx.utils.RequestNamer;
+
+public class RequestNamerImpl implements RequestNamer {
+ @Override
+ public String getRequestName(Message> message) {
+ JsonObject body = (JsonObject) message.body();
+ return message.address() + "." + body.getString("action");
+ }
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/database/DatabaseStub.java b/server/src/main/java/org/stagemonitor/vertx/example/database/DatabaseStub.java
new file mode 100644
index 0000000..4eff4dd
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/database/DatabaseStub.java
@@ -0,0 +1,90 @@
+package org.stagemonitor.vertx.example.database;
+
+import io.vertx.core.json.JsonArray;
+import io.vertx.core.json.JsonObject;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class DatabaseStub {
+ private static DatabaseStub ourInstance = new DatabaseStub();
+
+ public static DatabaseStub aquire() {
+ return ourInstance;
+ }
+
+ private JsonArray acceptedCredentials;
+ private HashMap books;
+ private HashMap> availabilities;
+
+ private DatabaseStub() {
+ acceptedCredentials = new JsonArray(new ArrayList(){{
+ add(new JsonObject(){{
+ put("username", "test1");
+ put("password", "test1");
+ }});
+ add(new JsonObject(){{
+ put("username", "test2");
+ put("password", "test2");
+ }});
+ }});
+
+ books = new HashMap(){{
+ put("book1", new JsonObject(){{
+ put("name", "book1");
+ put("author", "author1");
+ put("price", 12.50);
+ }});
+ put("book2", new JsonObject(){{
+ put("name", "book2");
+ put("author", "author2");
+ put("price", 15.50);
+ }});
+ }};
+
+ availabilities = new HashMap>(){{
+ put("Montreal", new HashMap(){{
+ put("book1", 2);
+ put("book2", 3);
+ }});
+ put("Laval", new HashMap(){{
+ put("book1", 3);
+ put("book2", 2);
+ }});
+ put("Repentigny", new HashMap(){{
+ put("book1", 2);
+ put("book2", 0);
+ }});
+ put("Terrebonne", new HashMap(){{
+ put("book1", 0);
+ put("book2", 2);
+ }});
+ }};
+ }
+
+ public boolean checkCredentials(String username, String password){
+ boolean accepted = false;
+ JsonObject user;
+ for (int i = 0; i < acceptedCredentials.size() && ! accepted; i++) {
+ user = acceptedCredentials.getJsonObject(i);
+ accepted = username.equals(user.getString("username")) && password.equals(user.getString("password"));
+ }
+ return accepted;
+ }
+
+ public JsonObject getBookByName(String name){
+ return books.get(name);
+ }
+
+ public JsonObject getBookAvailabilities(String name){
+ JsonObject avail = new JsonObject();
+ int count;
+ for(String city : availabilities.keySet()){
+ count = availabilities.get(city).get(name);
+ if(count > 0){
+ avail.put(city, count);
+ }
+ }
+ return avail;
+ }
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/BaseVerticle.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/BaseVerticle.java
new file mode 100644
index 0000000..f0e6df1
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/BaseVerticle.java
@@ -0,0 +1,204 @@
+package org.stagemonitor.vertx.example.verticles;
+
+import io.vertx.core.AbstractVerticle;
+import io.vertx.core.Context;
+import io.vertx.core.Handler;
+import io.vertx.core.Vertx;
+import io.vertx.core.eventbus.EventBus;
+import io.vertx.core.eventbus.Message;
+import io.vertx.core.json.JsonArray;
+import io.vertx.core.json.JsonObject;
+import io.vertx.core.logging.Logger;
+import io.vertx.core.logging.LoggerFactory;
+
+import java.lang.reflect.Method;
+import java.net.HttpURLConnection;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+public abstract class BaseVerticle extends AbstractVerticle {
+
+ protected EventBus bus;
+ protected JsonObject config;
+ protected Logger logger;
+ protected String address;
+
+ private HashMap actionMethodMap = new HashMap<>();
+
+ @Override
+ public void init(Vertx vertx, Context context) {
+ super.init(vertx, context);
+ bus = this.vertx.eventBus();
+ config = context.config();
+ }
+
+ private Method getMethodForAction(String action){
+ if (actionMethodMap.containsKey(action)) {
+ return actionMethodMap.get(action);
+ } else {
+ Method tmp = null;
+ try {
+ tmp = getClass().getDeclaredMethod(action, Message.class);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+ if(tmp != null){
+ actionMethodMap.put(action, tmp);
+ }
+ return tmp;
+ }
+ }
+
+ protected void registerActions(List actions){
+ if (address == null) {
+ throw new IllegalStateException("Address must be initialized first");
+ }
+ logger = LoggerFactory.getLogger(address);
+
+ bus.consumer(address, (Handler>) message -> {
+ String action = message.body().getString("action");
+
+ if(actions.contains(action)){
+ Method method = getMethodForAction(action);
+
+ if (method == null){
+ sendError(message, "Action " + action + " not implemented");
+ }
+ else {
+ try {
+ method.invoke(this, message);
+ } catch (Exception e) {
+ logger.error("Error happened with action : " + action);
+ logger.error(e,e);
+ sendError(message, "Oups an error happenned on the server");
+ }
+ }
+ }
+ else{
+ sendError(message, "Action " + action + " not supported");
+ }
+ });
+ logger.info(address + " started with actions " + String.join(", ", actions));
+ }
+
+ protected void sendStatus(Message message, String status, int code) {
+ sendStatus(message, status, code, new JsonObject());
+ }
+
+ private JsonObject constructBaseResponse(String status, int code){
+ JsonObject response = new JsonObject();
+ response.put("status", status);
+ response.put("code", code);
+ return response;
+ }
+
+ protected void sendStatus(Message message, String status, int code, JsonObject json) {
+ JsonObject response = constructBaseResponse(status, code);
+ response.put("result", json);
+ message.reply(response);
+ }
+
+ protected void sendStatus(Message message, String status, int code, JsonArray jsonA) {
+ JsonObject response = constructBaseResponse(status, code);
+ response.put("result", jsonA);
+ message.reply(response);
+ }
+
+ protected void sendBytes(Message message, byte[] data) {
+ JsonObject response = new JsonObject();
+ response.put("bytes", data);
+ message.reply(response);
+ }
+
+ protected void sendOK(Message message, JsonObject json) {
+ sendStatus(message, "ok", HttpURLConnection.HTTP_OK, json);
+ }
+
+ protected void sendOK(Message message, JsonArray jsonA) {
+ sendStatus(message, "ok", HttpURLConnection.HTTP_OK, jsonA);
+ }
+
+ protected void sendOK(Message message) {
+ sendOK(message, new JsonObject());
+ }
+
+ protected void sendUndefined(Message message) {
+ JsonObject response = constructBaseResponse("ok", HttpURLConnection.HTTP_OK);
+ message.reply(response);
+ }
+
+ protected void sendError(Message message, String error) {
+ sendError(message, error, null);
+ }
+
+ protected void sendError(Message message, String error, Exception e) {
+ JsonObject json = new JsonObject();
+ json.put("message", error);
+ sendStatus(message, "error", HttpURLConnection.HTTP_INTERNAL_ERROR, json);
+ }
+
+ protected boolean getOptionalBooleanConfig(String fieldName, boolean defaultValue) {
+ Boolean b = config.getBoolean(fieldName);
+ return b == null ? defaultValue : b.booleanValue();
+ }
+
+ protected String getOptionalStringConfig(String fieldName, String defaultValue) {
+ String s = config.getString(fieldName);
+ return s == null ? defaultValue : s;
+ }
+
+ protected int getOptionalIntConfig(String fieldName, int defaultValue) {
+ Number i = config.getInteger(fieldName);
+ return i == null ? defaultValue : i.intValue();
+ }
+
+ protected long getOptionalLongConfig(String fieldName, long defaultValue) {
+ Number l = config.getLong(fieldName);
+ return l == null ? defaultValue : l.longValue();
+ }
+
+ protected JsonObject getOptionalObjectConfig(String fieldName, JsonObject defaultValue) {
+ JsonObject o = config.getJsonObject(fieldName);
+ return o == null ? defaultValue : o;
+ }
+
+ protected JsonArray getOptionalArrayConfig(String fieldName, JsonArray defaultValue) {
+ JsonArray a = config.getJsonArray(fieldName);
+ return a == null ? defaultValue : a;
+ }
+
+ protected boolean getMandatoryBooleanConfig(String fieldName) {
+ Boolean b = config.getBoolean(fieldName);
+ if (b == null) {
+ // TODO busmod do not exist no more
+ throw new IllegalArgumentException(fieldName + " must be specified in config for busmod");
+ }
+ return b;
+ }
+
+ protected String getMandatoryStringConfig(String fieldName) {
+ String s = config.getString(fieldName);
+ if (s == null) {
+ throw new IllegalArgumentException(fieldName + " must be specified in config for busmod");
+ }
+ return s;
+ }
+
+ protected int getMandatoryIntConfig(String fieldName) {
+ Number i = config.getInteger(fieldName);
+ if (i == null) {
+ throw new IllegalArgumentException(fieldName + " must be specified in config for busmod");
+ }
+ return i.intValue();
+ }
+
+ protected long getMandatoryLongConfig(String fieldName) {
+ Number l = config.getLong(fieldName);
+ if (l == null) {
+ throw new IllegalArgumentException(fieldName + " must be specified in config for busmod");
+ }
+ return l.longValue();
+ }
+
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/BookService.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/BookService.java
new file mode 100644
index 0000000..5a5938a
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/BookService.java
@@ -0,0 +1,65 @@
+package org.stagemonitor.vertx.example.verticles;
+
+import io.vertx.core.eventbus.Message;
+import io.vertx.core.json.JsonObject;
+import io.vertx.core.logging.LoggerFactory;
+
+import java.util.Arrays;
+
+public class BookService extends BaseVerticle{
+ public static final String DB_SERVICE = "dbservice";
+
+ private static final String[] ACTIONS = new String[]{"getBookInfo"};
+
+ @Override
+ public void start() throws Exception {
+ super.start();
+ address = "example.bookService";
+ logger = LoggerFactory.getLogger(address);
+ registerActions(Arrays.asList(ACTIONS));
+ }
+
+ public void getBookInfo(Message message){
+ String bookName = message.body().getString("name");
+ if(!bookName.isEmpty()){
+ JsonObject getBookJson = new JsonObject(){{
+ put("action", "getBookByName");
+ put("name", bookName);
+ }};
+ JsonObject getAvailJson = new JsonObject(){{
+ put("action", "getBookAvailabilities");
+ put("name", bookName);
+ }};
+
+ bus.send(DB_SERVICE, getBookJson, resBook ->{
+ if(resBook.succeeded()){
+ bus.send(DB_SERVICE, getAvailJson, resAvail -> {
+ if(resAvail.succeeded()){
+ JsonObject response = (JsonObject) resBook.result().body();
+ if(response.getInteger("code") == null) {
+ JsonObject avail = (JsonObject) resAvail.result().body();
+ if(avail.getInteger("code") == null) {
+ response.put("availabilities", avail);
+ }
+ else{
+ response = avail;
+ }
+ }
+
+ message.reply(response);
+ }
+ else{
+ logger.error("Error while getting book",resAvail.cause());
+ }
+ });
+ }
+ else{
+ logger.error("Error while getting book",resBook.cause());
+ }
+ });
+ }
+ else{
+ sendError(message, "The name cannot be empty");
+ }
+ }
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/DbService.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/DbService.java
new file mode 100644
index 0000000..b2b386b
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/DbService.java
@@ -0,0 +1,54 @@
+package org.stagemonitor.vertx.example.verticles;
+
+import io.vertx.core.eventbus.Message;
+import io.vertx.core.json.JsonObject;
+import io.vertx.core.logging.LoggerFactory;
+import org.stagemonitor.vertx.example.database.DatabaseStub;
+
+import java.util.Arrays;
+
+public class DbService extends BaseVerticle {
+ private static final String[] ACTIONS = new String[]{"checkCredentials", "getBookByName", "getBookAvailabilities"};
+
+ @Override
+ public void start() throws Exception {
+ super.start();
+ address = "dbservice";
+ logger = LoggerFactory.getLogger(address);
+ registerActions(Arrays.asList(ACTIONS));
+ }
+
+ public void checkCredentials(Message message){
+ DatabaseStub database = DatabaseStub.aquire();
+
+ boolean accepted = database.checkCredentials(message.body().getString("username"), message.body().getString("password"));
+ if(accepted){
+ sendOK(message);
+ }
+ else{
+ sendError(message, "Credentials invalid");
+ }
+ }
+
+ public void getBookByName(Message message){
+ DatabaseStub database = DatabaseStub.aquire();
+
+ JsonObject book = database.getBookByName(message.body().getString("name"));
+
+ if(book != null){
+ message.reply(book);
+ }
+ else{
+ sendError(message, "Book does not exist");
+ }
+ }
+
+ public void getBookAvailabilities(Message message){
+ DatabaseStub database = DatabaseStub.aquire();
+
+ JsonObject avail = database.getBookAvailabilities(message.body().getString("name"));
+ if(!avail.isEmpty()){
+ message.reply(avail);
+ }
+ }
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/LoginHandler.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/LoginHandler.java
new file mode 100644
index 0000000..180adfb
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/LoginHandler.java
@@ -0,0 +1,60 @@
+package org.stagemonitor.vertx.example.verticles;
+
+
+import io.vertx.core.AsyncResult;
+import io.vertx.core.Handler;
+import io.vertx.core.eventbus.EventBus;
+import io.vertx.core.eventbus.Message;
+import io.vertx.core.json.JsonObject;
+import io.vertx.core.logging.Logger;
+import io.vertx.core.logging.LoggerFactory;
+import io.vertx.ext.web.RoutingContext;
+
+import java.net.HttpURLConnection;
+
+public class LoginHandler implements Handler {
+
+ private static final String DB_SERVICE = "dbservice";
+
+ protected Logger logger = LoggerFactory.getLogger(LoginHandler.class);
+
+ @Override
+ public void handle(RoutingContext context) {
+ EventBus bus = context.vertx().eventBus();
+ JsonObject requestBody = context.getBodyAsJson();
+ String username = requestBody.getString("username");
+ String password = requestBody.getString("password");
+
+ if(username == null || password == null){
+ logger.info("Failed: null params");
+ context.fail(HttpURLConnection.HTTP_UNAUTHORIZED);
+ }
+ else {
+ JsonObject json = new JsonObject(){{
+ put("action", "checkCredentials");
+ put("username", username);
+ put("password", password);
+ }};
+
+ bus.send(DB_SERVICE, json, (Handler>>) res -> {
+ if(res.succeeded()){
+ Message message = res.result();
+ boolean codeOk = message.body().getInteger("code") == HttpURLConnection.HTTP_OK;
+ JsonObject result = new JsonObject(){{
+ put("code", codeOk ? HttpURLConnection.HTTP_OK : HttpURLConnection.HTTP_UNAUTHORIZED);
+ put("result", codeOk ? "Login Succeeded" : "Login Failed");
+ }};
+
+ context.response().putHeader("Content-Type", "text/json");
+ context.response().putHeader("Content-Length", Integer.toString(result.toString().length()));
+ context.response().write(result.toString());
+ context.response().end();
+ }
+ else{
+ logger.info("Failed: failed result");
+ context.fail(HttpURLConnection.HTTP_UNAUTHORIZED);
+ }
+ });
+ }
+ }
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/MainVerticle.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/MainVerticle.java
new file mode 100644
index 0000000..026f3d8
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/MainVerticle.java
@@ -0,0 +1,60 @@
+package org.stagemonitor.vertx.example.verticles;
+
+import io.vertx.core.AbstractVerticle;
+import io.vertx.core.Context;
+import io.vertx.core.DeploymentOptions;
+import io.vertx.core.Vertx;
+import io.vertx.core.json.JsonObject;
+import org.stagemonitor.core.Stagemonitor;
+
+import java.util.HashMap;
+
+public class MainVerticle extends AbstractVerticle {
+ public static final int DEFAULT_PORT = 8080;
+
+ public static void main(String[] args) {
+ }
+
+ @Override
+ public void init(Vertx vertx, Context context) {
+ Stagemonitor.init();
+ super.init(vertx, context);
+ }
+
+ @Override
+ public void start() throws Exception {
+ super.start();
+ System.out.println("starting server on " + Integer.toString(DEFAULT_PORT));
+ JsonObject webServerConfig = new JsonObject("{"
+ + "\"web_root\":\"web\","
+ + "\"bridge\":true,"
+ + "\"route_matcher\":true,"
+ + "\"port\":" + DEFAULT_PORT + ","
+ + "\"index_page\":\"index.html\","
+ + "\"sjs_config\": {"
+ + "\"prefix\":\"/eventbus\""
+ + "},"
+ + "\"inbound_permitted\":[ { \"address_re\":\".+\" } ]"
+ + "}"
+ );
+
+ DeploymentOptions opt = new DeploymentOptions(){{
+ setWorker(true);
+ setHa(true);
+ setConfig(webServerConfig);
+ }};
+
+ DeploymentOptions optWorker = new DeploymentOptions(){{
+ setWorker(true);
+ setHa(true);
+ }};
+
+ DeploymentOptions optHA = new DeploymentOptions(){{
+ setHa(true);
+ }};
+
+ vertx.deployVerticle("org.stagemonitor.vertx.example.verticles.DbService", optWorker);
+ vertx.deployVerticle("org.stagemonitor.vertx.example.verticles.BookService", optHA);
+ vertx.deployVerticle("org.stagemonitor.vertx.example.verticles.WebServer", opt);
+ }
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/WebServer.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/WebServer.java
new file mode 100644
index 0000000..71334a4
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/WebServer.java
@@ -0,0 +1,83 @@
+package org.stagemonitor.vertx.example.verticles;
+
+import io.vertx.core.AsyncResult;
+import io.vertx.core.Handler;
+import io.vertx.core.eventbus.Message;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.HttpServer;
+import io.vertx.core.http.HttpServerOptions;
+import io.vertx.core.json.JsonObject;
+import io.vertx.core.logging.LoggerFactory;
+import io.vertx.ext.web.Router;
+import io.vertx.ext.web.RoutingContext;
+import io.vertx.ext.web.handler.BodyHandler;
+import io.vertx.ext.web.handler.StaticHandler;
+import io.vertx.ext.web.handler.impl.StaticHandlerImpl;
+import io.vertx.ext.web.handler.sockjs.BridgeOptions;
+import io.vertx.ext.web.handler.sockjs.PermittedOptions;
+import io.vertx.ext.web.handler.sockjs.SockJSHandler;
+
+import java.net.HttpURLConnection;
+
+public class WebServer extends BaseVerticle {
+ public static final int DEFAULT_PORT = 8080;
+ public static final String DEFAULT_ADDRESS = "0.0.0.0";
+ public static final String DEFAULT_WEB_ROOT = "web";
+ public static final String DEFAULT_INDEX_PAGE = "index.html";
+ public static final boolean CACHING_ENABLED = true;
+
+ private Router router;
+
+ @Override
+ public void start() throws Exception {
+ super.start();
+ logger = LoggerFactory.getLogger("WebServer");
+
+ router = Router.router(this.vertx);
+
+ router.route().handler(BodyHandler.create());
+
+ router.route(HttpMethod.POST, "/login").handler(new LoginHandler());
+
+ if(getOptionalBooleanConfig("bridge", false)){
+ SockJSHandler sockJSHandler = SockJSHandler.create(vertx);
+
+ BridgeOptions options = new BridgeOptions();
+ options.addInboundPermitted(new PermittedOptions(){{
+ setAddressRegex(".*");
+ }});
+ options.addOutboundPermitted(new PermittedOptions(){{
+ setAddressRegex(".*");
+ }});
+
+ sockJSHandler.bridge(options);
+
+ router.route("/eventbus/*").handler(sockJSHandler);
+ }
+
+ router.route().handler(staticHandler());
+
+ HttpServer server = vertx.createHttpServer(new HttpServerOptions(){{
+ setMaxWebsocketFrameSize(Integer.MAX_VALUE);
+ setCompressionSupported(true);
+ }});
+
+ server.requestHandler(it -> router.accept(it)).listen(
+ getOptionalIntConfig("port", DEFAULT_PORT),
+ getOptionalStringConfig("host", DEFAULT_ADDRESS),
+ ar -> {
+ if(!ar.succeeded()) {
+ logger.error(ar.cause().toString());
+ }
+ }
+ );
+ }
+
+ private StaticHandler staticHandler() {
+ return new StaticHandlerImpl(){{
+ setWebRoot(getOptionalStringConfig("web_root", DEFAULT_WEB_ROOT));
+ setIndexPage(getOptionalStringConfig("index_page", DEFAULT_INDEX_PAGE));
+ setCachingEnabled(getOptionalBooleanConfig("caching", CACHING_ENABLED));
+ }};
+ }
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/BaseVerticle.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/BaseVerticle.java
new file mode 100644
index 0000000..cf9dc28
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/BaseVerticle.java
@@ -0,0 +1,202 @@
+package org.stagemonitor.vertx.example.verticles.rxjava;
+
+import io.vertx.core.Context;
+import io.vertx.core.Vertx;
+import io.vertx.core.json.JsonArray;
+import io.vertx.core.json.JsonObject;
+import io.vertx.core.logging.Logger;
+import io.vertx.core.logging.LoggerFactory;
+import io.vertx.rxjava.core.AbstractVerticle;
+import io.vertx.rxjava.core.eventbus.EventBus;
+import io.vertx.rxjava.core.eventbus.Message;
+
+import java.lang.reflect.Method;
+import java.net.HttpURLConnection;
+import java.util.HashMap;
+import java.util.List;
+
+public abstract class BaseVerticle extends AbstractVerticle {
+
+ protected EventBus bus;
+ protected JsonObject config;
+ protected Logger logger;
+ protected String address;
+
+ private HashMap actionMethodMap = new HashMap<>();
+
+ @Override
+ public void init(Vertx vertx, Context context) {
+ super.init(vertx, context);
+ bus = this.vertx.eventBus();
+ config = context.config();
+ }
+
+ private Method getMethodForAction(String action){
+ if (actionMethodMap.containsKey(action)) {
+ return actionMethodMap.get(action);
+ } else {
+ Method tmp = null;
+ try {
+ tmp = getClass().getDeclaredMethod(action, Message.class);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+ if(tmp != null){
+ actionMethodMap.put(action, tmp);
+ }
+ return tmp;
+ }
+ }
+
+ protected void registerActions(List actions){
+ if (address == null) {
+ throw new IllegalStateException("Address must be initialized first");
+ }
+ logger = LoggerFactory.getLogger(address);
+
+ bus.consumer(address).toObservable().subscribe( message -> {
+ String action = message.body().getString("action");
+
+ if(actions.contains(action)){
+ Method method = getMethodForAction(action);
+
+ if (method == null){
+ sendError(message, "Action " + action + " not implemented");
+ }
+ else {
+ try {
+ method.invoke(this, message);
+ } catch (Exception e) {
+ logger.error("Error happened with action : " + action);
+ logger.error(e,e);
+ sendError(message, "Oups an error happenned on the server");
+ }
+ }
+ }
+ else{
+ sendError(message, "Action " + action + " not supported");
+ }
+ });
+ logger.info(address + " started with actions " + String.join(", ", actions));
+ }
+
+ protected void sendStatus(Message message, String status, int code) {
+ sendStatus(message, status, code, new JsonObject());
+ }
+
+ private JsonObject constructBaseResponse(String status, int code){
+ JsonObject response = new JsonObject();
+ response.put("status", status);
+ response.put("code", code);
+ return response;
+ }
+
+ protected void sendStatus(Message message, String status, int code, JsonObject json) {
+ JsonObject response = constructBaseResponse(status, code);
+ response.put("result", json);
+ message.reply(response);
+ }
+
+ protected void sendStatus(Message message, String status, int code, JsonArray jsonA) {
+ JsonObject response = constructBaseResponse(status, code);
+ response.put("result", jsonA);
+ message.reply(response);
+ }
+
+ protected void sendBytes(Message message, byte[] data) {
+ JsonObject response = new JsonObject();
+ response.put("bytes", data);
+ message.reply(response);
+ }
+
+ protected void sendOK(Message message, JsonObject json) {
+ sendStatus(message, "ok", HttpURLConnection.HTTP_OK, json);
+ }
+
+ protected void sendOK(Message message, JsonArray jsonA) {
+ sendStatus(message, "ok", HttpURLConnection.HTTP_OK, jsonA);
+ }
+
+ protected void sendOK(Message message) {
+ sendOK(message, new JsonObject());
+ }
+
+ protected void sendUndefined(Message message) {
+ JsonObject response = constructBaseResponse("ok", HttpURLConnection.HTTP_OK);
+ message.reply(response);
+ }
+
+ protected void sendError(Message message, String error) {
+ sendError(message, error, null);
+ }
+
+ protected void sendError(Message message, String error, Exception e) {
+ JsonObject json = new JsonObject();
+ json.put("message", error);
+ sendStatus(message, "error", HttpURLConnection.HTTP_INTERNAL_ERROR, json);
+ }
+
+ protected boolean getOptionalBooleanConfig(String fieldName, boolean defaultValue) {
+ Boolean b = config.getBoolean(fieldName);
+ return b == null ? defaultValue : b.booleanValue();
+ }
+
+ protected String getOptionalStringConfig(String fieldName, String defaultValue) {
+ String s = config.getString(fieldName);
+ return s == null ? defaultValue : s;
+ }
+
+ protected int getOptionalIntConfig(String fieldName, int defaultValue) {
+ Number i = config.getInteger(fieldName);
+ return i == null ? defaultValue : i.intValue();
+ }
+
+ protected long getOptionalLongConfig(String fieldName, long defaultValue) {
+ Number l = config.getLong(fieldName);
+ return l == null ? defaultValue : l.longValue();
+ }
+
+ protected JsonObject getOptionalObjectConfig(String fieldName, JsonObject defaultValue) {
+ JsonObject o = config.getJsonObject(fieldName);
+ return o == null ? defaultValue : o;
+ }
+
+ protected JsonArray getOptionalArrayConfig(String fieldName, JsonArray defaultValue) {
+ JsonArray a = config.getJsonArray(fieldName);
+ return a == null ? defaultValue : a;
+ }
+
+ protected boolean getMandatoryBooleanConfig(String fieldName) {
+ Boolean b = config.getBoolean(fieldName);
+ if (b == null) {
+ // TODO busmod do not exist no more
+ throw new IllegalArgumentException(fieldName + " must be specified in config for busmod");
+ }
+ return b;
+ }
+
+ protected String getMandatoryStringConfig(String fieldName) {
+ String s = config.getString(fieldName);
+ if (s == null) {
+ throw new IllegalArgumentException(fieldName + " must be specified in config for busmod");
+ }
+ return s;
+ }
+
+ protected int getMandatoryIntConfig(String fieldName) {
+ Number i = config.getInteger(fieldName);
+ if (i == null) {
+ throw new IllegalArgumentException(fieldName + " must be specified in config for busmod");
+ }
+ return i.intValue();
+ }
+
+ protected long getMandatoryLongConfig(String fieldName) {
+ Number l = config.getLong(fieldName);
+ if (l == null) {
+ throw new IllegalArgumentException(fieldName + " must be specified in config for busmod");
+ }
+ return l.longValue();
+ }
+
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/BookService.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/BookService.java
new file mode 100644
index 0000000..e81848b
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/BookService.java
@@ -0,0 +1,55 @@
+package org.stagemonitor.vertx.example.verticles.rxjava;
+
+import io.vertx.core.json.JsonObject;
+import io.vertx.core.logging.LoggerFactory;
+import io.vertx.rxjava.core.eventbus.Message;
+import rx.Observable;
+
+import java.util.Arrays;
+
+public class BookService extends BaseVerticle {
+ public static final String DB_SERVICE = "dbservice";
+
+ private static final String[] ACTIONS = new String[]{"getBookInfo"};
+
+ @Override
+ public void start() throws Exception {
+ super.start();
+ address = "example.bookService";
+ logger = LoggerFactory.getLogger(address);
+ registerActions(Arrays.asList(ACTIONS));
+ }
+
+ public void getBookInfo(Message message){
+ String bookName = message.body().getString("name");
+ if(!bookName.isEmpty()){
+ JsonObject getBookJson = new JsonObject(){{
+ put("action", "getBookByName");
+ put("name", bookName);
+ }};
+ JsonObject getAvailJson = new JsonObject(){{
+ put("action", "getBookAvailabilities");
+ put("name", bookName);
+ }};
+
+ Observable> obsBook = bus.sendObservable(DB_SERVICE, getBookJson);
+ Observable> obsAvail = bus.sendObservable(DB_SERVICE, getAvailJson);
+
+ Observable.zip(obsBook, obsAvail, (msgBook, msgAvail) -> {
+ JsonObject response = msgBook.body();
+ if(response.getInteger("code") == null) {
+ if(msgAvail.body().getInteger("code") == null) {
+ response.put("availabilities", msgAvail.body());
+ }
+ else{
+ response = msgAvail.body();
+ }
+ }
+ return response;
+ }).subscribe(message::reply);
+ }
+ else{
+ sendError(message, "The name cannot be empty");
+ }
+ }
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/DbService.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/DbService.java
new file mode 100644
index 0000000..fb5441a
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/DbService.java
@@ -0,0 +1,54 @@
+package org.stagemonitor.vertx.example.verticles.rxjava;
+
+import io.vertx.core.json.JsonObject;
+import io.vertx.core.logging.LoggerFactory;
+import io.vertx.rxjava.core.eventbus.Message;
+import org.stagemonitor.vertx.example.database.DatabaseStub;
+
+import java.util.Arrays;
+
+public class DbService extends BaseVerticle {
+ private static final String[] ACTIONS = new String[]{"checkCredentials", "getBookByName", "getBookAvailabilities"};
+
+ @Override
+ public void start() throws Exception {
+ super.start();
+ address = "dbservice";
+ logger = LoggerFactory.getLogger(address);
+ registerActions(Arrays.asList(ACTIONS));
+ }
+
+ public void checkCredentials(Message message){
+ DatabaseStub database = DatabaseStub.aquire();
+
+ boolean accepted = database.checkCredentials(message.body().getString("username"), message.body().getString("password"));
+ if(accepted){
+ sendOK(message);
+ }
+ else{
+ sendError(message, "Credentials invalid");
+ }
+ }
+
+ public void getBookByName(Message message){
+ DatabaseStub database = DatabaseStub.aquire();
+
+ JsonObject book = database.getBookByName(message.body().getString("name"));
+
+ if(book != null){
+ message.reply(book);
+ }
+ else{
+ sendError(message, "Book does not exist");
+ }
+ }
+
+ public void getBookAvailabilities(Message message){
+ DatabaseStub database = DatabaseStub.aquire();
+
+ JsonObject avail = database.getBookAvailabilities(message.body().getString("name"));
+ if(!avail.isEmpty()){
+ message.reply(avail);
+ }
+ }
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/LoginHandler.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/LoginHandler.java
new file mode 100644
index 0000000..517d06e
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/LoginHandler.java
@@ -0,0 +1,53 @@
+package org.stagemonitor.vertx.example.verticles.rxjava;
+
+
+
+
+import io.vertx.core.Handler;
+import io.vertx.core.json.JsonObject;
+import io.vertx.core.logging.Logger;
+import io.vertx.core.logging.LoggerFactory;
+import io.vertx.rxjava.core.eventbus.EventBus;
+import io.vertx.rxjava.ext.web.RoutingContext;
+
+import java.net.HttpURLConnection;
+
+public class LoginHandler implements Handler {
+
+ private static final String DB_SERVICE = "dbservice";
+
+ protected Logger logger = LoggerFactory.getLogger(LoginHandler.class);
+
+ @Override
+ public void handle(RoutingContext context) {
+ EventBus bus = context.vertx().eventBus();
+ JsonObject requestBody = context.getBodyAsJson();
+ String username = requestBody.getString("username");
+ String password = requestBody.getString("password");
+
+ if(username == null || password == null){
+ logger.info("Failed: null params");
+ context.fail(HttpURLConnection.HTTP_UNAUTHORIZED);
+ }
+ else {
+ JsonObject json = new JsonObject(){{
+ put("action", "checkCredentials");
+ put("username", username);
+ put("password", password);
+ }};
+
+ bus.sendObservable(DB_SERVICE, json).subscribe(message -> {
+ boolean codeOk = message.body().getInteger("code") == HttpURLConnection.HTTP_OK;
+ JsonObject result = new JsonObject(){{
+ put("code", codeOk ? HttpURLConnection.HTTP_OK : HttpURLConnection.HTTP_UNAUTHORIZED);
+ put("result", codeOk ? "Login Succeeded" : "Login Failed");
+ }};
+
+ context.response().putHeader("Content-Type", "text/json");
+ context.response().putHeader("Content-Length", Integer.toString(result.toString().length()));
+ context.response().write(result.toString());
+ context.response().end();
+ });
+ }
+ }
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/MainVerticle.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/MainVerticle.java
new file mode 100644
index 0000000..0abbe82
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/MainVerticle.java
@@ -0,0 +1,58 @@
+package org.stagemonitor.vertx.example.verticles.rxjava;
+
+import io.vertx.core.AbstractVerticle;
+import io.vertx.core.Context;
+import io.vertx.core.DeploymentOptions;
+import io.vertx.core.Vertx;
+import io.vertx.core.json.JsonObject;
+import org.stagemonitor.core.Stagemonitor;
+
+public class MainVerticle extends AbstractVerticle {
+ public static final int DEFAULT_PORT = 8080;
+
+ public static void main(String[] args) {
+ }
+
+ @Override
+ public void init(Vertx vertx, Context context) {
+ Stagemonitor.init();
+ super.init(vertx, context);
+ }
+
+ @Override
+ public void start() throws Exception {
+ super.start();
+ System.out.println("starting server on " + Integer.toString(DEFAULT_PORT));
+ JsonObject webServerConfig = new JsonObject("{"
+ + "\"web_root\":\"web\","
+ + "\"bridge\":true,"
+ + "\"route_matcher\":true,"
+ + "\"port\":" + DEFAULT_PORT + ","
+ + "\"index_page\":\"index.html\","
+ + "\"sjs_config\": {"
+ + "\"prefix\":\"/eventbus\""
+ + "},"
+ + "\"inbound_permitted\":[ { \"address_re\":\".+\" } ]"
+ + "}"
+ );
+
+ DeploymentOptions opt = new DeploymentOptions(){{
+ setWorker(true);
+ setHa(true);
+ setConfig(webServerConfig);
+ }};
+
+ DeploymentOptions optWorker = new DeploymentOptions(){{
+ setWorker(true);
+ setHa(true);
+ }};
+
+ DeploymentOptions optHA = new DeploymentOptions(){{
+ setHa(true);
+ }};
+
+ vertx.deployVerticle("org.stagemonitor.vertx.example.verticles.rxjava.DbService", optWorker);
+ vertx.deployVerticle("org.stagemonitor.vertx.example.verticles.rxjava.BookService", optHA);
+ vertx.deployVerticle("org.stagemonitor.vertx.example.verticles.rxjava.WebServer", opt);
+ }
+}
diff --git a/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/WebServer.java b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/WebServer.java
new file mode 100644
index 0000000..654c682
--- /dev/null
+++ b/server/src/main/java/org/stagemonitor/vertx/example/verticles/rxjava/WebServer.java
@@ -0,0 +1,77 @@
+package org.stagemonitor.vertx.example.verticles.rxjava;
+
+
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.HttpServerOptions;
+import io.vertx.core.logging.LoggerFactory;
+import io.vertx.ext.web.handler.impl.StaticHandlerImpl;
+import io.vertx.ext.web.handler.sockjs.BridgeOptions;
+import io.vertx.ext.web.handler.sockjs.PermittedOptions;
+import io.vertx.rxjava.core.http.HttpServer;
+import io.vertx.rxjava.ext.web.Router;
+import io.vertx.rxjava.ext.web.handler.BodyHandler;
+import io.vertx.rxjava.ext.web.handler.StaticHandler;
+import io.vertx.rxjava.ext.web.handler.sockjs.SockJSHandler;
+
+public class WebServer extends BaseVerticle {
+ public static final int DEFAULT_PORT = 8080;
+ public static final String DEFAULT_ADDRESS = "0.0.0.0";
+ public static final String DEFAULT_WEB_ROOT = "web";
+ public static final String DEFAULT_INDEX_PAGE = "index.html";
+ public static final boolean CACHING_ENABLED = true;
+
+ private Router router;
+
+ @Override
+ public void start() throws Exception {
+ super.start();
+ logger = LoggerFactory.getLogger("WebServer");
+
+ router = Router.router(this.vertx);
+
+ router.route().handler(BodyHandler.create());
+
+ router.route(HttpMethod.POST, "/login").handler(new LoginHandler());
+
+ if(getOptionalBooleanConfig("bridge", false)){
+ SockJSHandler sockJSHandler = SockJSHandler.create(vertx);
+
+ BridgeOptions options = new BridgeOptions();
+ options.addInboundPermitted(new PermittedOptions(){{
+ setAddressRegex(".*");
+ }});
+ options.addOutboundPermitted(new PermittedOptions(){{
+ setAddressRegex(".*");
+ }});
+
+ sockJSHandler.bridge(options);
+
+ router.route("/eventbus/*").handler(sockJSHandler);
+ }
+
+ router.route().handler(staticHandler());
+
+ HttpServer server = vertx.createHttpServer(new HttpServerOptions(){{
+ setMaxWebsocketFrameSize(Integer.MAX_VALUE);
+ setCompressionSupported(true);
+ }});
+
+ server.requestHandler(it -> router.accept(it)).listen(
+ getOptionalIntConfig("port", DEFAULT_PORT),
+ getOptionalStringConfig("host", DEFAULT_ADDRESS),
+ ar -> {
+ if(!ar.succeeded()) {
+ logger.error(ar.cause().toString());
+ }
+ }
+ );
+ }
+
+ private StaticHandler staticHandler() {
+ return new StaticHandler(new StaticHandlerImpl(){{
+ setWebRoot(getOptionalStringConfig("web_root", DEFAULT_WEB_ROOT));
+ setIndexPage(getOptionalStringConfig("index_page", DEFAULT_INDEX_PAGE));
+ setCachingEnabled(getOptionalBooleanConfig("caching", CACHING_ENABLED));
+ }});
+ }
+}
diff --git a/server/src/main/resources/log4j.properties b/server/src/main/resources/log4j.properties
new file mode 100644
index 0000000..c40bc65
--- /dev/null
+++ b/server/src/main/resources/log4j.properties
@@ -0,0 +1,24 @@
+# For the general syntax of propperty based configuration files see
+# the documenation of org.apache.log4j.PropertyConfigurator.
+
+# The root category uses two appenders: default.out and default.file.
+# The first one gathers all log output, the latter only starting with
+# the priority INFO.
+# The root priority is DEBUG, so that all classes can be logged unless
+# defined otherwise in more specific properties.
+log4j.rootLogger=INFO, default.out
+log4j.logger.io.vertx.ext.web.handler.impl.SessionHandlerImpl=OFF
+log4j.logger.io.vertx.ext.web.handler.impl.StaticHandlerImpl=TRACE
+
+# System.out.println appender for all classes
+log4j.appender.default.out=org.apache.log4j.ConsoleAppender
+log4j.appender.default.out.threshold=INFO
+log4j.appender.default.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.default.out.layout.ConversionPattern=%-5p %c: %m%n
+
+log4j.appender.default.file=org.apache.log4j.FileAppender
+log4j.appender.default.file.append=true
+log4j.appender.default.file.file=/log/mylogfile.log
+log4j.appender.default.file.threshold=INFO
+log4j.appender.default.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.default.file.layout.ConversionPattern=%-5p %c: %m%n
\ No newline at end of file
diff --git a/server/src/main/resources/stagemonitor.properties b/server/src/main/resources/stagemonitor.properties
new file mode 100644
index 0000000..1db311b
--- /dev/null
+++ b/server/src/main/resources/stagemonitor.properties
@@ -0,0 +1,16 @@
+stagemonitor.active = true
+stagemonitor.elasticsearch.url =
+stagemonitor.applicationName = vertx-example
+stagemonitor.instanceName = example1
+stagemonitor.instrument.include = org.stagemonitor.vertx.example, io.vertx, rx
+stagemonitor.requestmonitor.external.onlyReportNExternalRequestsPerMinute = 1000000
+stagemonitor.instrument.debug = false
+
+
+stagemonitor.vertx.eventbus.requestNamerImplementation = org.stagemonitor.vertx.example.RequestNamerImpl
+
+####Default values####
+stagemonitor.vertx.eventbus.eventBusImplementation = io.vertx.core.eventbus.impl.EventBusImpl
+stagemonitor.vertx.eventbus.messageConsumerImplementation = io.vertx.core.eventbus.impl.EventBusImpl$HandlerRegistration
+stagemonitor.vertx.web.webRouteImplementation = io.vertx.ext.web.impl.RouteImpl
+#######################
\ No newline at end of file
diff --git a/web/css/main.css b/web/css/main.css
new file mode 100644
index 0000000..1d6becc
--- /dev/null
+++ b/web/css/main.css
@@ -0,0 +1,56 @@
+div#loginForm{
+ position: absolute;
+ top: 20%;
+ left: 50%;
+ width: 200px;
+ margin-left: -100px;
+}
+
+#txtUsername, #txtPassword{
+ width: 100%;
+ margin-bottom: 10px;
+}
+
+#btnLogin{
+ width: 50%;
+ display: block;
+ margin: auto;
+}
+
+div#bookForm{
+ position: absolute;
+ top: 20%;
+ left: 50%;
+ width:500px;
+ margin-left: -250px;
+}
+
+#txtSearch{
+ margin-left: 50px;
+ width: 300px;
+}
+
+#btnSearch{
+ margin-left: 20px;
+ width: 80px;
+}
+
+#bookInfo{
+ margin-top: 30px;
+ text-align: center;
+ display: none;
+}
+
+#bookInfo table{
+ margin: 0 auto;
+ text-align: left;
+}
+
+#bookInfo tr th:first-child,td:first-child{
+ padding-left: 2px;
+ padding-right: 10px;
+}
+
+#bookInfo table td.centered{
+ text-align: center;
+}
\ No newline at end of file
diff --git a/web/index.html b/web/index.html
new file mode 100644
index 0000000..ce81651
--- /dev/null
+++ b/web/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+ Stagemonitor vertx example
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/web/js/DOM.js b/web/js/DOM.js
new file mode 100644
index 0000000..fb5370c
--- /dev/null
+++ b/web/js/DOM.js
@@ -0,0 +1,29 @@
+var DOM = function(){
+ function queryFirst(selector, start){
+ var start = start || document;
+ return start.querySelector(selector);
+ }
+
+ function queryLast(selector, start){
+ var start = start || document;
+ var nodelist = start.querySelectorAll(selector);
+ return nodelist[nodelist.length-1];
+ }
+
+ function queryAll(selector, start){
+ var start = start || document;
+ return nodeListToArray(start.querySelectorAll(selector));
+ }
+
+ function nodeListToArray(nl){
+ var arr = [];
+ for(var i=-1,l=nl.length;++i!==l;arr[i]=nl[i]); //m/thode la plus rapide pour convertir un nodelist en array
+ return arr;
+ }
+
+ return {
+ queryFirst: queryFirst,
+ queryLast: queryLast,
+ queryAll: queryAll
+ }
+}();
\ No newline at end of file
diff --git a/web/js/EventBusHandler.js b/web/js/EventBusHandler.js
new file mode 100644
index 0000000..4228a04
--- /dev/null
+++ b/web/js/EventBusHandler.js
@@ -0,0 +1,28 @@
+var EventBusHandler = function () {
+ var bus;
+ var eventBusHandlerState = vertx.EventBus.CLOSED;
+
+ function init(){
+ bus = new vertx.EventBus("/eventbus");
+ bus.onopen = function () {
+ bus.sockJSConn;
+ eventBusHandlerState = vertx.EventBus.OPEN;
+ };
+ bus.onclose = function () {
+ console.warn("Eventbus closed");
+ eventBusHandlerState = vertx.EventBus.CLOSED;
+ };
+ }
+
+ function send(address, message, replyHandler, failureHandler) {
+ if(eventBusHandlerState === vertx.EventBus.OPEN){
+ bus.send(address, message, replyHandler, failureHandler);
+ }
+ }
+
+
+ return{
+ init:init,
+ send:send
+ }
+}();
diff --git a/web/js/NET.js b/web/js/NET.js
new file mode 100644
index 0000000..3acc6fc
--- /dev/null
+++ b/web/js/NET.js
@@ -0,0 +1,42 @@
+var NET = function(){
+ function get(config) {
+ var request = new XMLHttpRequest();
+ request.open('GET', config.url, true);
+ config.headers && config.headers.forEach(function (header) {
+ request.setRequestHeader(header.header,header.value);
+ request.onreadystatechange = function() {
+ if (this.readyState === 4) {
+ if (this.status >= 200 && this.status < 400) {
+ config.success && config.success(this);
+ } else {
+ config.error && config.error(this);
+ }
+ }
+ };
+ });
+ request.send();
+ }
+
+ function post(config) {
+ var request = new XMLHttpRequest();
+ request.open('POST', config.url, true);
+ config.headers && config.headers.forEach(function (header) {
+ request.setRequestHeader(header.header,header.value);
+ request.onreadystatechange = function() {
+ if (this.readyState === 4) {
+ if (this.status >= 200 && this.status < 400) {
+ config.success && config.success(this);
+ } else {
+ config.error && config.error(this);
+ }
+ }
+ };
+ });
+ request.send(config.data);
+ }
+
+ return {
+ get:get,
+ post:post
+ }
+}();
diff --git a/web/js/index.js b/web/js/index.js
new file mode 100644
index 0000000..1af4bd5
--- /dev/null
+++ b/web/js/index.js
@@ -0,0 +1,25 @@
+
+document.addEventListener('DOMContentLoaded', function(){
+ DOM.queryFirst('#btnLogin').addEventListener('click', function () {
+ var username = DOM.queryFirst('#txtUsername').value;
+ var password = DOM.queryFirst('#txtPassword').value;
+
+ NET.post({
+ url: window.location + 'login',
+ headers:[
+ {header: 'Content-Type', value: 'application/json; charset=UTF-8'}
+ ],
+ success: function (req) {
+ var response = JSON.parse(req.response);
+ if(response.code === 200){
+ window.location += "pages/mainPage.html"
+ }
+ else{
+ alert(response.result);
+ }
+ },
+ data: JSON.stringify({username: username, password: password})
+ });
+
+ })
+});
\ No newline at end of file
diff --git a/web/js/libs/sockjs.min.js b/web/js/libs/sockjs.min.js
new file mode 100644
index 0000000..60e80b0
--- /dev/null
+++ b/web/js/libs/sockjs.min.js
@@ -0,0 +1,3 @@
+/* sockjs-client v1.1.1 | http://sockjs.org | MIT license */
+!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.SockJS=t()}}(function(){var t;return function e(t,n,r){function i(s,a){if(!n[s]){if(!t[s]){var u="function"==typeof require&&require;if(!a&&u)return u(s,!0);if(o)return o(s,!0);var l=new Error("Cannot find module '"+s+"'");throw l.code="MODULE_NOT_FOUND",l}var c=n[s]={exports:{}};t[s][0].call(c.exports,function(e){var n=t[s][1][e];return i(n?n:e)},c,c.exports,e,t,n,r)}return n[s].exports}for(var o="function"==typeof require&&require,s=0;si;i++)r[i-1]=arguments[i];for(var o=0;o1?this._listeners[t]=n.slice(0,r).concat(n.slice(r+1)):delete this._listeners[t]):void 0}},n.prototype.dispatchEvent=function(){var t=arguments[0],e=t.type,n=1===arguments.length?[t]:Array.apply(null,arguments);if(this["on"+e]&&this["on"+e].apply(this,n),e in this._listeners)for(var r=this._listeners[e],i=0;i=3e3&&4999>=t}t("./shims");var o,s=t("url-parse"),a=t("inherits"),u=t("json3"),l=t("./utils/random"),c=t("./utils/escape"),f=t("./utils/url"),h=t("./utils/event"),d=t("./utils/transport"),p=t("./utils/object"),v=t("./utils/browser"),m=t("./utils/log"),y=t("./event/event"),b=t("./event/eventtarget"),g=t("./location"),w=t("./event/close"),x=t("./event/trans-message"),_=t("./info-receiver");a(r,b),r.prototype.close=function(t,e){if(t&&!i(t))throw new Error("InvalidAccessError: Invalid code");if(e&&e.length>123)throw new SyntaxError("reason argument has an invalid length");if(this.readyState!==r.CLOSING&&this.readyState!==r.CLOSED){var n=!0;this._close(t||1e3,e||"Normal closure",n)}},r.prototype.send=function(t){if("string"!=typeof t&&(t=""+t),this.readyState===r.CONNECTING)throw new Error("InvalidStateError: The connection has not been established yet");this.readyState===r.OPEN&&this._transport.send(c.quote(t))},r.version=t("./version"),r.CONNECTING=0,r.OPEN=1,r.CLOSING=2,r.CLOSED=3,r.prototype._receiveInfo=function(t,e){if(this._ir=null,!t)return void this._close(1002,"Cannot connect to server");this._rto=this.countRTO(e),this._transUrl=t.base_url?t.base_url:this.url,t=p.extend(t,this._urlInfo);var n=o.filterToEnabled(this._transportsWhitelist,t);this._transports=n.main,this._connect()},r.prototype._connect=function(){for(var t=this._transports.shift();t;t=this._transports.shift()){if(t.needBody&&(!n.document.body||"undefined"!=typeof n.document.readyState&&"complete"!==n.document.readyState&&"interactive"!==n.document.readyState))return this._transports.unshift(t),void h.attachEvent("load",this._connect.bind(this));var e=this._rto*t.roundTrips||5e3;this._transportTimeoutId=setTimeout(this._transportTimeout.bind(this),e);var r=f.addPath(this._transUrl,"/"+this._server+"/"+this._generateSessionId()),i=this._transportOptions[t.transportName],o=new t(r,this._transUrl,i);return o.on("message",this._transportMessage.bind(this)),o.once("close",this._transportClose.bind(this)),o.transportName=t.transportName,void(this._transport=o)}this._close(2e3,"All transports failed",!1)},r.prototype._transportTimeout=function(){this.readyState===r.CONNECTING&&this._transportClose(2007,"Transport timed out")},r.prototype._transportMessage=function(t){var e,n=this,r=t.slice(0,1),i=t.slice(1);switch(r){case"o":return void this._open();case"h":return void this.dispatchEvent(new y("heartbeat"))}if(i)try{e=u.parse(i)}catch(o){}if("undefined"!=typeof e)switch(r){case"a":Array.isArray(e)&&e.forEach(function(t){n.dispatchEvent(new x(t))});break;case"m":this.dispatchEvent(new x(e));break;case"c":Array.isArray(e)&&2===e.length&&this._close(e[0],e[1],!0)}},r.prototype._transportClose=function(t,e){return this._transport&&(this._transport.removeAllListeners(),this._transport=null,this.transport=null),i(t)||2e3===t||this.readyState!==r.CONNECTING?void this._close(t,e):void this._connect()},r.prototype._open=function(){this.readyState===r.CONNECTING?(this._transportTimeoutId&&(clearTimeout(this._transportTimeoutId),this._transportTimeoutId=null),this.readyState=r.OPEN,this.transport=this._transport.transportName,this.dispatchEvent(new y("open"))):this._close(1006,"Server lost session")},r.prototype._close=function(t,e,n){var i=!1;if(this._ir&&(i=!0,this._ir.close(),this._ir=null),this._transport&&(this._transport.close(),this._transport=null,this.transport=null),this.readyState===r.CLOSED)throw new Error("InvalidStateError: SockJS has already been closed");this.readyState=r.CLOSING,setTimeout(function(){this.readyState=r.CLOSED,i&&this.dispatchEvent(new y("error"));var o=new w("close");o.wasClean=n||!1,o.code=t||1e3,o.reason=e,this.dispatchEvent(o),this.onmessage=this.onclose=this.onerror=null}.bind(this),0)},r.prototype.countRTO=function(t){return t>100?4*t:300+t},e.exports=function(e){return o=d(e),t("./iframe-bootstrap")(r,e),r}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./event/close":2,"./event/event":4,"./event/eventtarget":5,"./event/trans-message":6,"./iframe-bootstrap":8,"./info-receiver":12,"./location":13,"./shims":15,"./utils/browser":44,"./utils/escape":45,"./utils/event":46,"./utils/log":48,"./utils/object":49,"./utils/random":50,"./utils/transport":51,"./utils/url":52,"./version":53,debug:void 0,inherits:54,json3:55,"url-parse":56}],15:[function(){"use strict";function t(t){var e=+t;return e!==e?e=0:0!==e&&e!==1/0&&e!==-(1/0)&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function e(t){return t>>>0}function n(){}var r,i=Array.prototype,o=Object.prototype,s=Function.prototype,a=String.prototype,u=i.slice,l=o.toString,c=function(t){return"[object Function]"===o.toString.call(t)},f=function(t){return"[object Array]"===l.call(t)},h=function(t){return"[object String]"===l.call(t)},d=Object.defineProperty&&function(){try{return Object.defineProperty({},"x",{}),!0}catch(t){return!1}}();r=d?function(t,e,n,r){!r&&e in t||Object.defineProperty(t,e,{configurable:!0,enumerable:!1,writable:!0,value:n})}:function(t,e,n,r){!r&&e in t||(t[e]=n)};var p=function(t,e,n){for(var i in e)o.hasOwnProperty.call(e,i)&&r(t,i,e[i],n)},v=function(t){if(null==t)throw new TypeError("can't convert "+t+" to object");return Object(t)};p(s,{bind:function(t){var e=this;if(!c(e))throw new TypeError("Function.prototype.bind called on incompatible "+e);for(var r=u.call(arguments,1),i=function(){if(this instanceof l){var n=e.apply(this,r.concat(u.call(arguments)));return Object(n)===n?n:this}return e.apply(t,r.concat(u.call(arguments)))},o=Math.max(0,e.length-r.length),s=[],a=0;o>a;a++)s.push("$"+a);var l=Function("binder","return function ("+s.join(",")+"){ return binder.apply(this, arguments); }")(i);return e.prototype&&(n.prototype=e.prototype,l.prototype=new n,n.prototype=null),l}}),p(Array,{isArray:f});var m=Object("a"),y="a"!==m[0]||!(0 in m),b=function(t){var e=!0,n=!0;return t&&(t.call("foo",function(t,n,r){"object"!=typeof r&&(e=!1)}),t.call([1],function(){n="string"==typeof this},"x")),!!t&&e&&n};p(i,{forEach:function(t){var e=v(this),n=y&&h(this)?this.split(""):e,r=arguments[1],i=-1,o=n.length>>>0;if(!c(t))throw new TypeError;for(;++i>>0;if(!r)return-1;var i=0;for(arguments.length>1&&(i=t(arguments[1])),i=i>=0?i:Math.max(0,r+i);r>i;i++)if(i in n&&n[i]===e)return i;return-1}},g);var w=a.split;2!=="ab".split(/(?:ab)*/).length||4!==".".split(/(.?)(.?)/).length||"t"==="tesst".split(/(s)*/)[1]||4!=="test".split(/(?:)/,-1).length||"".split(/.?/).length||".".split(/()()/).length>1?!function(){var t=void 0===/()??/.exec("")[1];a.split=function(n,r){var o=this;if(void 0===n&&0===r)return[];if("[object RegExp]"!==l.call(n))return w.call(this,n,r);var s,a,u,c,f=[],h=(n.ignoreCase?"i":"")+(n.multiline?"m":"")+(n.extended?"x":"")+(n.sticky?"y":""),d=0;for(n=new RegExp(n.source,h+"g"),o+="",t||(s=new RegExp("^"+n.source+"$(?!\\s)",h)),r=void 0===r?-1>>>0:e(r);(a=n.exec(o))&&(u=a.index+a[0].length,!(u>d&&(f.push(o.slice(d,a.index)),!t&&a.length>1&&a[0].replace(s,function(){for(var t=1;t1&&a.index=r)));)n.lastIndex===a.index&&n.lastIndex++;return d===o.length?(c||!n.test(""))&&f.push(""):f.push(o.slice(d)),f.length>r?f.slice(0,r):f}}():"0".split(void 0,0).length&&(a.split=function(t,e){return void 0===t&&0===e?[]:w.call(this,t,e)});var x=" \n\f\r \u2028\u2029",_="",E="["+x+"]",j=new RegExp("^"+E+E+"*"),T=new RegExp(E+E+"*$"),S=a.trim&&(x.trim()||!_.trim());p(a,{trim:function(){if(void 0===this||null===this)throw new TypeError("can't convert "+this+" to object");return String(this).replace(j,"").replace(T,"")}},S);var O=a.substr,C="".substr&&"b"!=="0b".substr(-1);p(a,{substr:function(t,e){return O.call(this,0>t&&(t=this.length+t)<0?0:t,e)}},C)},{}],16:[function(t,e){"use strict";e.exports=[t("./transport/websocket"),t("./transport/xhr-streaming"),t("./transport/xdr-streaming"),t("./transport/eventsource"),t("./transport/lib/iframe-wrap")(t("./transport/eventsource")),t("./transport/htmlfile"),t("./transport/lib/iframe-wrap")(t("./transport/htmlfile")),t("./transport/xhr-polling"),t("./transport/xdr-polling"),t("./transport/lib/iframe-wrap")(t("./transport/xhr-polling")),t("./transport/jsonp-polling")]},{"./transport/eventsource":20,"./transport/htmlfile":21,"./transport/jsonp-polling":23,"./transport/lib/iframe-wrap":26,"./transport/websocket":38,"./transport/xdr-polling":39,"./transport/xdr-streaming":40,"./transport/xhr-polling":41,"./transport/xhr-streaming":42}],17:[function(t,e){(function(n){"use strict";function r(t,e,n,r){var o=this;i.call(this),setTimeout(function(){o._start(t,e,n,r)},0)}var i=t("events").EventEmitter,o=t("inherits"),s=t("../../utils/event"),a=t("../../utils/url"),u=n.XMLHttpRequest;o(r,i),r.prototype._start=function(t,e,n,i){var o=this;try{this.xhr=new u}catch(l){}if(!this.xhr)return this.emit("finish",0,"no xhr support"),void this._cleanup();e=a.addQuery(e,"t="+ +new Date),this.unloadRef=s.unloadAdd(function(){o._cleanup(!0)});try{this.xhr.open(t,e,!0),this.timeout&&"timeout"in this.xhr&&(this.xhr.timeout=this.timeout,this.xhr.ontimeout=function(){o.emit("finish",0,""),o._cleanup(!1)})}catch(c){return this.emit("finish",0,""),void this._cleanup(!1)}if(i&&i.noCredentials||!r.supportsCORS||(this.xhr.withCredentials="true"),i&&i.headers)for(var f in i.headers)this.xhr.setRequestHeader(f,i.headers[f]);this.xhr.onreadystatechange=function(){if(o.xhr){var t,e,n=o.xhr;switch(n.readyState){case 3:try{e=n.status,t=n.responseText}catch(r){}1223===e&&(e=204),200===e&&t&&t.length>0&&o.emit("chunk",e,t);break;case 4:e=n.status,1223===e&&(e=204),(12005===e||12029===e)&&(e=0),o.emit("finish",e,n.responseText),o._cleanup(!1)}}};try{o.xhr.send(n)}catch(c){o.emit("finish",0,""),o._cleanup(!1)}},r.prototype._cleanup=function(t){if(this.xhr){if(this.removeAllListeners(),s.unloadDel(this.unloadRef),this.xhr.onreadystatechange=function(){},this.xhr.ontimeout&&(this.xhr.ontimeout=null),t)try{this.xhr.abort()}catch(e){}this.unloadRef=this.xhr=null}},r.prototype.close=function(){this._cleanup(!0)},r.enabled=!!u;var l=["Active"].concat("Object").join("X");!r.enabled&&l in n&&(u=function(){try{return new n[l]("Microsoft.XMLHTTP")}catch(t){return null}},r.enabled=!!new u);var c=!1;try{c="withCredentials"in new u}catch(f){}r.supportsCORS=c,e.exports=r}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../../utils/event":46,"../../utils/url":52,debug:void 0,events:3,inherits:54}],18:[function(t,e){(function(t){e.exports=t.EventSource}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],19:[function(t,e){(function(t){"use strict";var n=t.WebSocket||t.MozWebSocket;n&&(e.exports=function(t){return new n(t)})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],20:[function(t,e){"use strict";function n(t){if(!n.enabled())throw new Error("Transport created when disabled");i.call(this,t,"/eventsource",o,s)}var r=t("inherits"),i=t("./lib/ajax-based"),o=t("./receiver/eventsource"),s=t("./sender/xhr-cors"),a=t("eventsource");r(n,i),n.enabled=function(){return!!a},n.transportName="eventsource",n.roundTrips=2,e.exports=n},{"./lib/ajax-based":24,"./receiver/eventsource":29,"./sender/xhr-cors":35,eventsource:18,inherits:54}],21:[function(t,e){"use strict";function n(t){if(!i.enabled)throw new Error("Transport created when disabled");s.call(this,t,"/htmlfile",i,o)}var r=t("inherits"),i=t("./receiver/htmlfile"),o=t("./sender/xhr-local"),s=t("./lib/ajax-based");r(n,s),n.enabled=function(t){return i.enabled&&t.sameOrigin},n.transportName="htmlfile",n.roundTrips=2,e.exports=n},{"./lib/ajax-based":24,"./receiver/htmlfile":30,"./sender/xhr-local":37,inherits:54}],22:[function(t,e){"use strict";function n(t,e,r){if(!n.enabled())throw new Error("Transport created when disabled");o.call(this);var i=this;this.origin=a.getOrigin(r),this.baseUrl=r,this.transUrl=e,this.transport=t,this.windowId=c.string(8);var s=a.addPath(r,"/iframe.html")+"#"+this.windowId;this.iframeObj=u.createIframe(s,function(t){i.emit("close",1006,"Unable to load an iframe ("+t+")"),i.close()}),this.onmessageCallback=this._message.bind(this),l.attachEvent("message",this.onmessageCallback)}var r=t("inherits"),i=t("json3"),o=t("events").EventEmitter,s=t("../version"),a=t("../utils/url"),u=t("../utils/iframe"),l=t("../utils/event"),c=t("../utils/random");r(n,o),n.prototype.close=function(){if(this.removeAllListeners(),this.iframeObj){l.detachEvent("message",this.onmessageCallback);try{this.postMessage("c")}catch(t){}this.iframeObj.cleanup(),this.iframeObj=null,this.onmessageCallback=this.iframeObj=null}},n.prototype._message=function(t){if(a.isOriginEqual(t.origin,this.origin)){var e;try{e=i.parse(t.data)}catch(n){return}if(e.windowId===this.windowId)switch(e.type){case"s":this.iframeObj.loaded(),this.postMessage("s",i.stringify([s,this.transport,this.transUrl,this.baseUrl]));break;case"t":this.emit("message",e.data);break;case"c":var r;try{r=i.parse(e.data)}catch(n){return}this.emit("close",r[0],r[1]),this.close()}}},n.prototype.postMessage=function(t,e){this.iframeObj.post(i.stringify({windowId:this.windowId,type:t,data:e||""}),this.origin)},n.prototype.send=function(t){this.postMessage("m",t)},n.enabled=function(){return u.iframeEnabled},n.transportName="iframe",n.roundTrips=2,e.exports=n},{"../utils/event":46,"../utils/iframe":47,"../utils/random":50,"../utils/url":52,"../version":53,debug:void 0,events:3,inherits:54,json3:55}],23:[function(t,e){(function(n){"use strict";function r(t){if(!r.enabled())throw new Error("Transport created when disabled");o.call(this,t,"/jsonp",a,s)}var i=t("inherits"),o=t("./lib/sender-receiver"),s=t("./receiver/jsonp"),a=t("./sender/jsonp");i(r,o),r.enabled=function(){return!!n.document},r.transportName="jsonp-polling",r.roundTrips=1,r.needBody=!0,e.exports=r}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./lib/sender-receiver":28,"./receiver/jsonp":31,"./sender/jsonp":33,inherits:54}],24:[function(t,e){"use strict";function n(t){return function(e,n,r){var i={};"string"==typeof n&&(i.headers={"Content-type":"text/plain"});var s=o.addPath(e,"/xhr_send"),a=new t("POST",s,n,i);return a.once("finish",function(t){return a=null,200!==t&&204!==t?r(new Error("http status "+t)):void r()}),function(){a.close(),a=null;var t=new Error("Aborted");t.code=1e3,r(t)}}}function r(t,e,r,i){s.call(this,t,e,n(i),r,i)}var i=t("inherits"),o=t("../../utils/url"),s=t("./sender-receiver");i(r,s),e.exports=r},{"../../utils/url":52,"./sender-receiver":28,debug:void 0,inherits:54}],25:[function(t,e){"use strict";function n(t,e){i.call(this),this.sendBuffer=[],this.sender=e,this.url=t}var r=t("inherits"),i=t("events").EventEmitter;r(n,i),n.prototype.send=function(t){this.sendBuffer.push(t),this.sendStop||this.sendSchedule()},n.prototype.sendScheduleWait=function(){var t,e=this;this.sendStop=function(){e.sendStop=null,clearTimeout(t)},t=setTimeout(function(){e.sendStop=null,e.sendSchedule()},25)},n.prototype.sendSchedule=function(){var t=this;if(this.sendBuffer.length>0){var e="["+this.sendBuffer.join(",")+"]";this.sendStop=this.sender(this.url,e,function(e){t.sendStop=null,e?(t.emit("close",e.code||1006,"Sending error: "+e),t._cleanup()):t.sendScheduleWait()}),this.sendBuffer=[]}},n.prototype._cleanup=function(){this.removeAllListeners()},n.prototype.stop=function(){this._cleanup(),this.sendStop&&(this.sendStop(),this.sendStop=null)},e.exports=n},{debug:void 0,events:3,inherits:54}],26:[function(t,e){(function(n){"use strict";var r=t("inherits"),i=t("../iframe"),o=t("../../utils/object");e.exports=function(t){function e(e,n){i.call(this,t.transportName,e,n)}return r(e,i),e.enabled=function(e,r){if(!n.document)return!1;var s=o.extend({},r);return s.sameOrigin=!0,t.enabled(s)&&i.enabled()},e.transportName="iframe-"+t.transportName,e.needBody=!0,e.roundTrips=i.roundTrips+t.roundTrips-1,e.facadeTransport=t,e}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../../utils/object":49,"../iframe":22,inherits:54}],27:[function(t,e){"use strict";function n(t,e,n){i.call(this),this.Receiver=t,this.receiveUrl=e,this.AjaxObject=n,this._scheduleReceiver()}var r=t("inherits"),i=t("events").EventEmitter;r(n,i),n.prototype._scheduleReceiver=function(){var t=this,e=this.poll=new this.Receiver(this.receiveUrl,this.AjaxObject);e.on("message",function(e){t.emit("message",e)}),e.once("close",function(n,r){t.poll=e=null,t.pollIsClosing||("network"===r?t._scheduleReceiver():(t.emit("close",n||1006,r),t.removeAllListeners()))})},n.prototype.abort=function(){this.removeAllListeners(),this.pollIsClosing=!0,this.poll&&this.poll.abort()},e.exports=n},{debug:void 0,events:3,inherits:54}],28:[function(t,e){"use strict";function n(t,e,n,r,a){var u=i.addPath(t,e),l=this;o.call(this,t,n),this.poll=new s(r,u,a),this.poll.on("message",function(t){l.emit("message",t)}),this.poll.once("close",function(t,e){l.poll=null,l.emit("close",t,e),l.close()})}var r=t("inherits"),i=t("../../utils/url"),o=t("./buffered-sender"),s=t("./polling");r(n,o),n.prototype.close=function(){this.removeAllListeners(),this.poll&&(this.poll.abort(),this.poll=null),this.stop()},e.exports=n},{"../../utils/url":52,"./buffered-sender":25,"./polling":27,debug:void 0,inherits:54}],29:[function(t,e){"use strict";function n(t){i.call(this);var e=this,n=this.es=new o(t);n.onmessage=function(t){e.emit("message",decodeURI(t.data))},n.onerror=function(t){var r=2!==n.readyState?"network":"permanent";e._cleanup(),e._close(r)}}var r=t("inherits"),i=t("events").EventEmitter,o=t("eventsource");r(n,i),n.prototype.abort=function(){this._cleanup(),this._close("user")},n.prototype._cleanup=function(){var t=this.es;t&&(t.onmessage=t.onerror=null,t.close(),this.es=null)},n.prototype._close=function(t){var e=this;setTimeout(function(){e.emit("close",null,t),e.removeAllListeners()},200)},e.exports=n},{debug:void 0,events:3,eventsource:18,inherits:54}],30:[function(t,e){(function(n){"use strict";function r(t){a.call(this);var e=this;o.polluteGlobalNamespace(),this.id="a"+u.string(6),t=s.addQuery(t,"c="+decodeURIComponent(o.WPrefix+"."+this.id));var i=r.htmlfileEnabled?o.createHtmlfile:o.createIframe;n[o.WPrefix][this.id]={start:function(){e.iframeObj.loaded()},message:function(t){e.emit("message",t)},stop:function(){e._cleanup(),e._close("network")}},this.iframeObj=i(t,function(){e._cleanup(),e._close("permanent")})}var i=t("inherits"),o=t("../../utils/iframe"),s=t("../../utils/url"),a=t("events").EventEmitter,u=t("../../utils/random");i(r,a),r.prototype.abort=function(){this._cleanup(),this._close("user")},r.prototype._cleanup=function(){this.iframeObj&&(this.iframeObj.cleanup(),this.iframeObj=null),delete n[o.WPrefix][this.id]},r.prototype._close=function(t){this.emit("close",null,t),this.removeAllListeners()},r.htmlfileEnabled=!1;var l=["Active"].concat("Object").join("X");if(l in n)try{r.htmlfileEnabled=!!new n[l]("htmlfile")}catch(c){}r.enabled=r.htmlfileEnabled||o.iframeEnabled,e.exports=r}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../../utils/iframe":47,"../../utils/random":50,"../../utils/url":52,debug:void 0,events:3,inherits:54}],31:[function(t,e){(function(n){"use strict";function r(t){var e=this;l.call(this),i.polluteGlobalNamespace(),this.id="a"+o.string(6);var s=a.addQuery(t,"c="+encodeURIComponent(i.WPrefix+"."+this.id));n[i.WPrefix][this.id]=this._callback.bind(this),this._createScript(s),this.timeoutId=setTimeout(function(){e._abort(new Error("JSONP script loaded abnormally (timeout)"))},r.timeout)}var i=t("../../utils/iframe"),o=t("../../utils/random"),s=t("../../utils/browser"),a=t("../../utils/url"),u=t("inherits"),l=t("events").EventEmitter;u(r,l),r.prototype.abort=function(){if(n[i.WPrefix][this.id]){var t=new Error("JSONP user aborted read");t.code=1e3,this._abort(t)}},r.timeout=35e3,r.scriptErrorTimeout=1e3,r.prototype._callback=function(t){this._cleanup(),this.aborting||(t&&this.emit("message",t),this.emit("close",null,"network"),this.removeAllListeners())},r.prototype._abort=function(t){this._cleanup(),this.aborting=!0,this.emit("close",t.code,t.message),this.removeAllListeners()},r.prototype._cleanup=function(){if(clearTimeout(this.timeoutId),this.script2&&(this.script2.parentNode.removeChild(this.script2),this.script2=null),this.script){var t=this.script;t.parentNode.removeChild(t),t.onreadystatechange=t.onerror=t.onload=t.onclick=null,this.script=null}delete n[i.WPrefix][this.id]},r.prototype._scriptError=function(){var t=this;this.errorTimer||(this.errorTimer=setTimeout(function(){t.loadedOkay||t._abort(new Error("JSONP script loaded abnormally (onerror)"))},r.scriptErrorTimeout))},r.prototype._createScript=function(t){var e,r=this,i=this.script=n.document.createElement("script");if(i.id="a"+o.string(8),i.src=t,i.type="text/javascript",i.charset="UTF-8",i.onerror=this._scriptError.bind(this),i.onload=function(){r._abort(new Error("JSONP script loaded abnormally (onload)"))},i.onreadystatechange=function(){if(/loaded|closed/.test(i.readyState)){if(i&&i.htmlFor&&i.onclick){r.loadedOkay=!0;try{i.onclick()}catch(t){}}i&&r._abort(new Error("JSONP script loaded abnormally (onreadystatechange)"))
+ }},"undefined"==typeof i.async&&n.document.attachEvent)if(s.isOpera())e=this.script2=n.document.createElement("script"),e.text="try{var a = document.getElementById('"+i.id+"'); if(a)a.onerror();}catch(x){};",i.async=e.async=!1;else{try{i.htmlFor=i.id,i.event="onclick"}catch(a){}i.async=!0}"undefined"!=typeof i.async&&(i.async=!0);var u=n.document.getElementsByTagName("head")[0];u.insertBefore(i,u.firstChild),e&&u.insertBefore(e,u.firstChild)},e.exports=r}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"../../utils/browser":44,"../../utils/iframe":47,"../../utils/random":50,"../../utils/url":52,debug:void 0,events:3,inherits:54}],32:[function(t,e){"use strict";function n(t,e){i.call(this);var n=this;this.bufferPosition=0,this.xo=new e("POST",t,null),this.xo.on("chunk",this._chunkHandler.bind(this)),this.xo.once("finish",function(t,e){n._chunkHandler(t,e),n.xo=null;var r=200===t?"network":"permanent";n.emit("close",null,r),n._cleanup()})}var r=t("inherits"),i=t("events").EventEmitter;r(n,i),n.prototype._chunkHandler=function(t,e){if(200===t&&e)for(var n=-1;;this.bufferPosition+=n+1){var r=e.slice(this.bufferPosition);if(n=r.indexOf("\n"),-1===n)break;var i=r.slice(0,n);i&&this.emit("message",i)}},n.prototype._cleanup=function(){this.removeAllListeners()},n.prototype.abort=function(){this.xo&&(this.xo.close(),this.emit("close",null,"user"),this.xo=null),this._cleanup()},e.exports=n},{debug:void 0,events:3,inherits:54}],33:[function(t,e){(function(n){"use strict";function r(t){try{return n.document.createElement('