package io.vertx.example.web.angular_realtime;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.eventbus.Message;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.example.util.Runner;
import io.vertx.ext.auth.AuthProvider;
import io.vertx.ext.auth.shiro.ShiroAuth;
import io.vertx.ext.auth.shiro.ShiroAuthRealmType;
import io.vertx.ext.mongo.MongoClient;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.*;
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 io.vertx.ext.web.sstore.LocalSessionStore;
import java.util.LinkedList;
import java.util.List;
/*
* @author <a href="mailto:pmlopes@gmail.com">Paulo Lopes</a>
*/
public class Server extends AbstractVerticle {
// Convenience method so you can run it in your IDE
public static void main(String[] args) {
Runner.runExample(Server.class);
}
private MongoClient mongo;
@Override
public void start() throws Exception {
// Create a mongo client using all defaults (connect to localhost and default port) using the database name "demo".
mongo = MongoClient.createShared(vertx, new JsonObject().put("db_name", "demo"));
// the load function just populates some data on the storage
loadData(mongo);
// the app works 100% realtime
vertx.eventBus().consumer("vtoons.listAlbums", this::listAlbums);
vertx.eventBus().consumer("vtoons.placeOrder", this::placeOrder);
Router router = Router.router(vertx);
// We need cookies and sessions
router.route().handler(CookieHandler.create());
router.route().handler(BodyHandler.create());
router.route().handler(SessionHandler.create(LocalSessionStore.create(vertx)));
// Simple auth service which uses a properties file for user/role info
AuthProvider authProvider = ShiroAuth.create(vertx, ShiroAuthRealmType.PROPERTIES, new JsonObject());
// We need a user session handler too to make sure the user is stored in the session between requests
router.route().handler(UserSessionHandler.create(authProvider));
router.post("/login").handler(ctx -> {
JsonObject credentials = ctx.getBodyAsJson();
if (credentials == null) {
// bad request
ctx.fail(400);
return;
}
// use the auth handler to perform the authentication for us
authProvider.authenticate(credentials, login -> {
// error handling
if (login.failed()) {
// forbidden
ctx.fail(403);
return;
}
ctx.setUser(login.result());
ctx.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json").end("{}");
});
});
router.route("/eventbus/*").handler(ctx -> {
// we need to be logged in
if (ctx.user() == null) {
ctx.fail(403);
} else {
ctx.next();
}
});
// Allow outbound traffic to the vtoons addresses
BridgeOptions options = new BridgeOptions()
// this is the public store allowed inbound
.addInboundPermitted(new PermittedOptions()
.setAddress("vtoons.listAlbums"))
// this is the login inbound message
.addInboundPermitted(new PermittedOptions()
.setAddress("vtoons.login"))
// this is the authenticated place orders inbound
.addInboundPermitted(new PermittedOptions()
.setAddress("vtoons.placeOrder")
.setRequiredAuthority("place_order"))
// all outbound messages are permitted
.addOutboundPermitted(new PermittedOptions());
router.route("/eventbus/*").handler(SockJSHandler.create(vertx).bridge(options));
// Serve the static resources
router.route().handler(StaticHandler.create());
vertx.createHttpServer().requestHandler(router::accept).listen(8080);
}
private void listAlbums(Message<JsonObject> msg) {
// issue a find command to mongo to fetch all documents from the "albums" collection.
mongo.find("albums", new JsonObject(), lookup -> {
// error handling
if (lookup.failed()) {
msg.fail(500, lookup.cause().getMessage());
return;
}
// now convert the list to a JsonArray because it will be easier to encode the final object as the response.
final JsonArray json = new JsonArray();
for (JsonObject o : lookup.result()) {
json.add(o);
}
msg.reply(json);
});
}
private void placeOrder(Message<JsonObject> msg) {
mongo.save("orders", msg.body(), save -> {
// error handling
if (save.failed()) {
msg.fail(500, save.cause().getMessage());
return;
}
msg.reply(new JsonObject());
});
}
private void loadData(MongoClient db) {
db.dropCollection("albums", drop -> {
if (drop.failed()) {
throw new RuntimeException(drop.cause());
}
List<JsonObject> albums = new LinkedList<>();
albums.add(new JsonObject()
.put("artist", "The Wurzels")
.put("genre", "Scrumpy and Western")
.put("title", "I Am A Cider Drinker")
.put("price", 0.99));
albums.add(new JsonObject()
.put("artist", "Vanilla Ice")
.put("genre", "Hip Hop")
.put("title", "Ice Ice Baby")
.put("price", 0.01));
albums.add(new JsonObject()
.put("artist", "Ena Baga")
.put("genre", "Easy Listening")
.put("title", "The Happy Hammond")
.put("price", 0.50));
albums.add(new JsonObject()
.put("artist", "The Tweets")
.put("genre", "Bird related songs")
.put("title", "The Birdy Song")
.put("price", 1.20));
for (JsonObject album : albums) {
db.insert("albums", album, res -> {
System.out.println("inserted " + album.encode());
});
}
});
}
}