package ru.hflabs.rcd.service.document.metaField;
import org.springframework.validation.Errors;
import ru.hflabs.rcd.exception.constraint.IllegalPrimaryKeyException;
import ru.hflabs.rcd.exception.constraint.document.NotUniqueFieldsException;
import ru.hflabs.rcd.exception.search.document.UnknownMetaFieldException;
import ru.hflabs.rcd.model.ModelUtils;
import ru.hflabs.rcd.model.document.Field;
import ru.hflabs.rcd.model.document.MetaField;
import ru.hflabs.rcd.model.path.MetaFieldNamedPath;
import ru.hflabs.rcd.service.document.IDictionaryService;
import ru.hflabs.rcd.service.document.IFieldService;
import ru.hflabs.rcd.service.document.IMetaFieldService;
import ru.hflabs.rcd.service.document.NamedDocumentChangeValidator;
import static ru.hflabs.rcd.accessor.Accessors.DICTIONARY_TO_META_FIELD_INJECTOR;
import static ru.hflabs.rcd.accessor.Accessors.GROUP_TO_META_FIELD_INJECTOR;
import static ru.hflabs.rcd.model.CriteriaUtils.createCriteriaByIDs;
/**
* Класс <class>MetaFieldValidator</class> реализует сервис валидации изменения МЕТА-полей справочника
*
* @author Nazin Alexander
*/
public class MetaFieldChangeValidator extends NamedDocumentChangeValidator<MetaField, IMetaFieldService> {
/** Сервис работы со справочниками */
private IDictionaryService dictionaryService;
/** Сервис работы со значениями полей справочников */
private IFieldService fieldService;
public MetaFieldChangeValidator(boolean mustExist) {
super(MetaField.class, mustExist, UnknownMetaFieldException.class);
}
public void setDictionaryService(IDictionaryService dictionaryService) {
this.dictionaryService = dictionaryService;
}
public void setFieldService(IFieldService fieldService) {
this.fieldService = fieldService;
}
@Override
protected MetaField findUniqueByName(MetaField target) {
return getDocumentService().findUniqueByRelativeId(target.getDictionaryId(), target.getName(), false, true);
}
/**
* Выполняет валидацию установки {@link MetaField#FLAG_PRIMARY первичного флага}
*
* @param errors контейнер ошибок
* @param newObject обновляемое МЕТА-поле
* @param oldObject существущее МЕТА-поле или <code>NULL</code>
*/
private void doValidatePrimaryFlag(Errors errors, MetaField newObject, MetaField oldObject) {
boolean illegalChange = newObject.isFlagEstablished(MetaField.FLAG_PRIMARY) && (oldObject == null || !oldObject.isFlagEstablished(MetaField.FLAG_PRIMARY));
illegalChange = illegalChange || !newObject.isFlagEstablished(MetaField.FLAG_PRIMARY) && (oldObject != null && oldObject.isFlagEstablished(MetaField.FLAG_PRIMARY));
if (illegalChange) {
reject(errors, new NotUniqueFieldsException(ModelUtils.createMetaFieldNamedPath(newObject)), newObject.getName());
}
}
/**
* Выполняет валидацию установки {@link MetaField#FLAG_UNIQUE уникального флага}
*
* @param errors контейнер ошибок
* @param newObject обновляемое МЕТА-поле
* @param oldObject существущее МЕТА-поле или <code>NULL</code>
*/
private void doValidateUniqueFlag(Errors errors, MetaField newObject, MetaField oldObject) {
if (newObject.isFlagEstablished(MetaField.FLAG_UNIQUE) && (oldObject == null || !oldObject.isFlagEstablished(MetaField.FLAG_UNIQUE))) {
if (!fieldService.isFieldsUnique(newObject.getId())) {
reject(errors, new NotUniqueFieldsException(ModelUtils.createMetaFieldNamedPath(newObject)), newObject.getName());
}
}
}
/**
* Выполняет валидацию количества {@link ru.hflabs.rcd.model.document.Field значений полей}
*
* @param errors контейнер ошибок
* @param metaField уникальное МЕТА-поле
*/
private void doValidateFieldCount(Errors errors, MetaField metaField) {
// Если МЕТА-поле помечено как уникальное и не является первичным ключем,
// то количество полей для первичного ключа должно совпадать с количеством полей текущего МЕТА-поля
// для корректного формирования записей справочника
if (!metaField.isFlagEstablished(MetaField.FLAG_PRIMARY) && metaField.isFlagEstablished(MetaField.FLAG_UNIQUE)) {
MetaFieldNamedPath metaFieldNamedPath = ModelUtils.createMetaFieldNamedPath(metaField);
// Получаем количество значений полей по текущему полю
int currentFieldsCount = fieldService.countByCriteria(createCriteriaByIDs(Field.META_FIELD_ID, metaField.getId()));
// Получаем количество значений полей по первичному полю
MetaField primaryMetaField = getDocumentService().findPrimaryMetaFieldByNamedPath(metaFieldNamedPath, false);
int primaryFieldsCount = fieldService.countByCriteria(createCriteriaByIDs(Field.META_FIELD_ID, primaryMetaField.getId()));
// Проверяем количество
if (currentFieldsCount != primaryFieldsCount) {
reject(errors, new NotUniqueFieldsException(metaFieldNamedPath), metaField.getName());
}
}
}
/**
* Выполняет валидацию установленных флагов МЕТА-поля
*
* @param errors контейнер ошибок
* @param newObject обновляемое МЕТА-поле
* @param oldObject существущее МЕТА-поле или <code>NULL</code>
*/
protected void doValidateFlags(Errors errors, MetaField newObject, MetaField oldObject) {
// Проверяем первичный ключ
if (!errors.hasErrors()) {
doValidatePrimaryFlag(errors, newObject, oldObject);
}
// Проверяем количество значений полей
if (!errors.hasErrors()) {
doValidateFieldCount(errors, newObject);
}
// Проверяем уникальность
if (!errors.hasErrors()) {
doValidateUniqueFlag(errors, newObject, oldObject);
}
}
@Override
protected void doValidateCommon(Errors errors, MetaField target) {
String relativeId = DICTIONARY_TO_META_FIELD_INJECTOR.applyRelativeId(target);
try {
DICTIONARY_TO_META_FIELD_INJECTOR.inject(target, dictionaryService.findByID(relativeId, true, false));
doValidatePermissions(errors, GROUP_TO_META_FIELD_INJECTOR.apply(target));
} catch (IllegalPrimaryKeyException ex) {
reject(errors, ex, relativeId);
}
}
/**
* Класс <class>Create</class> реализует валидатор создания МЕТА-поля
*
* @author Nazin Alexander
*/
public static class Create extends MetaFieldChangeValidator {
public Create() {
super(false);
}
@Override
protected void doValidateCommon(Errors errors, MetaField target) {
super.doValidateCommon(errors, target);
if (!errors.hasErrors()) {
// Устанавливаем позицию поля относительно других
int metaFieldsCount = getDocumentService().countByCriteria(
createCriteriaByIDs(MetaField.DICTIONARY_ID, target.getDictionaryId())
);
target.setOrdinal(metaFieldsCount);
// Проверяем флаги
doValidateFlags(errors, target, null);
}
}
}
/**
* Класс <class>Update</class> реализует валидатор обновления МЕТА-поля
*
* @author Nazin Alexander
*/
public static class Update extends MetaFieldChangeValidator {
public Update() {
super(true);
}
@Override
protected void validateNewToOld(Errors errors, MetaField newObject, MetaField oldObject) {
super.validateNewToOld(errors, newObject, oldObject);
// Восстанавливаем позицию МЕТА-поля
newObject.setOrdinal(oldObject.getOrdinal());
// Восстанавливаем старое значение первичного ключа
if (oldObject.isFlagEstablished(MetaField.FLAG_PRIMARY)) {
newObject.establishFlags(MetaField.FLAG_PRIMARY);
}
// Проверяем флаги
doValidateFlags(errors, newObject, oldObject);
}
}
}