All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hawkular.HandlersManager Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014-2017 Red Hat, Inc. and/or its affiliates
 * and other contributors as indicated by the @author tags.
 *
 * Licensed 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
 *
 *    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 org.hawkular;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.hawkular.commons.log.MsgLogger;
import org.hawkular.commons.log.MsgLogging;
import org.hawkular.commons.properties.HawkularProperties;
import org.hawkular.handlers.BaseApplication;
import org.hawkular.handlers.RestEndpoint;
import org.hawkular.handlers.RestHandler;

import io.vertx.core.Vertx;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.CorsHandler;

/**
 * @author Jay Shaughnessy
 * @author Lucas Ponce
 */
public class HandlersManager {
    private static final MsgLogger log = MsgLogging.getMsgLogger(HandlersManager.class);

    // For pattern examples see:
    // github.com/vert-x3/vertx-web/blob/master/vertx-web/src/test/java/io/vertx/ext/web/handler/CORSHandlerTest.java
    private static final String CORS_ORIGIN_PATTERN = "hawkular.cors-origin-pattern";
    private static final String CORS_ORIGIN_PATTERN_DEFAULT = "*";
    private static final String CORS_HEADERS = "hawkular.cors-headers";
    private static final String CORS_HEADERS_DEFAULT = "origin,accept,content-type,hawkular-tenant";
    private static final String CORS_METHODS = "hawkular.cors-methods";
    private static final String CORS_METHODS_DEFAULT = "GET,POST,PUT,PATCH,DELETE,OPTIONS,HEAD";

    private Router router;
    private Map applications = new HashMap<>();
    private Map> applicationsClasses = new HashMap<>();
    private Map endpoints = new HashMap<>();
    private Map> endpointsClasses = new HashMap<>();
    private ClassLoader cl = Thread.currentThread().getContextClassLoader();
    private String corsAllowedOriginPattern;
    private String corsHeaders;
    private String corsMethods;

    public HandlersManager(Vertx vertx) {
        this.router = Router.router(vertx);
        corsAllowedOriginPattern = HawkularProperties.getProperty(CORS_ORIGIN_PATTERN, CORS_ORIGIN_PATTERN_DEFAULT);
        corsHeaders = HawkularProperties.getProperty(CORS_HEADERS, CORS_HEADERS_DEFAULT);
        corsMethods = HawkularProperties.getProperty(CORS_METHODS, CORS_METHODS_DEFAULT);
    }

