Package org.axonframework.unitofwork.nesting

Source Code of org.axonframework.unitofwork.nesting.TripleUnitOfWorkNestingTest$MyCommandHandler

/*
* Copyright (c) 2010-2012. Axon Framework
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.axonframework.unitofwork.nesting;

import org.axonframework.commandhandling.CommandBus;
import org.axonframework.commandhandling.GenericCommandMessage;
import org.axonframework.commandhandling.annotation.CommandHandler;
import org.axonframework.domain.DomainEventMessage;
import org.axonframework.domain.DomainEventStream;
import org.axonframework.domain.EventMessage;
import org.axonframework.domain.GenericDomainEventMessage;
import org.axonframework.domain.GenericEventMessage;
import org.axonframework.domain.MetaData;
import org.axonframework.domain.SimpleDomainEventStream;
import org.axonframework.domain.StubDomainEvent;
import org.axonframework.eventhandling.EventBus;
import org.axonframework.eventhandling.EventListener;
import org.axonframework.eventhandling.annotation.EventHandler;
import org.axonframework.eventsourcing.annotation.AbstractAnnotatedAggregateRoot;
import org.axonframework.eventsourcing.annotation.AggregateIdentifier;
import org.axonframework.eventsourcing.annotation.EventSourcingHandler;
import org.axonframework.eventstore.EventStore;
import org.axonframework.repository.Repository;
import org.axonframework.unitofwork.CurrentUnitOfWork;
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.*;

/**
* Rather extensive test that shows the existence of <a href="http://code.google.com/p/axonframework/issues/detail?id=204">issue
* #204</a>. This bug causes application to hang when using triply nested unit of work. The cleanup callbacks in the
* 3rd
* level of the hierarchy wasn't called, causing reentrant locks to stay active.
* <p/>
* This test does nesting to up to 4 levels, with 2 units of work on the same (second) level.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/contexts/triple_uow_nesting_test.xml"})
public class TripleUnitOfWorkNestingTest implements EventListener {

    @Autowired
    private CommandBus commandBus;

    @Autowired
    private EventStore eventStore;

    @Autowired
    private EventBus eventBus;

    @Autowired
    private PlatformTransactionManager transactionManager;

    private static String aggregateAIdentifier = "A";
    private static String aggregateBIdentifier = "B";

    private final ExecutorService executor = Executors.newFixedThreadPool(2);
    private List<EventMessage<?>> handledMessages;

    @Before
    public void setUp() throws Exception {
        eventBus.subscribe(this);
        handledMessages = new ArrayList<EventMessage<?>>();
        while (CurrentUnitOfWork.isStarted()) {
            CurrentUnitOfWork.get().rollback();
        }
    }

    @Test
    public void testLoopbackScenario() throws InterruptedException {
        TransactionStatus tx = transactionManager.getTransaction(new DefaultTransactionAttribute());
        eventStore.appendEvents("AggregateA", new SimpleDomainEventStream(
                new GenericDomainEventMessage<CreateEvent>(aggregateAIdentifier, (long) 0,
                                                           new CreateEvent(aggregateAIdentifier), MetaData.emptyInstance())));
        eventStore.appendEvents("AggregateB", new SimpleDomainEventStream(
                new GenericDomainEventMessage<CreateEvent>(aggregateBIdentifier, (long) 0,
                                                           new CreateEvent(aggregateBIdentifier), MetaData.emptyInstance())));
        transactionManager.commit(tx);
        assertEquals(1, toList(eventStore.readEvents("AggregateA", aggregateAIdentifier)).size());
        assertEquals(1, toList(eventStore.readEvents("AggregateB", aggregateBIdentifier)).size());
        commandBus.dispatch(GenericCommandMessage.asCommandMessage("hello"));

        assertEquals(5, toList(eventStore.readEvents("AggregateA", aggregateAIdentifier)).size());
        assertEquals(2, toList(eventStore.readEvents("AggregateB", aggregateBIdentifier)).size());

        for (int t = 0; t < 10; t++) {
            executor.submit(new SendCommandTask());
        }
        executor.shutdown();
        assertTrue("Commands did not execute in a reasonable time. Are there any unreleased locks remaining?",
                   executor.awaitTermination(2, TimeUnit.SECONDS));

        assertEquals(new HashSet(handledMessages).size(), handledMessages.size());
    }

    private List<DomainEventMessage> toList(DomainEventStream eventStream) {
        List<DomainEventMessage> events = new ArrayList<DomainEventMessage>();
        while (eventStream.hasNext()) {
            events.add(eventStream.next());
        }
        return events;
    }

    @Override
    public void handle(EventMessage event) {
        this.handledMessages.add(event);
    }

    public static class MyCommandHandler {

        @Autowired
        @Qualifier("aggregateARepository")
        private Repository<AggregateA> aggregateARepository;

        @Autowired
        @Qualifier("aggregateBRepository")
        private Repository<AggregateB> aggregateBRepository;

        @Autowired
        private EventBus eventBus;

        @CommandHandler
        public void handle(String stringCommand) {
            CurrentUnitOfWork.get().publishEvent(new GenericEventMessage<String>("Mock"), eventBus);
            aggregateARepository.load(aggregateAIdentifier).doSomething(stringCommand);
        }

        @CommandHandler
        public void handle(Object objectCommand) {
            CurrentUnitOfWork.get().publishEvent(new GenericEventMessage<String>("Mock"), eventBus);
            aggregateBRepository.load(aggregateBIdentifier).doSomething();
        }
    }

    public static class LoopbackSaga {

        @Autowired
        private CommandBus commandBus;

        @EventHandler
        public void handle(FirstEvent event) {
            commandBus.dispatch(GenericCommandMessage.asCommandMessage(new Object()));
            commandBus.dispatch(GenericCommandMessage.asCommandMessage("first"));
        }

        @EventHandler
        public void handle(SecondEvent event) {
            commandBus.dispatch(GenericCommandMessage.asCommandMessage("second"));
        }

        @EventHandler
        public void handle(ThirdEvent event) {
            commandBus.dispatch(GenericCommandMessage.asCommandMessage("third"));
        }
    }

    public static class FirstEvent {

    }

    public static class SecondEvent {

    }

    public static class ThirdEvent {

    }

    public static class AggregateA extends AbstractAnnotatedAggregateRoot {

        @AggregateIdentifier
        private String identifier;

        public AggregateA() {
        }

        @Override
        public Object getIdentifier() {
            return identifier;
        }

        @EventSourcingHandler
        private void handle(CreateEvent event) {
            this.identifier = event.getIdentifier();
        }

        public void doSomething(String stringCommand) {
            if ("hello".equalsIgnoreCase(stringCommand)) {
                apply(new FirstEvent());
            } else if ("second".equalsIgnoreCase(stringCommand)) {
                apply(new ThirdEvent());
            } else {
                apply(new StubDomainEvent());
            }
        }
    }

    public static class AggregateB extends AbstractAnnotatedAggregateRoot {

        @AggregateIdentifier
        private String identifier;

        public AggregateB() {
        }

        @EventSourcingHandler
        private void handle(CreateEvent event) {
            this.identifier = event.getIdentifier();
        }

        @Override
        public String getIdentifier() {
            return identifier;
        }

        public void doSomething() {
            apply(new SecondEvent());
        }
    }

    private static class CreateEvent {

        private String identifier;

        public CreateEvent(String identifier) {
            this.identifier = identifier;
        }

        public String getIdentifier() {
            return identifier;
        }
    }

    private class SendCommandTask implements Runnable {

        @Override
        public void run() {
            commandBus.dispatch(GenericCommandMessage.asCommandMessage("hello"));
        }
    }
}
TOP

Related Classes of org.axonframework.unitofwork.nesting.TripleUnitOfWorkNestingTest$MyCommandHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.