package ru.hflabs.rcd.service.document; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; import ru.hflabs.rcd.accessor.FieldAccessor; import ru.hflabs.rcd.model.Essence; import ru.hflabs.rcd.model.Identifying; import ru.hflabs.rcd.model.path.MetaFieldNamedPath; import ru.hflabs.rcd.model.rule.Rule; import ru.hflabs.rcd.service.IMergeService; import java.util.Collection; import java.util.Map; import static ru.hflabs.rcd.accessor.Accessors.shallowClone; import static ru.hflabs.rcd.model.ModelUtils.ID_FUNCTION; /** * Класс <class>RuleActualizeService</class> реализует сервис актуализации правил перекодирования по изменившимся зависимым документами * * @param <D> класс зависимых документов * @param <NP> класс именованного пути документа * @param <T> класс базовой сущности правила * @param <R> класс правила перекодирования * @author Nazin Alexander */ public class RuleActualizeService<D extends Identifying, NP extends MetaFieldNamedPath, T extends Essence, R extends Rule<NP, T, R>> implements IMergeService<Collection<D>, Collection<R>, Collection<R>> { /** Сервис доступа к зависимой сущности */ private final FieldAccessor<D, T> dependencyAccessor; /** Сервис доступа к источнику */ private final FieldAccessor<T, R> fromFieldAccessor; /** Сервис доступа к назначению */ private final FieldAccessor<T, R> toFieldAccessor; public RuleActualizeService(FieldAccessor<D, T> dependencyAccessor, FieldAccessor<T, R> fromFieldAccessor, FieldAccessor<T, R> toFieldAccessor) { this.dependencyAccessor = dependencyAccessor; this.fromFieldAccessor = fromFieldAccessor; this.toFieldAccessor = toFieldAccessor; } /** * Выполняет актуализацию правила * * @param rule целевое правило * @param dependency новая зависимость (may be <code>NULL</code>) * @param fieldAccessor сервис доступа к базовому полю * @return Возвращает актуализированное правило */ private R doMerge(R rule, D dependency, FieldAccessor<T, R> fieldAccessor) { if (dependency != null) { // Выполняем актуализацию поля T targetField = dependencyAccessor.inject(fieldAccessor.apply(rule), dependency); // Актуализируем и возвращаем правило return fieldAccessor.inject(rule, targetField); } // Возвращаем исходное правило return rule; } /** * Выполняет актуализацию правила * * @param source исходное правило * @param target целевое правило * @param id2dependency карта зависимостей * @return Возвращает актуализированное правило */ private R doMerge(R source, R target, Map<String, D> id2dependency) { String fromDependencyId = ID_FUNCTION.apply(dependencyAccessor.apply(source.getFrom())); target = doMerge(target, id2dependency.get(fromDependencyId), fromFieldAccessor); String toDependencyId = ID_FUNCTION.apply(dependencyAccessor.apply(source.getTo())); target = doMerge(target, id2dependency.get(toDependencyId), toFieldAccessor); return target; } @Override public Collection<R> merge(Collection<D> dependencies, Collection<R> rules) { // Выполняем построение карты зависимых сущностей к их идентификаторам Map<String, D> id2dependency = Maps.uniqueIndex(dependencies, ID_FUNCTION); // Выполняем обновление правил ImmutableList.Builder<R> result = ImmutableList.builder(); for (R rule : rules) { result.add(doMerge(rule, shallowClone(rule), id2dependency)); } // Возвращаем обновленные правила return result.build(); } }