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

org.javalite.activeweb.Route Maven / Gradle / Ivy

There is a newer version: 3.5-j11
Show newest version
package org.javalite.activeweb;

import org.javalite.common.Inflector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static org.javalite.common.Util.blank;
import static org.javalite.common.Util.join;

/**
 * Instance of this class will contain routing information.
 *
 * @author Igor Polevoy: 1/8/13 4:21 PM
 */
public class Route {
    private static Logger LOGGER = LoggerFactory.getLogger(Route.class);

    private AppController controller;
    private String actionName, id, wildCardName, wildCardValue, targetAction;
    private List ignoreSpecs;
    private HttpMethod httpMethod;
    private boolean custom = false;
    private Method actionMethod;

    public Route(AppController controller, String actionName, HttpMethod method) {
        this.controller = controller;
        this.httpMethod = method;
        initActionMethod(actionName);
    }

    public Route(AppController controller, String actionName, String id, HttpMethod method) {
        this.controller = controller;
        this.id = id;
        this.httpMethod = method;
        initActionMethod(actionName);
    }

    public Route(RouteBuilder builder, HttpMethod method, boolean custom) {
        this.controller = builder.getController();
        this.id = builder.getId();
        this.wildCardName = builder.getWildcardName();
        this.wildCardValue = builder.getWildCardValue();
        this.httpMethod = method;
        this.custom = custom;
        initActionMethod(builder.getActionName());
    }


    /**
     * package private, only need for ViewSpec
     */
    Route(AppController controller) {
        this.controller = controller;
    }


    private void initActionMethod(String actionName) {

        if(blank(actionName)){
            throw new IllegalArgumentException("Action name cannot be blank");
        }

        this.actionName = actionName;
        try {
            String actionMethodName = Inflector.camelize(actionName.replace('-', '_'), false);
            actionMethod = controller.getClass().getMethod(actionMethodName);
        } catch (NoSuchMethodException e) {
            throw new ActionNotFoundException(e);
        }
    }

    boolean isWildCard() {
        return wildCardName != null;
    }

    String getWildCardName() {
        return wildCardName;
    }

    String getWildCardValue() {
        return wildCardValue;
    }

    public AppController getController() {
        return controller;
    }


    public Method getActionMethod() {
        return actionMethod;
    }


    public String getActionName() {
        return actionName;
    }

    public String getId() {
        return id;
    }

    public HttpMethod getHttpMethod() {
        return httpMethod;
    }

    protected String getControllerPath() {
        return Router.getControllerPath(controller.getClass());
    }

    /**
     * This is used in specs
     *
     * @return controller class name
     */
    protected String getControllerClassName() {
        return controller.getClass().getName();
    }

    protected void setIgnoreSpecs(List ignoreSpecs) {
        this.ignoreSpecs = ignoreSpecs;
    }

    protected boolean ignores(String path) {
        if (ignoreSpecs == null) {
            return false;
        } else {
            for (IgnoreSpec ignoreSpec : ignoreSpecs) {
                if (ignoreSpec.ignores(path))
                    return true;
            }
        }
        return false;
    }

    public boolean isCustom() {
        return custom;
    }

    /**
     * In case of OPTIONS HTTP method, the controller action might be routed to Controller#options, in which case
     * you can use this getter to see what was the original intended controller action.
     */
    public String getTargetAction() {
        return targetAction;
    }


    void setTargetAction(String targetAction) {
        this.targetAction = targetAction;
    }

    /**
     * Checks if the action method supports requested HTTP method
     */
    boolean actionSupportsHTTPMethod() {
        HttpMethod method = HttpMethod.getMethod(RequestContext.getHttpRequest());
        if (!actionSupportsHttpMethod()) {
            DirectResponse res = new DirectResponse("");
            //see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
            res.setStatus(405);
            LOGGER.warn("Requested action does not support HTTP method: " + method.name() + ", returning status code 405.");
            RequestContext.setControllerResponse(res);
            //see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
            RequestContext.getHttpResponse().setHeader("Allow", join(allowedActions(), ", "));
            return false;
        }
        return true;
    }

    /**
     * Checks if the action supports an HTTP method, according to its configuration.
     *
     * @return true if supports, false if does not.
     */
    private boolean actionSupportsHttpMethod() {
        if (controller.restful()) {
            return restfulActionSupportsHttpMethod() || standardActionSupportsHttpMethod();
        } else {
            return standardActionSupportsHttpMethod();
        }
    }

    private boolean standardActionSupportsHttpMethod() {
        for (HttpMethod m : allowedActions()) {
            if (m == httpMethod)
                return true;
        }
        return false;
    }

    private List allowedActions() {
        Annotation[] annotations = actionMethod.getAnnotations();

        //default behavior: GET method!
        if (annotations.length == 0) {
            return Collections.singletonList(HttpMethod.GET);
        } else {
            List res = new ArrayList<>();
            for (Annotation annotation : annotations) {
                try {
                    res.add(HttpMethod.valueOf(annotation.annotationType().getSimpleName()));
                } catch (IllegalArgumentException ignore) {
                } // we do not know this annotation
            }
            return res;
        }
    }

    private boolean restfulActionSupportsHttpMethod() {
        if (       actionName.equals("index") && httpMethod.equals(HttpMethod.GET)
                || actionName.equals("newForm") && httpMethod.equals(HttpMethod.GET)
                || actionName.equals("create") && httpMethod.equals(HttpMethod.POST)
                || actionName.equals("show") && httpMethod.equals(HttpMethod.GET)
                || actionName.equals("editForm") && httpMethod.equals(HttpMethod.GET)
                || actionName.equals("update") && httpMethod.equals(HttpMethod.PUT)
                || actionName.equals("destroy") && httpMethod.equals(HttpMethod.DELETE)
                || actionName.equals("options") && httpMethod.equals(HttpMethod.OPTIONS)) {
            return true;
        } else {
            LOGGER.warn("Cannot execute a non-restful action on a restful controller.");
            return false;
        }
    }

    @Override
    public String toString() {
        return "Route{" +
                "controller=" + controller +
                ", actionName='" + actionName + '\'' +
                ", id='" + id + '\'' +
                ", httpMethod=" + httpMethod +
                ", custom=" + custom +
                ", actionMethod=" + actionMethod +
                '}';
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy