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

io.yawp.repository.shields.ShieldBase Maven / Gradle / Ivy

There is a newer version: 2.08alpha
Show newest version
package io.yawp.repository.shields;

import io.yawp.commons.http.HttpException;
import io.yawp.commons.utils.FacadeUtils;
import io.yawp.repository.Feature;
import io.yawp.repository.IdRef;
import io.yawp.repository.models.ObjectHolder;
import io.yawp.repository.actions.ActionKey;
import io.yawp.repository.actions.ActionMethod;
import io.yawp.repository.actions.InvalidActionMethodException;
import io.yawp.repository.query.NoResultException;
import io.yawp.repository.query.condition.BaseCondition;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public abstract class ShieldBase extends Feature {

    private ShieldRules rules = new ShieldRules<>();

    private boolean allow = false;

    private Class endpointClazz;

    private ActionKey actionKey;

    private Map actionMethods;

    protected IdRef id;

    protected List objects;

    protected String requestJson;

    protected Map params;

    public abstract void always();

    public abstract void defaults();

    public abstract void index(IdRef parentId);

    public abstract void show(IdRef id);

    public abstract void create(List objects);

    public abstract void update(IdRef id, T object);

    public abstract void destroy(IdRef id);

    // initialize methods

    public void setEndpointClazz(Class endpointClazz) {
        this.endpointClazz = endpointClazz;
    }

    public final void setId(IdRef id) {
        this.id = id;
    }

    public void setRequestJson(String requestJson) {
        this.requestJson = requestJson;
    }

    public final void setParams(Map params) {
        this.params = params;
    }

    public final void setActionKey(ActionKey actionKey) {
        this.actionKey = actionKey;
    }

    public final void setActionMethods(Map actionMethods) {
        this.actionMethods = actionMethods;
    }

    // shield rules

    public final Rule allow() {
        return allow(true);
    }

    public final Rule allow(boolean allow) {
        Rule rule = new Rule<>(yawp, endpointClazz, id, objects);

        if (allow) {
            rules.add(rule);
            this.allow = true;
        }

        return rule;
    }

    public final boolean isAction(Class... actionClazzes) {
        return isActionRoute() && Arrays.asList(actionClazzes).contains(currentActionClazz());
    }

    private boolean isActionRoute() {
        return actionKey != null;
    }

    private Class currentActionClazz() {
        return yawp.getFeatures().getByClazz(endpointClazz).getActionClazz(actionKey);
    }

    public final boolean requestHasAnyObject() {
        return objects != null;
    }

    public final void protectIndex() {
        always();
        index(id);
        throwNotFoundIfNotAllowed();
    }

    @SuppressWarnings("unchecked")
    public final void protectShow() {
        always();
        show((IdRef) id);
        throwNotFoundIfNotAllowed();
    }

    public final void protectCreate() {
        always();
        create(objects);
        throwNotFoundIfNotAllowed();

        applySetFacade();

        verifyConditions();
        throwForbiddenIfNotAllowed();
    }

    @SuppressWarnings("unchecked")
    public final void protectUpdate() {
        always();
        update((IdRef) id, objects == null ? null : objects.get(0));
        throwNotFoundIfNotAllowed();

        applySetFacade();

        verifyConditions();
        throwForbiddenIfNotAllowed();
    }

    @SuppressWarnings("unchecked")
    public final void protectDestroy() {
        always();
        destroy((IdRef) id);
        throwNotFoundIfNotAllowed();

        verifyConditions();
        throwForbiddenIfNotAllowed();
    }

    public final void protectCustom() {
        always();
        protectEachCustomAction();
        throwNotFoundIfNotAllowed();

        verifyConditions();
        throwForbiddenIfNotAllowed();
    }

    private void throwNotFoundIfNotAllowed() {
        if (!allow) {
            throw new HttpException(404, "The request was not allowed by the endpoint shield " + getClass().getName());
        }
    }

    private void throwForbiddenIfNotAllowed() {
        if (!allow) {
            throw new HttpException(403, "The request was not allowed by the endpoint shield " + getClass().getName());
        }
    }

    @SuppressWarnings("unchecked")
    private void applySetFacade() {
        Class facade = rules.getFacade();

        if (facade == null) {
            return;
        }

        for (T object : objects) {
            ObjectHolder objectHolder = new ObjectHolder(object);
            IdRef existingObjectId = (IdRef) objectHolder.getId();

            if (existingObjectId == null) {
                FacadeUtils.set(object, facade);
                continue;
            }

            try {
                T current = existingObjectId.fetch();
                FacadeUtils.set(object, current, facade);
            } catch (NoResultException ex) {
                // we are creating a new record with fixed id
                FacadeUtils.set(object, facade);
            }
        }

    }

    @SuppressWarnings("unchecked")
    public void applyGetFacade(Object object) {
        Class facade = rules.getFacade();

        if (facade == null) {
            return;
        }

        FacadeUtils.get((T) object, facade);
    }

    @SuppressWarnings("unchecked")
    public final void setObjects(List objects) {
        this.objects = (List) objects;
    }

    public BaseCondition getWhere() {
        return rules.getWhere();
    }

    public boolean hasCondition() {
        return rules.hasCondition();
    }

    public boolean hasFacade() {
        return rules.hasFacade();
    }

    private void verifyConditions() {
        this.allow = rules.evaluateConditions();
    }

    private void protectEachCustomAction() {
        if (!actionMethods.containsKey(actionKey)) {
            defaults();
            return;
        }

        Method method = actionMethods.get(actionKey);
        invokeCustomActionShield(method);
    }

    private void invokeCustomActionShield(Method method) {
        try {
            method.invoke(this, createArguments(method));
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    private Object[] createArguments(Method method) {
        try {
            ActionMethod actionMethod = new ActionMethod(method);
            return actionMethod.createArguments(yawp, id, requestJson, params);
        } catch (InvalidActionMethodException e) {
            throw new RuntimeException(e);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy