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

io.yawp.servlet.EndpointRouter Maven / Gradle / Ivy

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

import io.yawp.commons.http.HttpException;
import io.yawp.commons.http.HttpResponse;
import io.yawp.commons.http.HttpVerb;
import io.yawp.commons.utils.JsonUtils;
import io.yawp.repository.EndpointFeatures;
import io.yawp.repository.EndpointNotFoundException;
import io.yawp.repository.IdRef;
import io.yawp.repository.ObjectHolder;
import io.yawp.repository.Repository;
import io.yawp.repository.RepositoryFeatures;
import io.yawp.repository.actions.ActionKey;
import io.yawp.servlet.rest.RestAction;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

public class EndpointRouter {

	private Repository r;

	private RepositoryFeatures features;

	private String uri;

	private boolean overCollection;

	private ActionKey customActionKey;

	private HttpVerb verb;

	private IdRef id;

	private Class endpointClazz;

	private String requestJson;

	private Map params;

	private List objects;

	private EndpointRouter(Repository r, HttpVerb verb, String uri, String requestJson, Map params) {
		this.verb = verb;
		this.uri = uri;
		this.r = r;
		this.requestJson = requestJson;
		this.params = params;
		this.features = r.getFeatures();

		try {
			parseAll();
		} catch (EndpointNotFoundException e) {
			throw new HttpException(404, "Endpoint not found: " + e.getEndpointPath());
		}
	}

	public static EndpointRouter parse(Repository r, HttpVerb verb, String uri, String requestJson, Map params) {
		return new EndpointRouter(r, verb, uri, requestJson, params);
	}

	private void parseAll() {
		this.id = IdRef.parse(r, verb, uri);

		this.customActionKey = parseCustomActionKey();
		this.overCollection = parseOverCollection();
		this.endpointClazz = parseEndpointClazz();
		this.objects = parseRequestJson();
	}

	private Class parseEndpointClazz() {
		String[] parts = uri.substring(1).split("/");

		if (isOverCollection()) {
			if (isCustomAction()) {
				return features.get("/" + parts[parts.length - 2]).getClazz();
			}
			return features.get("/" + parts[parts.length - 1]).getClazz();
		}

		return id.getClazz();
	}

	private ActionKey parseCustomActionKey() {

		if (id == null) {
			return rootCollectionCustomActionKey();
		}

		if (id.getUri().length() == uri.length()) {
			return null;
		}

		String lastToken = uri.substring(id.getUri().length() + 1);
		if (hasTwoParts(lastToken)) {
			return nestedCollectionCustomActionKey(lastToken);
		}

		return singleObjectCustomActionKey(lastToken);
	}

	private ActionKey singleObjectCustomActionKey(String lastToken) {
		ActionKey actionKey = new ActionKey(verb, lastToken, false);
		if (features.hasCustomAction(id.getClazz(), actionKey)) {
			return actionKey;
		}

		return null;
	}

	private ActionKey nestedCollectionCustomActionKey(String lastToken) {
		String[] tokens = lastToken.split("/");

		ActionKey actionKey = new ActionKey(verb, tokens[1], true);
		if (features.hasCustomAction("/" + tokens[0], actionKey)) {
			return actionKey;
		}
		return null;
	}

	private ActionKey rootCollectionCustomActionKey() {
		String[] tokens = uri.substring(1).split("/");

		if (tokens.length == 1) {
			return null;
		}

		ActionKey actionKey = new ActionKey(verb, tokens[1], true);
		if (features.hasCustomAction("/" + tokens[0], actionKey)) {
			return actionKey;
		}

		return null;
	}

	private boolean parseOverCollection() {
		if (id == null) {
			return true;
		}

		if (id.getUri().length() == uri.length()) {
			return false;
		}

		String lastToken = uri.substring(id.getUri().length() + 1);
		if (hasTwoParts(lastToken)) {
			return true;
		}

		ActionKey actionKey = new ActionKey(verb, lastToken, false);
		if (features.hasCustomAction(id.getClazz(), actionKey)) {
			return false;
		}

		return true;
	}

