Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.openshift.booster; import io.openshift.booster.service.Store; import io.openshift.booster.service.impl.JdbcProductStore; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import io.vertx.rxjava.core.AbstractVerticle; import io.vertx.rxjava.core.http.HttpServer; import io.vertx.rxjava.core.http.HttpServerResponse; import io.vertx.rxjava.ext.jdbc.JDBCClient; import io.vertx.rxjava.ext.web.Router; import io.vertx.rxjava.ext.web.RoutingContext; import io.vertx.rxjava.ext.web.handler.BodyHandler; import io.vertx.rxjava.ext.web.handler.StaticHandler; import rx.Single; import java.util.NoSuchElementException; import static io.openshift.booster.Errors.error; public class CrudApplication extends AbstractVerticle { private Store store; @Override public void start() { // Create a router object. Router router = Router.router(vertx); // implement a basic REST CRUD mapping router.get("/api/fruits").handler(this::retrieveAll); router.get("/api/fruits/:id").handler(this::getOne); // enable parsing of request bodies router.route().handler(BodyHandler.create()); router.post("/api/fruits").handler(this::addOne); router.put("/api/fruits/:id").handler(this::updateOne); router.delete("/api/fruits/:id").handler(this::deleteOne); // health check router.get("/health").handler(rc -> rc.response().end("OK")); // web interface router.get().handler(StaticHandler.create()); // Create a JDBC client JDBCClient jdbc = JDBCClient.createShared(vertx, new JsonObject() .put("url", "jdbc:postgresql://" + getEnv("MY_DATABASE_SERVICE_HOST", "localhost") + ":5432/my_data") .put("driver_class", "org.postgresql.Driver").put("user", getEnv("DB_USERNAME", "luke")) .put("password", getEnv("DB_PASSWORD", "secret"))); DBInitHelper.initDatabase(vertx, jdbc).andThen(initHttpServer(router, jdbc)).subscribe( (http) -> System.out.println("Server ready on port " + http.actualPort()), Throwable::printStackTrace); } private Single<HttpServer> initHttpServer(Router router, JDBCClient client) { store = new JdbcProductStore(client); // Create the HTTP server and pass the "accept" method to the request handler. return vertx.createHttpServer().requestHandler(router::accept).rxListen(8080); } private void retrieveAll(RoutingContext ctx) { HttpServerResponse response = ctx.response().putHeader("Content-Type", "application/json"); JsonArray res = new JsonArray(); store.readAll().subscribe(res::add, err -> error(ctx, 400, err), () -> response.end(res.encodePrettily())); } private void getOne(RoutingContext ctx) { HttpServerResponse response = ctx.response().putHeader("Content-Type", "application/json"); long id = getId(ctx); if (id == -1) { error(ctx, 400, "invalid id"); return; } store.read(id).subscribe(json -> response.end(json.encodePrettily()), err -> { if (err instanceof NoSuchElementException) { error(ctx, 404, err); } else if (err instanceof IllegalArgumentException) { error(ctx, 400, err); } else { error(ctx, 500, err); } }); } private void addOne(RoutingContext ctx) { JsonObject item; try { item = ctx.getBodyAsJson(); } catch (RuntimeException e) { error(ctx, 400, "invalid payload"); return; } if (item == null) { error(ctx, 400, "invalid payload"); return; } store.create(item) .subscribe(json -> ctx.response().putHeader("Location", "/api/fruits/" + json.getInteger("id")) .putHeader("Content-Type", "application/json").setStatusCode(201) .end(json.encodePrettily()), err -> writeError(ctx, err)); } private void updateOne(RoutingContext ctx) { long id = getId(ctx); if (id == -1) { error(ctx, 404, "unknown fruit"); return; } JsonObject item; try { item = ctx.getBodyAsJson(); } catch (RuntimeException e) { error(ctx, 400, "invalid payload"); return; } if (item == null) { error(ctx, 400, "invalid payload"); return; } store.update(id, item).subscribe(() -> ctx.response().putHeader("Content-Type", "application/json") .setStatusCode(200).end(item.put("id", id).encodePrettily()), err -> writeError(ctx, err)); } private void writeError(RoutingContext ctx, Throwable err) { if (err instanceof NoSuchElementException) { error(ctx, 404, err); } else if (err instanceof IllegalArgumentException) { error(ctx, 422, err); } else { error(ctx, 409, err); } } private void deleteOne(RoutingContext ctx) { long id = getId(ctx); if (id == -1) { error(ctx, 404, "unknown product"); return; } store.delete(id).subscribe(() -> ctx.response().setStatusCode(204).end(), err -> { if (err instanceof NoSuchElementException) { error(ctx, 404, err); } else { error(ctx, 400, err); } }); } private long getId(RoutingContext ctx) { try { return Long.parseLong(ctx.pathParam("id")); } catch (NumberFormatException e) { return -1; } } private String getEnv(String key, String dv) { String s = System.getenv(key); if (s == null) { return dv; } return s; } }