public interface Event extends Serializable {
	
} @AllArgsConstructor
public static class CreateCommandHandler implements CommandHandler<CreateInventoryItem> {

    @Delegate @NonNull
    final InventoryItemAggregateRoot aggregateRoot;
    @NonNull
    final ItemDescriptionGeneratorService service;

    public List<? extends Event> handle(CreateInventoryItem command) {
        checkArgument(getId() == null, "item already exists");
        checkNotNull(service);
        String description = service.generate(command.getId());
        InventoryItemCreated event = new InventoryItemCreated(command.getId(), description);
        return Arrays.asList(event);
    }
} @Value
public static class CreateInventoryItem implements Command {
    @NonNull
    UUID commandId;
    @NonNull
    UUID id;
    Long targetVersion = 0L;
} @AllArgsConstructor
public static class DecreaseCommandHandler implements CommandHandler<DecreaseInventory> {

    @Delegate @NonNull
    final InventoryItemAggregateRoot aggregateRoot;

    public List<? extends Event> handle(DecreaseInventory command) {
        checkArgument(getId() != null, "before decreasing you must create an item");
        checkArgument(getId().equals(command.getId()), "item id does not match");
        checkArgument(isAvailable(command.howMany), "there are not enough items available");
        InventoryDecreased event = new InventoryDecreased(command.getId(), command.getHowMany());
        return Arrays.asList(event);
    }
} @Value
public static class DecreaseInventory implements Command {
    @NonNull
    UUID commandId;
    @NonNull
    UUID id;
    @NonNull
    Integer howMany;
    Long targetVersion;
} @AllArgsConstructor
public static class IncreaseCommandHandler implements CommandHandler<IncreaseInventory> {

    @Delegate @NonNull
    final InventoryItemAggregateRoot aggregateRoot;

    public List<? extends Event> handle(IncreaseInventory command) {
        checkArgument(getId() != null, "before increasing you must create an item");
        checkArgument(getId().equals(command.getId()), "item id does not match");
        InventoryIncreased event = new InventoryIncreased(command.getId(), command.getHowMany());
        return Arrays.asList(event);
    }
} @Value
public static class IncreaseInventory implements Command {
    @NonNull
    UUID commandId;
    @NonNull
    UUID id;
    @NonNull
    Integer howMany;
    Long targetVersion;
} @Value
public static class InventoryDecreased implements Event {
    @NonNull
    UUID id;
    @NonNull
    Integer howMany;
} @Value
public static class InventoryIncreased implements Event {
    @NonNull
    UUID id;
    @NonNull
    Integer howMany;
} @Data
public static class InventoryItemAggregateRoot implements AggregateRoot {

    UUID id;
    String description;
    Integer available = 0;

    public void on(InventoryItemCreated event) {
        this.id = event.id;
        this.description = event.description;
        this.available = 0;
    }

    public void on(InventoryIncreased event) {
        this.available = this.available + event.howMany;
    }

    public void on(InventoryDecreased event) {
        this.available = this.available - event.howMany;
    }
        
    public boolean isAvailable(int howMany) {
        return getAvailable() - howMany >= 0;
    }

} @Value
public static class InventoryItemCreated implements Event {
    @NonNull
    UUID id;
    @NonNull
    String description;
} public static interface ItemDescriptionGeneratorService {
    String generate(UUID id);
}
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.UUID;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.myeslib.core.Event;
import org.myeslib.example.SampleDomain.CreateCommandHandler;
import org.myeslib.example.SampleDomain.CreateInventoryItem;
import org.myeslib.example.SampleDomain.DecreaseCommandHandler;
import org.myeslib.example.SampleDomain.DecreaseInventory;
import org.myeslib.example.SampleDomain.IncreaseCommandHandler;
import org.myeslib.example.SampleDomain.IncreaseInventory;
import org.myeslib.example.SampleDomain.InventoryDecreased;
import org.myeslib.example.SampleDomain.InventoryIncreased;
import org.myeslib.example.SampleDomain.InventoryItemAggregateRoot;
import org.myeslib.example.SampleDomain.InventoryItemCreated;
import org.myeslib.example.SampleDomain.ItemDescriptionGeneratorService;
package org.myeslib.example;




@RunWith(MockitoJUnitRunner.class)
public class InventoryItemCommandHandlerTest {

	@Mock
	ItemDescriptionGeneratorService uuidGeneratorService ;

	@Test(expected=NullPointerException.class)
	public void createWithNullService() {
		
		InventoryItemAggregateRoot aggregateRoot = new InventoryItemAggregateRoot();
		
		CreateInventoryItem command = new CreateInventoryItem(UUID.randomUUID(), UUID.randomUUID());
		
		CreateCommandHandler commandHandler = new CreateCommandHandler(aggregateRoot, null);
		
		commandHandler.handle(command);
	}
	
	
	@Test(expected=IllegalArgumentException.class)
	public void createOnAnExistingInstance() {
		
		InventoryItemAggregateRoot aggregateRoot = new InventoryItemAggregateRoot();
		
		UUID id = UUID.randomUUID();
		
		aggregateRoot.setId(id);
		
		CreateInventoryItem command = new CreateInventoryItem(UUID.randomUUID(), id);
		
		CreateCommandHandler commandHandler = new CreateCommandHandler(aggregateRoot, uuidGeneratorService);
	
		commandHandler.handle(command);
	
	}
	
	
	@Test(expected=IllegalArgumentException.class)
	public void increaseOnAnWrongInstance() {
		
		InventoryItemAggregateRoot aggregateRoot = new InventoryItemAggregateRoot();
		
		UUID id = UUID.randomUUID();
		
		aggregateRoot.setId(id);
		
		IncreaseInventory command = new IncreaseInventory(UUID.randomUUID(), UUID.randomUUID(), 1, 0L);