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

colesico.framework.router.codegen.RoutesBuilder Maven / Gradle / Ivy

/*
 * Copyright © 2014-2020 Vladlen V. Larionov and others as noted.
 *
 * 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 colesico.framework.router.codegen;


import colesico.framework.assist.Elements;
import colesico.framework.assist.StrUtils;
import colesico.framework.assist.codegen.CodegenException;
import colesico.framework.assist.codegen.model.AnnotationAssist;
import colesico.framework.assist.codegen.model.ParserElement;
import colesico.framework.http.HttpMethod;
import colesico.framework.router.RequestMethod;
import colesico.framework.router.Route;
import colesico.framework.router.RouteAttribute;
import colesico.framework.router.RouteAttributes;
import colesico.framework.router.assist.RouteTrie;
import colesico.framework.service.codegen.model.ServiceElement;
import colesico.framework.service.codegen.model.TeleMethodElement;
import org.apache.commons.lang3.StringUtils;

import javax.lang.model.element.PackageElement;
import java.util.HashMap;
import java.util.Map;

/**
 * Routes builder
 * Used to construct routes while a service parsing
 */
public class RoutesBuilder {

    protected static final String INDEX_SERVICE_PREFIX = "Index";
    protected static final String INDEX_METHOD_NAME = "index";
    protected static final String OTHER_METHOD_NAME = "other";

    protected final Elements teleMethods = new Elements<>();

    protected final String serviceRoute;

    public RoutesBuilder(ServiceElement service) {
        this.serviceRoute = buildServiceRoute(service);
    }

    public final void addTeleMethod(TeleMethodElement teleMethod) {
        String targetMethodName = teleMethod.getName();
        final String route = buildMethodRoute(teleMethod);

        RoutedTeleMethodElement rtme = teleMethods.find(rte -> rte.getRoute().equals(route));
        if (null != rtme) {
            throw CodegenException.of()
                    .message("Duplicate router path: " + route + "->" + targetMethodName + "(...). Route already bound to " + rtme.getTeleMethod().getServiceMethod().getName() + "(...)")
                    .element(teleMethod.getServiceMethod().getOriginMethod()).build();
        }

        Map methodRouteAttrs = parseRouteAttributes(teleMethod.getServiceMethod().getOriginMethod());
        Map classRouteAttrs = parseRouteAttributes(teleMethod.getServiceMethod().getOriginMethod().getParentClass());
        classRouteAttrs.putAll(methodRouteAttrs);

        RoutedTeleMethodElement routedTeleMethod = new RoutedTeleMethodElement(teleMethod, route, classRouteAttrs);
        teleMethods.add(routedTeleMethod);
        teleMethod.setProperty(RoutedTeleMethodElement.class, routedTeleMethod);
    }

    protected String buildMethodRoute(TeleMethodElement teleMethod) {

        AnnotationAssist routeAnn = teleMethod.getServiceMethod().getOriginMethod().getAnnotation(Route.class);
        String methodRoute;
        if (routeAnn != null) {
            methodRoute = StringUtils.trim(routeAnn.unwrap().value());
            // If NOT absolute route
            if (!methodRoute.startsWith(RouteTrie.SEGMENT_DELEMITER)) {
                // Local route optional marker
                if (methodRoute.startsWith("./")) {
                    methodRoute = methodRoute.substring(2);
                }
                methodRoute = StrUtils.concatPath(serviceRoute, methodRoute, RouteTrie.SEGMENT_DELEMITER);
            }
        } else {
            String methodName = teleMethod.getName();
            if (methodName.equals(INDEX_METHOD_NAME)) {
                // Local root route
                methodRoute = "";
            } else if (methodName.equals(OTHER_METHOD_NAME)) {
                // any route
                methodRoute = "*";
            } else {
                methodRoute = StrUtils.toSeparatorNotation(methodName, '-');
            }
            methodRoute = StrUtils.concatPath(serviceRoute, methodRoute, RouteTrie.SEGMENT_DELEMITER);
        }

        HttpMethod httpMethod = HttpMethod.HTTP_METHOD_GET;
        AnnotationAssist methodAnnotation = teleMethod.getServiceMethod().getOriginMethod().getAnnotation(RequestMethod.class);
        if (methodAnnotation != null) {
            httpMethod = HttpMethod.of(methodAnnotation.unwrap().value());
        }

        return StrUtils.concatPath(httpMethod.getName(), methodRoute, RouteTrie.SEGMENT_DELEMITER);
    }