    public void start() {
        try {
            scan();
            log.info("Rest Handlers scan finished");
            applicationsClasses.entrySet().stream().forEach(appClass -> {
                try {
                    BaseApplication app = appClass.getValue().newInstance();
                    log.infof("Starting App [ %s ] - BaseUrl [ %s ]", appClass.getKey(), app.baseUrl());
                    app.start();
                    applications.put(appClass.getKey(), app);
                } catch (Exception e) {
                    log.errorf(e, "Error loading App [%s]", appClass);
                }
            });
            endpointsClasses.entrySet().stream().forEach(endpoint -> {
                try {
                    String endpointPackage = endpoint.getValue().getPackage().getName();

                    BaseApplication app = null;
                    while (endpointPackage.length() != 0) {
                        app = applications.get(endpointPackage);
                        if (app != null) {
                            break;
                        }

                        if (endpointPackage.lastIndexOf('.') == -1) {
                            break;
                        }

                        endpointPackage = endpointPackage.substring(0, endpointPackage.lastIndexOf('.'));
                    }

                    if (app == null) {
                        log.errorf("Handler [%s] does not belong to an application.", endpoint.getValue().getName());
                        return;
                    }

                    String baseUrl = app.baseUrl();
                    router.route(baseUrl + "*").handler(BodyHandler.create());

                    if (corsAllowedOriginPattern.length() > 0) {
                        CorsHandler corsHandler = CorsHandler.create(corsAllowedOriginPattern);
                        if (corsHeaders.length() > 0) {
                            corsHandler.allowedHeaders(extractCorsHeaders(corsHeaders));
                        }
                        if (corsMethods.length() > 0) {
                            corsHandler.allowedMethods(extractCorsMethods(corsMethods));
                        }
                        router.route(baseUrl + "*").handler(corsHandler);
                    }
                    RestHandler handler = endpoint.getValue().newInstance();
                    handler.initRoutes(baseUrl, router);
                    endpoints.put(endpoint.getKey(), handler);
                    log.infof("Starting on [ %s ]: Endpoint [ %s ] - Handler [ %s ]", baseUrl, endpoint.getKey().getEndpoint(), endpoint.getValue().getName());
                } catch (Exception e) {
                    log.errorf(e, "Error loading Handler [%s]", endpoint);
                }
            });
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

    public void handle(HttpServerRequest req) {
        log.debugf("%s %s %s", req.method().name(), req.path(), req.params());
        router.accept(req);
    }

    public void stop() {
        applications.entrySet().stream().forEach(application -> application.getValue().stop());
    }

    private void scan() throws IOException {
        List pathsToProcess = new ArrayList<>();

        ClassLoader classLoader = getClass().getClassLoader();
        URL[] classLoaderPaths = ((URLClassLoader) classLoader).getURLs();
        for (int i = 0; i < classLoaderPaths.length; i++) {
            pathsToProcess.add(classLoaderPaths[i].getPath());
        }

        String[] classpath = System.getProperty("java.class.path").split(":");
        for (int i = 0; i < classpath.length; i++) {
            pathsToProcess.add(classpath[i]);
        }

        for (String fullFileName : pathsToProcess) {
            File file = new File(fullFileName);
            String fileName = file.getName();
            if (file.isDirectory()) {
                processDirectory(fullFileName, fullFileName.length());
            } else if (fileName.contains("hawkular") && fileName.endsWith("jar")) {
                processArchive(fullFileName);
            }
        }
    }

    private void processArchive(String path) throws IOException, FileNotFoundException {
        log.debug(path);
        try (ZipInputStream zip = new ZipInputStream(new FileInputStream(path))) {
            for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
                if (!entry.isDirectory() && entry.getName().endsWith(".class")
                        && entry.getName().contains("hawkular")) {
                    processClass(entry.getName());
                }
            }
        }
    }

    public void processDirectory(String directoryName, int rootLength) {
        log.debug(directoryName);
        File directory = new File(directoryName);
        for (File file : directory.listFiles()) {
            if (file.isFile() && file.getName().endsWith(".class")) {
                processClass(file.getPath().substring(rootLength));
            } else if (file.isDirectory()) {
                processDirectory(file.getAbsolutePath(), rootLength);
            }
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private void processClass(String className) {
        className = className.replace('/', '.'); // including ".class"
        className = className.substring(0, className.length() - 6);
        log.debug(className);
        try {
            Class clazz = cl.loadClass(className);
            Class[] interfaces = clazz.getInterfaces();
            for (int j = 0; j < interfaces.length; j++) {
                if (interfaces[j].equals(BaseApplication.class)) {
                    String appName = clazz.getPackage().getName();
                    applicationsClasses.put(appName, clazz);
                }
            }
            if (clazz.isAnnotationPresent(RestEndpoint.class)) {
                RestEndpoint endpoint = (RestEndpoint)clazz.getAnnotation(RestEndpoint.class);
                for (int j=0; j extractCorsHeaders(String corsHeaders) {
        Set headers = new HashSet<>();
        if (corsHeaders != null && corsHeaders.length() > 0) {
            String[] splitted = corsHeaders.split(",");
            for (int i = 0; i < splitted.length; i++) {
                headers.add(splitted[i]);
            }
        }
        return headers;
    }

    private Set extractCorsMethods(String corsMethods) {
        Set methods = new HashSet<>();
        if (corsMethods != null && corsMethods.length() > 0) {
            String[] splitted = corsMethods.split(",");
            for (int i = 0; i < splitted.length; i++) {
                try {
                    methods.add(HttpMethod.valueOf(splitted[i]));
                } catch (Exception e) {
                    log.warnf("Skipping unknown CORS method [%s]: %s", splitted[i], e.getMessage());
                }
            }
        }
        return methods;
    }

    public static class EndpointKey {
        private String endpoint;
        private String className;

        public EndpointKey(String endpoint, String className) {
            this.endpoint = endpoint;
            this.className = className;
        }

        public String getEndpoint() {
            return endpoint;
        }

        public void setEndpoint(String endpoint) {
            this.endpoint = endpoint;
        }

        public String getClassName() {
            return className;
        }

        public void setClassName(String className) {
            this.className = className;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            EndpointKey that = (EndpointKey) o;

            if (endpoint != null ? !endpoint.equals(that.endpoint) : that.endpoint != null) return false;
            return className != null ? className.equals(that.className) : that.className == null;
        }

        @Override
        public int hashCode() {
            int result = endpoint != null ? endpoint.hashCode() : 0;
            result = 31 * result + (className != null ? className.hashCode() : 0);
            return result;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy