@Override public void rollback(Throwable cause) { if (logger.isDebugEnabled()) { logger.debug("Rolling back Unit Of Work.", cause); } Assert.state(isActive() && phase().isBefore(Phase.ROLLBACK), () -> String.format("The UnitOfWork is in an incompatible phase: %s", phase())); Assert.state(isCurrent(), () -> "The UnitOfWork is not the current Unit of Work"); try { setRollbackCause(cause); changePhase(Phase.ROLLBACK); if (isRoot()) { changePhase(Phase.CLEANUP, Phase.CLOSED); } } finally { CurrentUnitOfWork.clear(this); } }
@Override public void start() { if (logger.isDebugEnabled()) { logger.debug("Starting Unit Of Work"); } Assert.state(Phase.NOT_STARTED.equals(phase()), () -> "UnitOfWork is already started"); rolledBack = false; onRollback(u -> rolledBack = true); CurrentUnitOfWork.ifStarted(parent -> { // we're nesting. this.parentUnitOfWork = parent; root().onCleanup(r -> changePhase(Phase.CLEANUP, Phase.CLOSED)); }); changePhase(Phase.STARTED); CurrentUnitOfWork.set(this); }
@Override public Connection getConnection() throws SQLException { if (!CurrentUnitOfWork.isStarted() || CurrentUnitOfWork.get().phase().isAfter(UnitOfWork.Phase.PREPARE_COMMIT)) { return delegate.getConnection();
@Override public Connection getConnection() throws SQLException { if (!CurrentUnitOfWork.isStarted() || CurrentUnitOfWork.get().phase().isAfter(UnitOfWork.Phase.PREPARE_COMMIT)) { return delegate.getConnection();
@Override public Connection getConnection() throws SQLException { if (!CurrentUnitOfWork.isStarted() || CurrentUnitOfWork.get().phase().isAfter(UnitOfWork.Phase.PREPARE_COMMIT)) { return delegate.getConnection();
if (u.parent().isPresent() && !u.parent().get().phase().isAfter(PREPARE_COMMIT)) { eventsQueue(u.parent().get()).addAll(eventQueue); } else { if (u.parent().isPresent() && !u.root().phase().isAfter(COMMIT)) { u.root().onCommit(w -> doWithEvents(this::commit, eventQueue)); } else { if (u.parent().isPresent() && !u.root().phase().isAfter(AFTER_COMMIT)) { u.root().afterCommit(w -> doWithEvents(this::afterCommit, eventQueue)); } else {
@Override public void publish(List<? extends EventMessage<?>> events) { Stream<MessageMonitor.MonitorCallback> ingested = events.stream().map(messageMonitor::onMessageIngested); if (CurrentUnitOfWork.isStarted()) { UnitOfWork<?> unitOfWork = CurrentUnitOfWork.get(); Assert.state(!unitOfWork.phase().isAfter(PREPARE_COMMIT), () -> "It is not allowed to publish events when the current Unit of Work has already been " + "committed. Please start a new Unit of Work before publishing events."); Assert.state(!unitOfWork.root().phase().isAfter(PREPARE_COMMIT), () -> "It is not allowed to publish events when the root Unit of Work has already been " + "committed."); unitOfWork.afterCommit(u -> ingested.forEach(MessageMonitor.MonitorCallback::reportSuccess)); unitOfWork.onRollback(uow -> ingested.forEach( message -> message.reportFailure(uow.getExecutionResult().getExceptionResult()) )); eventsQueue(unitOfWork).addAll(events); } else { try { prepareCommit(intercept(events)); commit(events); afterCommit(events); ingested.forEach(MessageMonitor.MonitorCallback::reportSuccess); } catch (Exception e) { ingested.forEach(m -> m.reportFailure(e)); throw e; } } }
if (u.parent().isPresent() && !u.parent().get().phase().isAfter(PREPARE_COMMIT)) { eventsQueue(u.parent().get()).addAll(eventQueue); } else { if (u.parent().isPresent() && !u.root().phase().isAfter(COMMIT)) { u.root().onCommit(w -> doWithEvents(this::commit, eventQueue)); } else { if (u.parent().isPresent() && !u.root().phase().isAfter(AFTER_COMMIT)) { u.root().afterCommit(w -> doWithEvents(this::afterCommit, eventQueue)); } else {
@Override public void publish(List<? extends EventMessage<?>> events) { Stream<MessageMonitor.MonitorCallback> ingested = events.stream().map(messageMonitor::onMessageIngested); if (CurrentUnitOfWork.isStarted()) { UnitOfWork<?> unitOfWork = CurrentUnitOfWork.get(); Assert.state(!unitOfWork.phase().isAfter(PREPARE_COMMIT), () -> "It is not allowed to publish events when the current Unit of Work has already been " + "committed. Please start a new Unit of Work before publishing events."); Assert.state(!unitOfWork.root().phase().isAfter(PREPARE_COMMIT), () -> "It is not allowed to publish events when the root Unit of Work has already been " + "committed."); unitOfWork.afterCommit(u -> ingested.forEach(MessageMonitor.MonitorCallback::reportSuccess)); unitOfWork.onRollback(u -> ingested.forEach(m -> m.reportFailure(u.getExecutionResult().getExceptionResult()))); eventsQueue(unitOfWork).addAll(events); } else { try { prepareCommit(intercept(events)); commit(events); afterCommit(events); ingested.forEach(MessageMonitor.MonitorCallback::reportSuccess); } catch (Exception e) { ingested.forEach(m -> m.reportFailure(e)); throw e; } } }
@Override public void rollback(Throwable cause) { if (logger.isDebugEnabled()) { logger.debug("Rolling back Unit Of Work.", cause); } Assert.state(isActive() && phase().isBefore(Phase.ROLLBACK), () -> String.format("The UnitOfWork is in an incompatible phase: %s", phase())); Assert.state(isCurrent(), () -> "The UnitOfWork is not the current Unit of Work"); try { setRollbackCause(cause); changePhase(Phase.ROLLBACK); if (isRoot()) { changePhase(Phase.CLEANUP, Phase.CLOSED); } } finally { CurrentUnitOfWork.clear(this); } }
@Override public void rollback(Throwable cause) { if (logger.isDebugEnabled()) { logger.debug("Rolling back Unit Of Work.", cause); } Assert.state(isActive() && phase().isBefore(Phase.ROLLBACK), () -> String.format("The UnitOfWork is in an incompatible phase: %s", phase())); Assert.state(isCurrent(), () -> "The UnitOfWork is not the current Unit of Work"); try { setRollbackCause(cause); changePhase(Phase.ROLLBACK); if (isRoot()) { changePhase(Phase.CLEANUP, Phase.CLOSED); } } finally { CurrentUnitOfWork.clear(this); } }
/** * Register handlers with the current Unit of Work that save or delete the given {@code aggregate} when * the Unit of Work is committed. * * @param aggregate The Aggregate to save or delete when the Unit of Work is committed */ protected void prepareForCommit(A aggregate) { if (UnitOfWork.Phase.STARTED.isBefore(CurrentUnitOfWork.get().phase())) { doCommit(aggregate); } else { CurrentUnitOfWork.get().onPrepareCommit(u -> { // If the aggregate isn't "managed" anymore, it means its state was invalidated by a rollback doCommit(aggregate); }); } }
/** * Adds a handler to the collection. Note that the order in which you register the handlers determines the order * in which they will be handled during the various stages of a unit of work. * * @param phase The phase of the unit of work to attach the handler to * @param handler The handler to invoke in the given phase */ public void addHandler(Phase phase, Consumer<UnitOfWork<T>> handler) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Adding handler {} for phase {}", handler.getClass().getName(), phase.toString()); } final Deque<Consumer<UnitOfWork<T>>> consumers = handlers.computeIfAbsent(phase, p -> new ArrayDeque<>()); if (phase.isReverseCallbackOrder()) { consumers.addFirst(handler); } else { consumers.add(handler); } }
/** * Register handlers with the current Unit of Work that save or delete the given {@code aggregate} when * the Unit of Work is committed. * * @param aggregate The Aggregate to save or delete when the Unit of Work is committed */ protected void prepareForCommit(A aggregate) { if (UnitOfWork.Phase.STARTED.isBefore(CurrentUnitOfWork.get().phase())) { doCommit(aggregate); } else { CurrentUnitOfWork.get().onPrepareCommit(u -> { // if the aggregate isn't "managed" anymore, it means its state was invalidated by a rollback doCommit(aggregate); }); } }
@Override public void start() { if (logger.isDebugEnabled()) { logger.debug("Starting Unit Of Work"); } Assert.state(Phase.NOT_STARTED.equals(phase()), () -> "UnitOfWork is already started"); rolledBack = false; onRollback(u -> rolledBack = true); CurrentUnitOfWork.ifStarted(parent -> { // we're nesting. this.parentUnitOfWork = parent; root().onCleanup(r -> changePhase(Phase.CLEANUP, Phase.CLOSED)); }); changePhase(Phase.STARTED); CurrentUnitOfWork.set(this); }
/** * Invoke the handlers in this collection attached to the given {@code phase}. * * @param unitOfWork The Unit of Work that is changing its phase * @param phase The phase for which attached handlers should be invoked */ @SuppressWarnings("unchecked") public void notifyHandlers(UnitOfWork<T> unitOfWork, Phase phase) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Notifying handlers for phase {}", phase.toString()); } Deque<Consumer<UnitOfWork<T>>> l = handlers.getOrDefault(phase, EMPTY); while (!l.isEmpty()) { l.remove().accept(unitOfWork); } }
@Override public void start() { if (logger.isDebugEnabled()) { logger.debug("Starting Unit Of Work"); } Assert.state(Phase.NOT_STARTED.equals(phase()), () -> "UnitOfWork is already started"); rolledBack = false; onRollback(u -> rolledBack = true); CurrentUnitOfWork.ifStarted(parent -> { // we're nesting. this.parentUnitOfWork = parent; root().onCleanup(r -> changePhase(Phase.CLEANUP, Phase.CLOSED)); }); changePhase(Phase.STARTED); CurrentUnitOfWork.set(this); }
/** * Adds a handler to the collection. Note that the order in which you register the handlers determines the order * in which they will be handled during the various stages of a unit of work. * * @param phase The phase of the unit of work to attach the handler to * @param handler The handler to invoke in the given phase */ public void addHandler(Phase phase, Consumer<UnitOfWork<T>> handler) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Adding handler {} for phase {}", handler.getClass().getName(), phase.toString()); } final Deque<Consumer<UnitOfWork<T>>> consumers = handlers.computeIfAbsent(phase, p -> new ArrayDeque<>()); if (phase.isReverseCallbackOrder()) { consumers.addFirst(handler); } else { consumers.add(handler); } }
/** * Invoke the handlers in this collection attached to the given {@code phase}. * * @param unitOfWork The Unit of Work that is changing its phase * @param phase The phase for which attached handlers should be invoked */ @SuppressWarnings("unchecked") public void notifyHandlers(UnitOfWork<T> unitOfWork, Phase phase) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Notifying handlers for phase {}", phase.toString()); } Deque<Consumer<UnitOfWork<T>>> l = handlers.getOrDefault(phase, EMPTY); while (!l.isEmpty()) { l.remove().accept(unitOfWork); } }