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

play.data.validation.UniqueCheck Maven / Gradle / Ivy

There is a newer version: 2.6.2
Show newest version
package play.data.validation;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Pattern;
import net.sf.oval.Validator;
import net.sf.oval.configuration.annotation.AbstractAnnotationCheck;
import net.sf.oval.context.FieldContext;
import net.sf.oval.context.OValContext;
import play.db.Model;
import play.db.jpa.GenericModel;
import play.db.jpa.JPQL;
import play.exceptions.UnexpectedException;

/** Check which proof if one or a set of properties is unique. */
public class UniqueCheck extends AbstractAnnotationCheck {

  private String uniqueKeyContext = null;
  static final String mes = "validation.unique";
  private static final Pattern PROPERTY_DIVIDER = Pattern.compile("[,;\\s]\\s*");

  @Override
  public void configure(Unique constraintAnnotation) {
    uniqueKeyContext = constraintAnnotation.value();
    setMessage(constraintAnnotation.message());
  }

  @Override
  public Map createMessageVariables() {
    Map messageVariables = new TreeMap<>();
    messageVariables.put("2-properties", uniqueKeyContext);
    return messageVariables;
  }

  private String[] getPropertyNames(String uniqueKey) {
    String completeUniqueKey;
    if (!uniqueKeyContext.isEmpty()) {
      completeUniqueKey = uniqueKeyContext + ";" + uniqueKey;
    } else {
      completeUniqueKey = uniqueKey;
    }
    return PROPERTY_DIVIDER.split(completeUniqueKey);
  }

  /** {@inheritDoc} */
  @Override
  public boolean isSatisfied(
      Object validatedObject, Object value, OValContext context, Validator validator) {
    requireMessageVariablesRecreation();
    if (value == null) {
      return true;
    }
    String[] propertyNames = getPropertyNames(((FieldContext) context).getField().getName());
    GenericModel model = (GenericModel) validatedObject;
    Model.Factory factory = Model.Manager.factoryFor(model.getClass());
    String keyProperty = factory.keyName();
    Object keyValue = factory.keyValue(model);
    //In case of an update make sure that we won't read the current record from database.
    boolean isUpdate = (keyValue != null);
    String entityName = model.getClass().getName();
    StringBuilder jpql = new StringBuilder("SELECT COUNT(o) FROM ");
    jpql.append(entityName).append(" AS o where ");
    Object[] values = new Object[isUpdate ? propertyNames.length + 1 : propertyNames.length];
    Class clazz = validatedObject.getClass();
    int index = 1;
    for (int i = 0; i < propertyNames.length; i++) {
      Field field = getField(clazz, propertyNames[i]);
      field.setAccessible(true);
      try {
        values[i] = field.get(model);
      } catch (Exception ex) {
        throw new UnexpectedException(ex);
      }
      if (i > 0) {
        jpql.append(" And ");
      }
      jpql.append("o.")
          .append(propertyNames[i])
          .append(" = ?")
          .append(index++)
          .append(" ");
    }
    if (isUpdate) {
      values[propertyNames.length] = keyValue;
      jpql.append(" and o.")
          .append(keyProperty)
          .append(" <>  ?")
          .append(index++)
          .append(" ");
    }
    return JPQL.instance.count(entityName, jpql.toString(), values) == 0L;
  }

  private Field getField(Class clazz, String fieldName) {
    Class c = clazz;
    try {
      while (!c.equals(Object.class)) {
        try {
          return c.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
          c = c.getSuperclass();
        }
      }
    } catch (Exception e) {
      throw new UnexpectedException(
          "Error while determining the field " + fieldName + " for an object of type " + clazz, e);
    }
    throw new UnexpectedException(
        "Cannot get the field " + fieldName + " for an object of type " + clazz);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy