com.hpe.sw.cms.verticle.ApiVerticle.java Source code

Java tutorial

Introduction

Here is the source code for com.hpe.sw.cms.verticle.ApiVerticle.java

Source

/**
 * (c)Copyright[2016]Hewlett Packard Enterprise Development LP
 * Licensed under the Apache License,Version2.0(the"License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 * 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 com.hpe.sw.cms.verticle;

import com.hpe.sw.cms.store.Image;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.Message;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.FileUpload;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Set;
import java.util.zip.GZIPInputStream;

/**
 * API Verticle exposes a number of Restful endpoint
 *
 * @author keke
 * @author dmb
 */
public class ApiVerticle extends AbstractVerticle {
    private static final Logger LOG = LoggerFactory.getLogger(ApiVerticle.class);

    @Override
    public void start() throws Exception {
        super.start();
        HttpServer server = vertx.createHttpServer();
        Router mainRouter = Router.router(vertx);
        Router restApi = Router.router(vertx);
        mainRouter.mountSubRouter("/api", restApi);
        setUpApiRouter(restApi);
        server.requestHandler(mainRouter::accept).listen(8080);
    }

    private void setUpApiRouter(Router restApi) {
        restApi.route().handler(BodyHandler.create());
        //end point which receives Docker Registry events
        restApi.post("/registry/event").consumes("application/vnd.docker.distribution.events.v1+json")
                .handler(registryEventHandler());
        //end point which provides image list ; images?timestamp=timestamp , url to get images after timestamp ;images?id=imageid , url to get images with param imageid.
        restApi.get("/images").produces("application/json").handler(imagesHandler());
        //images/scan?host=${host}&name=${name}&tag=${tag} for downloading scan file, /images/enrich?host=${host}&name=${name}&tag=${tag} for downloading enrich file.
        restApi.get("/images/:id/:fileCategory").handler(downloadHandler());
        restApi.get("/images/:fileCategory").handler(downloadHandler());
        //_scanfile?host=${host}&name=${name}&tag=${tag}&imageId={imageId} for successful scanning, _scanfile?host=${host}&name=${name}&tag=${tag}&imageId=0&errorMsg=${MESSAGE} for failed scanning.
        restApi.post("/_scanfile").handler(uploadHandler());
    }

