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

io.yawp.repository.IdRef Maven / Gradle / Ivy

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

import io.yawp.commons.http.HttpVerb;
import io.yawp.repository.actions.ActionKey;
import io.yawp.repository.query.QueryBuilder;

import java.util.ArrayList;
import java.util.List;

public class IdRef implements Comparable> {

	private Repository r;

	private Class clazz;

	private ObjectModel model;

	private Long id;

	private String name;

	private IdRef parentId;

	protected IdRef(Repository r, Class clazz, Long id) {
		this.r = r;
		this.clazz = clazz;
		this.id = id;
		this.model = new ObjectModel(clazz);
	}

	public IdRef(Repository r, Class clazz, String name) {
		this.r = r;
		this.clazz = clazz;
		this.name = name;
		this.model = new ObjectModel(clazz);
	}

	public void setParentId(IdRef parentId) {
		this.parentId = parentId;
	}

	public T fetch() {
		return fetch(clazz);
	}

	public  TT fetch(Class childClazz) {
		return r.query(childClazz).fetch(this);
	}

	public  TT child(Class childClazz) {
		QueryBuilder q = r.query(childClazz).from(this);
		return q.only();
	}

	public Long asLong() {
		return id;
	}

	public String asString() {
		return name;
	}

	public Repository getRepository() {
		return r;
	}

	public Class getClazz() {
		return clazz;
	}

	public Class getParentClazz() {
		return model.getParentClazz();
	}

	public ObjectModel getModel() {
		return new ObjectModel(clazz);
	}

	@SuppressWarnings("unchecked")
	public  IdRef getParentId() {
		return (IdRef) parentId;
	}

	@SuppressWarnings("unchecked")
	public  IdRef getAncestorId(int ancestor) {
		IdRef ancestorId = this;
		for (int i = 0; i <= ancestor; i++) {
			ancestorId = ancestorId.getParentId();
		}
		return (IdRef) ancestorId;
	}

	public  IdRef createChildId(Class clazz, Long id) {
		IdRef idRef = new IdRef(r, clazz, id);
		idRef.setParentId(this);
		return idRef;
	}

	public  IdRef createChildId(Class clazz, String name) {
		IdRef idRef = new IdRef(r, clazz, name);
		idRef.setParentId(this);
		return idRef;
	}

	public static  IdRef create(Repository r, Class clazz, Long id) {
		return new IdRef(r, clazz, id);
	}

	public static  IdRef create(Repository r, Class clazz, String name) {
		return new IdRef(r, clazz, name);
	}

	public static  List> create(Repository r, Class clazz, Long... ids) {
		List> idRefs = new ArrayList>();
		for (int i = 0; i < ids.length; i++) {
			idRefs.add(create(r, clazz, ids[i]));
		}
		return idRefs;
	}

	@SuppressWarnings("unchecked")
	public static  IdRef parse(Repository r, HttpVerb verb, String path) {
		String[] parts = path.substring(1).split("/");

		if (parts.length < 2) {
			return null;
		}

		IdRef lastIdRef = null;

		for (int i = 0; i < parts.length; i += 2) {
			if (isActionOrCollection(r, verb, parts, i)) {
				break;
			}

			String endpointPath = "/" + parts[i];

			IdRef currentIdRef = null;

			if (!isString(parts[i + 1])) {
				Long asLong = Long.valueOf(parts[i + 1]);
				currentIdRef = (IdRef) create(r, getIdRefClazz(r, endpointPath), asLong);
			} else {
				String asString = parts[i + 1];
				currentIdRef = (IdRef) create(r, getIdRefClazz(r, endpointPath), asString);
			}

			currentIdRef.setParentId(lastIdRef);
			lastIdRef = currentIdRef;

			validateParentId(currentIdRef, path);
		}

		return lastIdRef;
	}

	public static IdRef parse(Repository r, String id) {
		return parse(r, HttpVerb.GET, id);
	}

	public static  IdRef parse(Class clazz, Repository r, String idString) {
		return parse(r, HttpVerb.GET, idString);
	}

	public static  List> parse(Class clazz, Repository r, List idsString) {
		ArrayList> ids = new ArrayList>();
		for (String idString : idsString) {
			ids.add(parse(clazz, r, idString));
		}
		return ids;
	}

	private static void validateParentId(IdRef id, String path) {
		Class parentClazz = id.getParentClazz();
		if (parentClazz == null) {
			if (id.getParentId() != null) {
				throw new RuntimeException("Invalid parent structure for id: " + path);
			}
			return;
		}

		if (id.getParentId() == null) {
			throw new RuntimeException("Invalid parent structure for id: " + path);
		}

		if (!parentClazz.equals(id.getParentId().getClazz())) {
			throw new RuntimeException("Invalid parent structure for id: " + path);
		}
	}

	private static Class getIdRefClazz(Repository r, String endpointPath) {
		return r.getFeatures().get(endpointPath).getClazz();
	}

	private static boolean isActionOrCollection(Repository r, HttpVerb verb, String[] parts, int i) {
		if (i < parts.length - 2) {
			return false;
		}

		if (i == parts.length - 1) {
			return true;
		}

		if (!isString(parts[parts.length - 1])) {
			return false;
		}

		String endpointPath = "/" + parts[parts.length - 2];
		String possibleAction = parts[parts.length - 1];

		ActionKey actionKey = new ActionKey(verb, possibleAction, true);
		return r.getFeatures().hasCustomAction(endpointPath, actionKey);
	}

	private static boolean isString(String s) {
		try {
			Long.valueOf(s);
			return false;
		} catch (NumberFormatException e) {
			return true;
		}
	}

	public void delete() {
		r.destroy(this);
	}

	public Object getSimpleValue() {
		if (id != null) {
			return id;
		}
		return name;
	}

	public String getName() {
		return name;
	}

	public Long getId() {
		return id;
	}

	public boolean isAncestorId(IdRef childId) {
		IdRef currentId = childId;
		while (currentId.getParentId() != null) {
			if (currentId.getParentId().getClazz().equals(this.getClazz())) {
				return this.equals(currentId.getParentId());
			}
			currentId = currentId.getParentId();
		}
		return false;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((clazz == null) ? 0 : clazz.hashCode());
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + ((parentId == null) ? 0 : parentId.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		IdRef other = (IdRef) obj;
		if (clazz == null) {
			if (other.clazz != null)
				return false;
		} else if (!clazz.equals(other.clazz))
			return false;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (parentId == null) {
			if (other.parentId != null)
				return false;
		} else if (!parentId.equals(other.parentId))
			return false;
		return true;
	}

	@Override
	public int compareTo(IdRef o) {
		if (id != null && o.id != null) {
			return id.compareTo(o.id);
		}
		return idOrNameAsString().compareTo(o.idOrNameAsString());
	}

	private String idOrNameAsString() {
		return id != null ? String.valueOf(id) : name;
	}

	@Override
	public String toString() {
		return getUri();
	}

	public String getUri() {
		StringBuilder sb = new StringBuilder();
		if (parentId != null) {
			sb.append(parentId.toString());
		}
		sb.append(r.getFeatures().get(clazz).getEndpointPath());
		sb.append("/");
		sb.append(id != null ? id : name);
		return sb.toString();
	}

}