package ru.hflabs.rcd.storage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.SmartApplicationListener; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import ru.hflabs.rcd.event.ContextEvent; import ru.hflabs.rcd.event.modify.ChangeEvent; import ru.hflabs.rcd.model.Identifying; import ru.hflabs.rcd.model.ModelOrder; import ru.hflabs.rcd.model.change.ChangeMode; import ru.hflabs.rcd.service.ISingleClassObserver; import java.util.Collection; /** * Класс <class>ChangeDocumentServiceTemplate</class> реализует базовый сервис изменения документов * * @author Nazin Alexander */ public abstract class ChangeServiceTemplate<E extends Identifying> implements ISingleClassObserver<E>, SmartApplicationListener, BeanNameAware { protected final Logger LOG = LoggerFactory.getLogger(getClass()); /** Идентификатор сервиса */ private String serviceId; /** Класс отслеживаемых документов */ private final Class<E> targetClass; /** Позиция слушателя, относительно других */ private int listenerOrder; public ChangeServiceTemplate(Class<E> targetClass) { this.targetClass = targetClass; this.listenerOrder = ModelOrder.getOrder(targetClass); } @Override public void setBeanName(String name) { this.serviceId = name; } @Override public int getOrder() { return listenerOrder; } public void setOrder(int order) { this.listenerOrder = order; } @Override public final Class<E> retrieveTargetClass() { return targetClass; } public String retrieveTargetClassName() { return retrieveTargetClass().getSimpleName(); } @Override public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { return ContextEvent.class.isAssignableFrom(eventType); } @Override public boolean supportsSourceType(Class<?> sourceType) { return true; } /** * Выполняет создание сущностей * * @param changed коллекция для создания * @return Возвращает созданные сущности */ protected abstract Collection<E> handleSelfCreateEvent(Collection<E> changed); /** * Выполняет обновление сущностей * * @param changed коллекция для обновления * @return Возвращает обновленные сущности */ protected abstract Collection<E> handleSelfUpdateEvent(Collection<E> changed); /** * Выполняет восстановление сущностей * * @param changed коллекция для обновления * @return Возвращает восстановленные сущности */ protected abstract Collection<E> handleSelfRestoreEvent(Collection<E> changed); /** * Выполняет закрытие сущностей * * @param changed коллекция для закрытия * @return Возвращает закрытые сущности */ protected abstract Collection<E> handleSelfCloseEvent(Collection<E> changed); /** * Выполняет обработку событий изменения отслеживаемых сущностей * * @param event событие */ protected void handleSelfChangeEvent(ChangeEvent event) { Collection<E> changed = event.getChanged(retrieveTargetClass()); // По типу события выпоняем модификацию документов в хранилище switch (event.getChangeType()) { case IGNORE: case SKIP: { break; } case CREATE: { handleSelfCreateEvent(changed); break; } case UPDATE: { handleSelfUpdateEvent(changed); break; } case RESTORE: { handleSelfRestoreEvent(changed); break; } case CLOSE: { handleSelfCloseEvent(changed); break; } default: { throw new UnsupportedOperationException( String.format("Change event '%s' not supported by '%s'", event.getChangeType(), getClass().getSimpleName()) ); } } } /** * Выполняет обработку события создания зависимых документов * * @param event событие */ protected void handleOtherCreateEvent(ChangeEvent event) { // do nothing } /** * Выполняет обработку события обновления зависимых документов * * @param event событие */ protected void handleOtherUpdateEvent(ChangeEvent event) { // do nothing } /** * Выполняет обработку события восстановления зависимых документов * * @param event событие */ private void handleOtherRestoreEvent(ChangeEvent event) { // do noting } /** * Выполняет обработку события закрытия зависимых документов * * @param event событие */ protected void handleOtherCloseEvent(ChangeEvent event) { // do nothing } /** * Выполняет обработку событий изменения документов, которые не отслеживаются данным сервисом * * @param event событие */ protected void handleOtherChangeEvent(ChangeEvent event) { if (!ChangeMode.ISOLATED.equals(event.getChangeMode())) { switch (event.getChangeType()) { case IGNORE: case SKIP: { break; } case CREATE: { handleOtherCreateEvent(event); break; } case UPDATE: { handleOtherUpdateEvent(event); break; } case RESTORE: { handleOtherRestoreEvent(event); break; } case CLOSE: { handleOtherCloseEvent(event); break; } default: { throw new UnsupportedOperationException(String.format("Event %s not supported by %s", event.getChangeType(), getClass().getName())); } } } } @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class) protected void handleChangeEvent(ChangeEvent event) { if (retrieveTargetClass().isAssignableFrom(event.getChangedClass())) { handleSelfChangeEvent(event); } else { handleOtherChangeEvent(event); } } /** * Выполняет обработку события приложения * * @param event событие */ protected void handleContextEvent(ContextEvent event) { if (event instanceof ChangeEvent) { handleChangeEvent((ChangeEvent) event); } } @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ContextEvent && ((ContextEvent) event).registryListener(serviceId)) { handleContextEvent((ContextEvent) event); } } }