package edu.ualberta.med.biobank.common.wrappers.checks;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import edu.ualberta.med.biobank.common.util.HibernateUtil;
import edu.ualberta.med.biobank.common.util.StringUtil;
import edu.ualberta.med.biobank.common.wrappers.ModelWrapper;
import edu.ualberta.med.biobank.common.wrappers.Property;
import edu.ualberta.med.biobank.common.wrappers.actions.UncachedAction;
import edu.ualberta.med.biobank.common.wrappers.property.GetterInterceptor;
import edu.ualberta.med.biobank.common.wrappers.property.LazyLoaderInterceptor;
import edu.ualberta.med.biobank.server.applicationservice.exceptions.BiobankSessionException;
import edu.ualberta.med.biobank.server.applicationservice.exceptions.DuplicatePropertySetException;
/**
* Checks that the {@link Collection} of {@link Property}-s is unique for the
* model object in the {@link ModelWrapper}, excluding the instance itself (if
* it is already persisted).
*
* @author jferland
*
* @param <E>
*/
public class UniquePreCheck<E> extends UncachedAction<E> {
private static final long serialVersionUID = 1L;
private static final String HQL = "SELECT COUNT(*) FROM {0} o WHERE ({1}) = ({2}) {3}"; //$NON-NLS-1$
private static final String EXCEPTION_STRING = "There already exists a {0} with property value(s) ({1}) for ({2}), respectively. These field(s) must be unique."; //$NON-NLS-1$
protected final Collection<Property<?, ? super E>> properties;
/**
*
* @param wrapper {@link ModelWrapper} which holds the model object
* @param properties to ensure uniqueness on
*/
public UniquePreCheck(ModelWrapper<E> wrapper,
Collection<Property<?, ? super E>> properties) {
super(wrapper);
this.properties = properties;
}
@Override
public void doUncachedAction(Session session)
throws BiobankSessionException {
Query query = getQuery(session);
Long count = HibernateUtil.getCountFromQuery(query);
if (count > 0) {
throwException();
}
}
private void throwException() throws DuplicatePropertySetException {
String modelClass = Format.modelClass(getModelClass());
String values = Format.propertyValues(getModel(), properties);
String names = Format.propertyNames(properties);
String msg = MessageFormat.format(EXCEPTION_STRING, modelClass, values,
names);
throw new DuplicatePropertySetException(msg);
}
private Query getQuery(Session session) {
String modelName = getModelClass().getName();
String propertyNames = StringUtil.join(getPropertyNames(), ", "); //$NON-NLS-1$
String valueBindings = getValueBindings();
String notSelfCondition = getNotSelfCondition();
String hql = MessageFormat.format(HQL, modelName, propertyNames,
valueBindings, notSelfCondition);
Query query = session.createQuery(hql);
setParameters(session, query);
return query;
}
private String getValueBindings() {
StringBuilder sb = new StringBuilder();
for (int i = 1, n = properties.size(); i <= n; i++) {
sb.append("?"); //$NON-NLS-1$
if (i < n) {
sb.append(","); //$NON-NLS-1$
}
}
return sb.toString();
}
private void setParameters(Session session, Query query) {
List<Object> values = getValues(session);
for (int i = 0, n = values.size(); i < n; i++) {
query.setParameter(i, values.get(i));
}
}
private String getNotSelfCondition() {
String idCheck = ""; //$NON-NLS-1$
Integer id = getModelId();
if (id != null) {
String idName = getIdProperty().getName();
idCheck = " AND " + idName + " <> " + id; //$NON-NLS-1$ //$NON-NLS-2$
}
return idCheck;
}
private List<String> getPropertyNames() {
List<String> propertyNames = new ArrayList<String>();
for (Property<?, ? super E> property : properties) {
propertyNames.add(property.getName());
}
return propertyNames;
}
private List<Object> getValues(Session session) {
List<Object> values = new ArrayList<Object>();
E model = getModel();
for (Property<?, ? super E> property : properties) {
GetterInterceptor lazyLoad = new LazyLoaderInterceptor(session, 1);
Object value = property.get(model, lazyLoad);
values.add(value);
}
return values;
}
}