package org.datacite.mds.validation.constraints.impl;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.datacite.mds.util.ValidationUtils;
import org.datacite.mds.validation.constraints.Unique;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

public class UniqueValidator implements ConstraintValidator<Unique, Object> {

    Logger log = Logger.getLogger(UniqueValidator.class);

    @PersistenceContext
    transient EntityManager entityManager;

    String field;
    String idField;
    String defaultMessage;

    public void initialize(Unique constraintAnnotation) {
        this.field = constraintAnnotation.field();
        this.idField = constraintAnnotation.idField();
        this.defaultMessage = constraintAnnotation.message();
    }

    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
    public boolean isValid(Object entity, ConstraintValidatorContext context) {
        Serializable id, value;
        try {
            id = (Serializable) PropertyUtils.getProperty(entity, idField);
            value = (Serializable) PropertyUtils.getProperty(entity, field);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        log.debug("entity=" + entity.getClass().getName() + ", id: " + idField + "=" + id + ", field: " + field + "=" + value);

        String qstr = "SELECT " + idField + " FROM " + entity.getClass().getName() + " WHERE " + field + " = :value";
        TypedQuery<Serializable> q = entityManager.createQuery(qstr, Serializable.class);
        q.setParameter("value", value);
        List<Serializable> results = q.getResultList();

        Boolean isUnique = true;
        if (results.size() == 1) {
            Serializable foundId = results.get(0);
            log.debug("#results=1 (" + idField + "=" + foundId + ")");
            isUnique = foundId.equals(id);
        } else {
            log.debug("#results=" + results.size());
            isUnique = results.size() == 0;
        }
        log.debug("isUnique=" + isUnique);
        
        if (!isUnique) {
          ValidationUtils.addConstraintViolation(context, defaultMessage, field);
        }
        
        return isUnique;
    }

}

@@ -851,17 +851,23 @@
  String 
-f
+uniqueF
 ield;%0A  
@@ -983,17 +983,23 @@
    this.
-f
+uniqueF
 ield = c
@@ -1334,77 +1334,644 @@
 e id
-, value;%0A        try %7B%0A            id = (Serializable) PropertyUtils.
+FieldValue = getProperty(entity, idField);%0A        Serializable uniqueFieldValue = getProperty(entity, uniqueField);%0A        log.debug(%22entity: %22 + entity.getClass().getName() + %22, id: %22 + idField + %22=%22 + idFieldValue + %22, field: %22%0A                + uniqueField + %22=%22 + uniqueFieldValue);%0A%0A        List%3CSerializable%3E foundIds = findIds(entity, uniqueFieldValue);%0A%0A        Boolean isUnique = foundIds.size() == 0 %7C%7C foundIds.contains(idFieldValue);%0A        log.debug(%22isUnique=%22 + isUnique);%0A%0A        ValidationUtils.addConstraintViolation(context, defaultMessage, uniqueField);%0A%0A        return isUnique;%0A    %7D%0A%0A    private Serializable 
 getP
@@ -1974,32 +1974,39 @@
 getProperty(
+Object 
 entity, 
 idField);%0A  
@@ -1989,33 +1989,39 @@
 ect entity, 
-idF
+String f
 ield)
-;
+ %7B
 %0A           
@@ -2021,19 +2021,32 @@
     
-    value =
+try %7B%0A            return
  (Se
@@ -2192,132 +2192,86 @@
     
+%7D%0A%0A
     
-log.debug(%22entity=%22 + entity.getClass().getName() + %22, id: %22 + idField + %22=%22 + id + %22, field: %22 + field + %22=%22 +
+private List%3CSerializable%3E findIds(Object entity, Serializable
  value)
-;%0A
+ %7B
 %0A   
@@ -2283,19 +2283,26 @@
 String q
-str
+ueryString
  = %22SELE
@@ -2371,21 +2371,43 @@
 ERE %22 + 
-field
+uniqueField%0A               
  + %22 = :
@@ -2448,16 +2448,20 @@
 zable%3E q
+uery
  = entit
@@ -2482,19 +2482,26 @@
 eQuery(q
-str
+ueryString
 , Serial
@@ -2524,16 +2524,20 @@
        q
+uery
 .setPara
@@ -2590,19 +2590,24 @@
 le%3E 
-result
+foundId
 s = q
+uery
 .get
@@ -2624,567 +2624,117 @@
 ();%0A
-%0A        Boolean isUnique = true;%0A        if (results.size() == 1) %7B%0A            Serializable foundId = results.get(0);%0A            log.debug(%22#results=1 (%22 + idField + %22=%22 + foundId + %22)%22);%0A            isUnique = foundId.equals(id);%0A        %7D else %7B%0A            log.debug(%22#results=%22 + results.size());%0A            isUnique = results.size() == 0;%0A        %7D%0A        log.debug(%22isUnique=%22 + isUnique);%0A        %0A        if (!isUnique) %7B%0A          ValidationUtils.addConstraintViolation(context, defaultMessage, field);%0A        %7D%0A        %0A        return isUnique
+        log.debug(%22found IDs with '%22 + uniqueField + %22=%22 + value + %22': %22 + foundIds);%0A        return foundIds
 ;%0A  

clean code