    protected String buildServiceRoute(ServiceElement service) {
        AnnotationAssist routeAnn = service.getOriginClass().getAnnotation(Route.class);
        String srvRoute;
        if (routeAnn != null) {
            srvRoute = StringUtils.trim(routeAnn.unwrap().value());

            // If absolute route
            if (srvRoute.startsWith(RouteTrie.SEGMENT_DELEMITER)) {
                return srvRoute;
            }

            // Local route optional marker
            if (srvRoute.startsWith("./")) {
                srvRoute = srvRoute.substring(2);
            }

            String pkgRoute = buildPackageRoute(service.getOriginClass().getPackage());
            return StrUtils.concatPath(pkgRoute, srvRoute, RouteTrie.SEGMENT_DELEMITER);
        } else {
            String serviceBeanName = service.getOriginClass().getSimpleName();
            // Local root route
            if (serviceBeanName.startsWith(INDEX_SERVICE_PREFIX)) {
                srvRoute = "";
            } else {
                // Bean route from bean simple class name
                srvRoute = StrUtils.toSeparatorNotation(serviceBeanName, '-');
            }
            String pkgRoute = buildPackageRoute(service.getOriginClass().getPackage());
            return StrUtils.concatPath(pkgRoute, srvRoute, RouteTrie.SEGMENT_DELEMITER);
        }
    }

    protected String buildPackageRoute(PackageElement pkg) {
        Route routeAnn = pkg.getAnnotation(Route.class);
        if (routeAnn == null) {
            return "/";
        }
        String route = StringUtils.trim(routeAnn.value());
        if (!route.startsWith(RouteTrie.SEGMENT_DELEMITER)) {
            throw CodegenException.of()
                    .message("Wrong package route: " + route + ". must starts with '" + RouteTrie.SEGMENT_DELEMITER + "'")
                    .element(pkg)
                    .build();
        }
        return route;
    }

    protected Map parseRouteAttributes(ParserElement methodOrClass) {
        Map result = new HashMap<>();
        AnnotationAssist routeAttributesAnn = methodOrClass.getAnnotation(RouteAttributes.class);
        if (routeAttributesAnn == null) {
            AnnotationAssist routeAttrAnn = methodOrClass.getAnnotation(RouteAttribute.class);
            if (routeAttrAnn != null) {
                result.put(routeAttrAnn.unwrap().name(), routeAttrAnn.unwrap().value());
            }
        } else {
            for (RouteAttribute routeAttrAnn : routeAttributesAnn.unwrap().value()) {
                result.put(routeAttrAnn.name(), routeAttrAnn.value());
            }
        }
        return result;
    }

    public final Elements getTeleMethods() {
        return teleMethods;
    }

    public static class RoutedTeleMethodElement {
        protected final TeleMethodElement teleMethod;
        protected final String route;
        protected final Map routeAttributes;

        public RoutedTeleMethodElement(TeleMethodElement teleMethod, String route, Map routeAttributes) {
            this.teleMethod = teleMethod;
            this.route = route;
            this.routeAttributes = routeAttributes;
        }

        public final String getRoute() {
            return route;
        }

        public TeleMethodElement getTeleMethod() {
            return teleMethod;
        }

        public Map getRouteAttributes() {
            return routeAttributes;
        }

        public String getHttpMethodName() {
            int i = route.indexOf(RouteTrie.SEGMENT_DELEMITER);
            return route.substring(0, i);
        }

        public String getRoutePath() {
            int i = route.indexOf(RouteTrie.SEGMENT_DELEMITER);
            return '/'+route.substring(i + 1);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy