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

fathom.rest.controller.ControllerRegistrar Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
/*
 * Copyright (C) 2015 the original author or authors.
 *
 * 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 fathom.rest.controller;

import com.google.common.base.Joiner;
import com.google.inject.Inject;
import com.google.inject.Injector;
import fathom.conf.Settings;
import fathom.rest.RouteRegistration;
import fathom.utils.ClassUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ro.pippo.core.util.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Collects annotated controller routes.
 *
 * @author James Moger
 */
public class ControllerRegistrar extends ControllerScanner {

    private static final Logger log = LoggerFactory.getLogger(ControllerRegistrar.class);

    private final Injector injector;

    private final List routeRegistrations;

    @Inject
    public ControllerRegistrar(Injector injector, Settings settings) {
        super(settings);
        this.injector = injector;
        this.routeRegistrations = new ArrayList<>();
    }

    public final void init(Package... packages) {
        List names = new ArrayList<>();
        for (Package pkg : packages) {
            names.add(pkg.getName());
        }
        init(names.toArray(new String[names.size()]));
    }

    /**
     * Scans, identifies, and registers annotated controller methods for the
     * current runtime settings.
     *
     * @param packageNames
     */
    public final void init(String... packageNames) {

        Collection> classes = discoverClasses(packageNames);
        if (classes.isEmpty()) {
            log.warn("No annotated controllers found in package(s) '{}'", Arrays.toString(packageNames));
            return;
        }

        log.debug("Found {} controller classes in {} package(s)", classes.size(), packageNames.length);

        init(classes);
    }

    /**
     * Register all methods in the specified controller classes.
     *
     * @param controllers
     */
    public final void init(Class... controllers) {
        List> classes = Arrays.asList(controllers);
        init(classes);
    }

    private final void init(Collection> classes) {
        Map> discoveredMethods = discoverMethods(classes);
        if (discoveredMethods.isEmpty()) {
            // if we are using the registrar we expect to discover controllers!
            log.warn("No annotated controller methods found in classes(s) '{}'", classes);
            return;
        }

        log.debug("Found {} annotated controller method(s)", discoveredMethods.size());

        registerControllerMethods(discoveredMethods);

        log.debug("Added {} annotated routes from '{}'", routeRegistrations.size(), classes);
    }

    /**
     * Return the collected route registrations.
     *
     * @return the route registrations
     */
    public List getRouteRegistrations() {
        return routeRegistrations;
    }

    /**
     * Register the controller methods as Routes.
     *
     * @param discoveredMethods
     */
    private void registerControllerMethods(Map> discoveredMethods) {

        Collection methods = sortMethods(discoveredMethods.keySet());

        Map, Set> controllers = new HashMap<>();
        for (Method method : methods) {
            Class controllerClass = (Class) method.getDeclaringClass();
            if (!controllers.containsKey(controllerClass)) {
                Set paths = collectPaths(controllerClass);
                controllers.put(controllerClass, paths);
            }

            Class httpMethodAnnotationClass = discoveredMethods.get(method);
            Annotation httpMethodAnnotation = method.getAnnotation(httpMethodAnnotationClass);

            String httpMethod = httpMethodAnnotation.annotationType().getAnnotation(HttpMethod.class).value();
            String[] methodPaths = ClassUtil.executeDeclaredMethod(httpMethodAnnotation, "value");

            Set controllerPaths = controllers.get(controllerClass);
            if (controllerPaths.isEmpty()) {
                // add an empty string to allow controllerPaths iteration
                controllerPaths.add("");
            }

            for (String controllerPath : controllerPaths) {

                if (methodPaths.length == 0) {
                    // method does not specify a path, inherit from controller
                    String fullPath = StringUtils.addStart(StringUtils.removeEnd(controllerPath, "/"), "/");
                    ControllerHandler handler = new ControllerHandler(injector, controllerClass, method.getName());
                    handler.validateMethodArgs(fullPath);

                    RouteRegistration registration = new RouteRegistration(httpMethod, fullPath, handler);
                    configureRegistration(registration, method);
                    routeRegistrations.add(registration);
                } else {
                    // method specifies one or more paths, concatenate with controller paths
                    for (String methodPath : methodPaths) {
                        String path = Joiner.on("/").skipNulls().join(StringUtils.removeEnd(controllerPath, "/"), StringUtils.removeStart(methodPath, "/"));
                        String fullPath = StringUtils.addStart(StringUtils.removeEnd(path, "/"), "/");

                        ControllerHandler handler = new ControllerHandler(injector, controllerClass, method.getName());
                        handler.validateMethodArgs(fullPath);

                        RouteRegistration registration = new RouteRegistration(httpMethod, fullPath, handler);
                        configureRegistration(registration, method);
                        routeRegistrations.add(registration);
                    }
                }

            }

        }
    }

    private void configureRegistration(RouteRegistration registration, Method method) {
        // specify optional route name
        if (method.isAnnotationPresent(Named.class)) {
            Named named = method.getAnnotation(Named.class);
            registration.setName(named.value());
        }

        // specify optional or required content-type suffixes
        ContentTypeBySuffix bySuffix = ClassUtil.getAnnotation(method, ContentTypeBySuffix.class);
        if (bySuffix != null) {
            Collection suffixes = ControllerUtil.getSuffixes(method);
            if (bySuffix.required()) {
                registration.requireContentTypeSuffixes(suffixes);
            } else {
                registration.contentTypeSuffixes(suffixes);
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy