package edu.washington.escience.myria.api.encoding; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.LinkedList; import java.util.List; import javax.ws.rs.core.Response.Status; import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import edu.washington.escience.myria.api.MyriaApiException; /** * The interface that all encodings must support. In particular, the validate function must throw an exception * explaining why the deserialized object is incorrect. * * */ public abstract class MyriaApiEncoding { /** * @return a list of required fields. */ @JsonIgnore private final List<Field> getRequiredFields() { Field[] fs = this.getClass().getFields(); List<Field> requiredFields = new LinkedList<>(); for (Field f : fs) { Annotation a = f.getAnnotation(Required.class); if (a != null) { requiredFields.add(f); } } return requiredFields; } /** * Checks that this deserialized instance passes input validation. First, it enforces that all required fields * (defined by the return value from getRequiredFields()) are present. Second, it calls the child's method * validateExtra(). * * @throws MyriaApiException if the validation checks fail. */ public final void validate() throws MyriaApiException { final List<String> missing = Lists.newLinkedList(); /* Check using Java reflection to see that every field is there. */ try { for (final Field f : getRequiredFields()) { if (null == f.get(this)) { missing.add(f.getName()); } } } catch (IllegalAccessException e) { throw new MyriaApiException(Status.INTERNAL_SERVER_ERROR, e); } if (!missing.isEmpty()) { /* Some field is missing; throw a 400 (BAD REQUEST) exception with the list of required fields. */ final StringBuilder sb = new StringBuilder(getClass().getName()).append(" is missing required fields: "); sb.append(Joiner.on(", ").join(missing)).append(".\n"); throw new MyriaApiException(Status.BAD_REQUEST, sb.toString()); } validateExtra(); } /** * Adaptor function for extending operators to use if they wish to add extra validation beyond the list of required * fields. */ protected void validateExtra() throws MyriaApiException {} }