    /**
     * Handler to receive POST /_scanfile.
     *
     * @return
     */
    private Handler<RoutingContext> uploadHandler() {
        return routingContext -> {
            int resposeCode = 201;
            String resposeMsg = "OK";
            String host = routingContext.request().getParam(Image.HOST);
            String name = routingContext.request().getParam(Image.NAME);
            String tag = routingContext.request().getParam(Image.TAG);
            String imageid = routingContext.request().getParam(Image.IMAGE_ID);
            String errorMsg = routingContext.request().getParam("errorMsg");
            JsonObject upFile = new JsonObject();
            upFile.put(Image.HOST, host);
            upFile.put(Image.NAME, name);
            upFile.put(Image.TAG, tag);
            if (errorMsg != null && "0".equals(imageid)) {
                upFile.put(Image.IS_SCANNED_FAILED, true);
                LOG.error("scanfile uploaded failed " + Image.getImageKey(upFile) + " with error message "
                        + errorMsg);
            } else {
                Set<FileUpload> upFiles = routingContext.fileUploads();
                FileUpload upF = upFiles.iterator().next();
                ByteArrayOutputStream out = null;
                BufferedInputStream in = null;
                upFile.put(Image.IMAGE_ID, imageid);
                upFile.put(Image.IS_SCANNED_FAILED, false);
                try {
                    File file = new File(upF.uploadedFileName());
                    in = new BufferedInputStream(new FileInputStream(file));
                    out = new ByteArrayOutputStream();
                    IOUtils.copy(in, out);
                    upFile.put(Image.SCANNED_FILE, out.toByteArray());
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        in.close();
                        out.close();
                    } catch (IOException e) {
                        upFile.put(Image.IS_SCANNED_FAILED, true);
                        resposeCode = 500;
                        resposeMsg = "Error happens when in reading file";
                        LOG.error(resposeMsg, e);
                    }
                }
                LOG.debug("scanfile uploaded " + Image.getImageKey(upFile));
            }
            routingContext.response().setStatusCode(resposeCode).end(resposeMsg);
            getVertx().eventBus().publish(Events.SCANFILE_UPLOADED.name(), upFile);
        };
    }

    @Override
    public void stop() throws Exception {
        super.stop();
    }

    /**
     * Handler to handle GET /images/:id request. Response is the image scan files (with/without enrich).
     *
     * @return
     */
    private Handler<RoutingContext> downloadHandler() {
        return routingContext -> {
            String category = routingContext.request().getParam("fileCategory");
            JsonObject params = new JsonObject();
            if (routingContext.request().getParam("id") != null) {
                params.put(Image.IMAGE_ID, routingContext.request().getParam("id"));
            } else {
                params.put(Image.HOST, routingContext.request().getParam(Image.HOST));
                params.put(Image.NAME, routingContext.request().getParam(Image.NAME));
                params.put(Image.TAG, routingContext.request().getParam(Image.TAG));
            }
            vertx.eventBus().send(Events.DOWNLOAD_FILE.name(), params, event -> {
                if (event.succeeded() && event.result() != null) {
                    Message msg = event.result();
                    JsonObject file = (JsonObject) msg.body();
                    routingContext.response().setChunked(true);
                    if (file == null) {
                        routingContext.response().setStatusCode(404).end("There is no image  found.");
                        return;
                    }
                    if ("enrich".equals(category) && file.getBinary(Image.ENRICHED_FILE) != null) {
                        String fileName = file.getString(Image.HOST) + "___" + file.getString(Image.NAME) + "___"
                                + file.getString(Image.IMAGE_ID) + ".xsf";
                        routingContext.response().putHeader("Content-Disposition",
                                "attachment; filename = " + fileName);
                        Buffer buffer = Buffer.buffer(file.getBinary(Image.ENRICHED_FILE));
                        routingContext.response().end(buffer);
                    } else if ("enrich_xml".equals(category) && file.getBinary(Image.SCANNED_FILE) != null) {
                        routingContext.response().end(decompressGzip(file.getBinary(Image.ENRICHED_FILE)));
                    } else if ("scan".equals(category) && file.getBinary(Image.SCANNED_FILE) != null) {
                        String fileName = file.getString(Image.HOST) + "___" + file.getString(Image.NAME) + "___"
                                + file.getString(Image.IMAGE_ID) + ".xsf";
                        routingContext.response().putHeader("Content-Disposition",
                                "attachment; filename = " + fileName);
                        Buffer buffer = Buffer.buffer(file.getBinary(Image.SCANNED_FILE));
                        routingContext.response().end(buffer);
                    } else if ("scan_xml".equals(category) && file.getBinary(Image.SCANNED_FILE) != null) {
                        routingContext.response().end(decompressGzip(file.getBinary(Image.SCANNED_FILE)));
                    }
                } else if (event.result() == null) {
                    routingContext.response().setStatusCode(404).end("There is no image  found.");
                } else {
                    routingContext.response().setStatusCode(500).end("Server has error.");
                }
            });
        };
    }

    /**
     * decompress gzip to string
     * @param gzip byte[]
     * @return
     */
    private String decompressGzip(byte[] gzip) {
        GZIPInputStream gZIPInputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bf = null;
        try {
            gZIPInputStream = new GZIPInputStream(new ByteArrayInputStream(gzip));
            inputStreamReader = new InputStreamReader(gZIPInputStream);
            bf = new BufferedReader(inputStreamReader);
            StringBuffer outStr = new StringBuffer();
            String line;
            while ((line = bf.readLine()) != null) {
                outStr.append(line);
            }
            return outStr.toString();
        } catch (Exception e) {
            return "failed in decompressGzip with error:" + e.getMessage();
        } finally {
            try {
                bf.close();
                inputStreamReader.close();
                gZIPInputStream.close();
            } catch (Throwable t) {
                return "failed in decompressGzip with error:" + t.getMessage();
            }
        }
    }

    /**
     * Handler to handle GET /images request. The response is a list of images
     *
     * @return
     */
    private Handler<RoutingContext> imagesHandler() {
        return routingContext -> {
            String timestamp = routingContext.request().getParam("timestamp");
            String id = routingContext.request().getParam("id");
            String include = routingContext.request().getParam("include");
            JsonObject param = new JsonObject();
            if (timestamp != null) {
                param.put("timestamp", timestamp);
            }
            if (id != null) {
                param.put("imageid", id);
            }
            if (include != null) {
                param.put("include", include);
            }
            getVertx().eventBus().send(Events.GET_IMAGES.name(), param, event -> {
                if (event.succeeded() && event.result() != null) {
                    Message msg = event.result();
                    JsonArray updates = (JsonArray) msg.body();
                    HttpServerResponse response = routingContext.response();
                    if (updates.size() == 0) {
                        response.end("There is no image found.");
                    } else {
                        response.end(updates.toString());
                    }
                } else if (event.result() == null) {
                    routingContext.response().setStatusCode(404).end("There is no image found.");
                } else {
                    routingContext.response().setStatusCode(500).end("Server has error.");
                }
            });
        };
    }

    /**
     * Handler to handle Docker Registry event
     *
     * @return handler context
     */
    private Handler<RoutingContext> registryEventHandler() {
        return routingContext -> {
            JsonObject body = routingContext.getBodyAsJson();
            LOG.info("Docker Registry events received from {}", routingContext.request().getParam("registry"));
            JsonArray events = body.getJsonArray("events");
            JsonArray updated = new JsonArray();
            JsonArray deleted = new JsonArray();
            events.forEach(e -> {
                JsonObject event = (JsonObject) e;
                if (event.getString("action").equals("push")) {
                    JsonObject obj = createObj(event);
                    if (obj != null) {
                        updated.add(obj);
                    }
                } else if (event.getString("action").equals("delete")) {
                    JsonObject obj = createObj(event);
                    if (obj != null) {
                        deleted.add(obj);
                    }
                }
            });
            if (updated.size() != 0)
                vertx.eventBus().publish(Events.EVENT_IMAGES_UPDATED.name(), updated);
            if (deleted.size() != 0) //TODO
                vertx.eventBus().publish(Events.EVENT_IMAGES_DELETED.name(), deleted);
            //Always return 200 OK.
            routingContext.response().setStatusCode(200).end("OK");

        };
    }

    private JsonObject createObj(JsonObject event) {
        try {
            JsonObject image = new JsonObject();
            String timestamp = event.getString("timestamp");
            if (timestamp != null && timestamp.length() > 19) {
                timestamp = timestamp.substring(0, 10) + " " + timestamp.substring(11, 19);
                image.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(timestamp).getTime());
            }
            String url = event.getJsonObject("target").getString("url");
            image.put("name", event.getJsonObject("target").getString("repository"));
            image.put("host", event.getJsonObject("request").getString("host"));
            image.put(Image.EVENT_URL, url);
            return image;
        } catch (Exception e) {
            LOG.error("Error in reading event to object ", e);
            return null;
        }
    }
}