	private boolean hasTwoParts(String lastToken) {
		return lastToken.indexOf("/") != -1;
	}

	public boolean isOverCollection() {
		return overCollection;
	}

	public boolean isCustomAction() {
		return customActionKey != null;
	}

	public String getCustomActionName() {
		if (!isCustomAction()) {
			return null;
		}
		return customActionKey.getActionName();
	}

	public ActionKey getCustomActionKey() {
		return customActionKey;
	}

	public EndpointFeatures getEndpointFeatures() {
		return features.get(endpointClazz);
	}

	public Class getEndpointClazz() {
		return getEndpointFeatures().getClazz();
	}

	public IdRef getIdRef() {
		return id;
	}

	private RestAction createRestAction(boolean enableHooks) {
		try {
			Class restActionClazz = RestAction.getRestActionClazz(verb, isOverCollection(), isCustomAction());

			RestAction action = restActionClazz.newInstance();

			action.setRepository(r);
			action.setEnableHooks(enableHooks);
			action.setEndpointClazz(endpointClazz);
			action.setId(id);
			action.setParams(params);
			action.setCustomActionKey(customActionKey);
			action.setRequestJson(requestJson);
			action.setObjects(objects);

			action.defineTrasnformer();
			action.defineShield();

			return action;

		} catch (InstantiationException | IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}

	private List parseRequestJson() {
		if (StringUtils.isBlank(requestJson)) {
			return null;
		}

		if (JsonUtils.isJsonArray(requestJson)) {
			return JsonUtils.fromList(r, requestJson, endpointClazz);
		}

		return Arrays.asList(JsonUtils.from(r, requestJson, endpointClazz));
	}

	public HttpResponse executeRestAction(boolean enableHooks) {
		return createRestAction(enableHooks).execute();
	}

	public boolean isValid() {
		return tryToAdjustIds();
	}

	public boolean tryToAdjustIds() {
		if (objects == null) {
			return true;
		}

		for (Object object : objects) {
			IdRef idInObject = forceIdInObjectIfNecessary(object);
			IdRef parentIdInObject = forceParentIdInObjectIfNecessary(object, idInObject);

			if (idInObject == null) {
				if (parentIdInObject != null && !parentIdInObject.equals(id)) {
					return false;
				}
				continue;
			}

			if (parentIdInObject != null && !parentIdInObject.equals(idInObject.getParentId())) {
				return false;
			}

			if (!idInObject.getClazz().equals(endpointClazz)) {
				return false;
			}

			if (id == null) {
				continue;
			}

			if (id.equals(idInObject)) {
				continue;
			}

			if (verb != HttpVerb.POST) {
				return false;
			}

			if (!id.isAncestorId(idInObject)) {
				return false;
			}
		}

		return true;
	}

	private IdRef forceParentIdInObjectIfNecessary(Object object, IdRef idInObject) {
		ObjectHolder objectHolder = new ObjectHolder(object);

		if (objectHolder.getModel().getParentClazz() == null) {
			return null;
		}

		IdRef parentId = objectHolder.getParentId();
		if (parentId != null) {
			return parentId;
		}

		if (idInObject != null) {
			objectHolder.setParentId(idInObject.getParentId());
			return idInObject.getParentId();
		}

		if (id != null) {
			objectHolder.setParentId(id);
			return id;
		}

		return null;
	}

	private IdRef forceIdInObjectIfNecessary(Object object) {
		ObjectHolder objectHolder = new ObjectHolder(object);

		IdRef idInObject = objectHolder.getId();

		if (idInObject != null) {
			return idInObject;
		}

		if (id != null && id.getClazz().equals(endpointClazz)) {
			objectHolder.setId(id);
			return id;
		}

		return null;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy