events) {
+ this.events = events;
+ }
+
+ @Override
+ public T getIdentity() {
+ return identity;
+ }
+
+ public void setIdentity(T id) {
+ this.identity = id;
+ }
+
@Override
public String toString() {
return "BaseEntity{" +
@@ -45,4 +71,4 @@ public class BaseEntity extends ResourceSupport implements Serializable {
", lastModified=" + lastModified +
'}';
}
-}
+}
\ No newline at end of file
diff --git a/account/account-web/src/main/java/demo/event/AccountEvent.java b/account/account-web/src/main/java/demo/event/AccountEvent.java
index 97d53dd..b5fde9a 100644
--- a/account/account-web/src/main/java/demo/event/AccountEvent.java
+++ b/account/account-web/src/main/java/demo/event/AccountEvent.java
@@ -2,33 +2,40 @@ package demo.event;
import com.fasterxml.jackson.annotation.JsonIgnore;
import demo.account.Account;
-import demo.domain.BaseEntity;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
/**
- * The domain event {@link AccountEvent} tracks the type and state of events as
- * applied to the {@link Account} domain object. This event resource can be used
- * to event source the aggregate state of {@link Account}.
+ * The domain event {@link AccountEvent} tracks the type and state of events as applied to the {@link Account} domain
+ * object. This event resource can be used to event source the aggregate state of {@link Account}.
*
- * This event resource also provides a transaction log that can be used to append
- * actions to the event.
+ * This event resource also provides a transaction log that can be used to append actions to the event.
*
- * @author kbastani
+ * @author Kenny Bastani
*/
@Entity
-public class AccountEvent extends BaseEntity {
+@EntityListeners(AuditingEntityListener.class)
+public class AccountEvent extends Event {
@Id
- @GeneratedValue
- private Long id;
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Long eventId;
@Enumerated(EnumType.STRING)
private AccountEventType type;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JsonIgnore
- private Account account;
+ private Account entity;
+
+ @CreatedDate
+ private Long createdAt;
+
+ @LastModifiedDate
+ private Long lastModified;
public AccountEvent() {
}
@@ -37,37 +44,69 @@ public class AccountEvent extends BaseEntity {
this.type = type;
}
- @JsonIgnore
+ public AccountEvent(AccountEventType type, Account entity) {
+ this.type = type;
+ this.entity = entity;
+ }
+
+ @Override
public Long getEventId() {
- return id;
+ return eventId;
}
+ @Override
public void setEventId(Long id) {
- this.id = id;
+ eventId = id;
}
+ @Override
public AccountEventType getType() {
return type;
}
+ @Override
public void setType(AccountEventType type) {
this.type = type;
}
- public Account getAccount() {
- return account;
+ @Override
+ public Account getEntity() {
+ return entity;
}
- public void setAccount(Account account) {
- this.account = account;
+ @Override
+ public void setEntity(Account entity) {
+ this.entity = entity;
+ }
+
+ @Override
+ public Long getCreatedAt() {
+ return createdAt;
+ }
+
+ @Override
+ public void setCreatedAt(Long createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ @Override
+ public Long getLastModified() {
+ return lastModified;
+ }
+
+ @Override
+ public void setLastModified(Long lastModified) {
+ this.lastModified = lastModified;
}
@Override
public String toString() {
return "AccountEvent{" +
- "id=" + id +
+ "eventId=" + eventId +
", type=" + type +
- ", account=" + account +
+ ", entity=" + entity +
+ ", createdAt=" + createdAt +
+ ", lastModified=" + lastModified +
"} " + super.toString();
}
}
diff --git a/account/account-web/src/main/java/demo/event/AccountEventRepository.java b/account/account-web/src/main/java/demo/event/AccountEventRepository.java
new file mode 100644
index 0000000..465d40d
--- /dev/null
+++ b/account/account-web/src/main/java/demo/event/AccountEventRepository.java
@@ -0,0 +1,4 @@
+package demo.event;
+
+public interface AccountEventRepository extends EventRepository {
+}
diff --git a/account/account-web/src/main/java/demo/event/AccountEvents.java b/account/account-web/src/main/java/demo/event/AccountEvents.java
deleted file mode 100644
index f45e8de..0000000
--- a/account/account-web/src/main/java/demo/event/AccountEvents.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package demo.event;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import demo.account.Account;
-import demo.account.AccountController;
-import org.springframework.hateoas.Link;
-import org.springframework.hateoas.LinkBuilder;
-import org.springframework.hateoas.Resources;
-
-import java.io.Serializable;
-import java.util.List;
-
-import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
-
-/**
- * The {@link AccountEvents} is a hypermedia collection of {@link AccountEvent} resources.
- *
- * @author kbastani
- */
-public class AccountEvents extends Resources implements Serializable {
-
- private Long accountId;
-
- /**
- * Create a new {@link AccountEvents} hypermedia resources collection for an {@link Account}.
- *
- * @param accountId is the unique identifier for the {@link Account}
- * @param content is the collection of {@link AccountEvents} attached to the {@link Account}
- */
- public AccountEvents(Long accountId, List content) {
- this(content);
- this.accountId = accountId;
-
- // Add hypermedia links to resources parent
- add(linkTo(AccountController.class)
- .slash("accounts")
- .slash(accountId)
- .slash("events")
- .withSelfRel(),
- linkTo(AccountController.class)
- .slash("accounts")
- .slash(accountId)
- .withRel("account"));
-
- LinkBuilder linkBuilder = linkTo(EventController.class);
-
- // Add hypermedia links to each item of the collection
- content.stream().parallel().forEach(event -> event.add(
- linkBuilder.slash("events")
- .slash(event.getEventId())
- .withSelfRel()
- ));
- }
-
- /**
- * Creates a {@link Resources} instance with the given content and {@link Link}s (optional).
- *
- * @param content must not be {@literal null}.
- * @param links the links to be added to the {@link Resources}.
- */
- private AccountEvents(Iterable content, Link... links) {
- super(content, links);
- }
-
- /**
- * Get the {@link Account} identifier that the {@link AccountEvents} apply to.
- *
- * @return the account identifier
- */
- @JsonIgnore
- public Long getAccountId() {
- return accountId;
- }
-}
diff --git a/account/account-web/src/main/java/demo/event/ConsistencyModel.java b/account/account-web/src/main/java/demo/event/ConsistencyModel.java
deleted file mode 100644
index 8bef081..0000000
--- a/account/account-web/src/main/java/demo/event/ConsistencyModel.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package demo.event;
-
-public enum ConsistencyModel {
- BASE,
- ACID
-}
diff --git a/account/account-web/src/main/java/demo/event/EventController.java b/account/account-web/src/main/java/demo/event/EventController.java
deleted file mode 100644
index 125ed8d..0000000
--- a/account/account-web/src/main/java/demo/event/EventController.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package demo.event;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.Optional;
-
-@RestController
-@RequestMapping("/v1")
-public class EventController {
-
- private final EventService eventService;
-
- public EventController(EventService eventService) {
- this.eventService = eventService;
- }
-
- @PostMapping(path = "/events/{id}")
- public ResponseEntity createEvent(@RequestBody AccountEvent event, @PathVariable Long id) {
- return Optional.ofNullable(eventService.createEvent(id, event, ConsistencyModel.ACID))
- .map(e -> new ResponseEntity<>(e, HttpStatus.CREATED))
- .orElseThrow(() -> new IllegalArgumentException("Event creation failed"));
- }
-
- @PutMapping(path = "/events/{id}")
- public ResponseEntity updateEvent(@RequestBody AccountEvent event, @PathVariable Long id) {
- return Optional.ofNullable(eventService.updateEvent(id, event))
- .map(e -> new ResponseEntity<>(e, HttpStatus.OK))
- .orElseThrow(() -> new IllegalArgumentException("Event update failed"));
- }
-
- @GetMapping(path = "/events/{id}")
- public ResponseEntity getEvent(@PathVariable Long id) {
- return Optional.ofNullable(eventService.getEvent(id))
- .map(e -> new ResponseEntity<>(e, HttpStatus.OK))
- .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
- }
-}
diff --git a/account/account-web/src/main/java/demo/event/EventRepository.java b/account/account-web/src/main/java/demo/event/EventRepository.java
deleted file mode 100644
index 273ba3b..0000000
--- a/account/account-web/src/main/java/demo/event/EventRepository.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package demo.event;
-
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.repository.query.Param;
-
-public interface EventRepository extends JpaRepository {
- Page findAccountEventsByAccountId(@Param("accountId") Long accountId, Pageable pageable);
-}
diff --git a/account/account-web/src/main/java/demo/event/EventService.java b/account/account-web/src/main/java/demo/event/EventService.java
deleted file mode 100644
index c4c06d9..0000000
--- a/account/account-web/src/main/java/demo/event/EventService.java
+++ /dev/null
@@ -1,214 +0,0 @@
-package demo.event;
-
-import demo.account.Account;
-import demo.account.AccountController;
-import org.apache.log4j.Logger;
-import org.springframework.cache.annotation.CacheConfig;
-import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.cloud.stream.messaging.Source;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.hateoas.MediaTypes;
-import org.springframework.hateoas.Resource;
-import org.springframework.http.RequestEntity;
-import org.springframework.integration.support.MessageBuilder;
-import org.springframework.stereotype.Service;
-import org.springframework.util.Assert;
-import org.springframework.web.client.RestTemplate;
-
-import java.net.URI;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
-
-/**
- * The {@link EventService} provides transactional service methods for {@link AccountEvent}
- * entities of the Account Service. Account domain events are generated with a {@link AccountEventType},
- * and action logs are appended to the {@link AccountEvent}.
- *
- * @author kbastani
- */
-@Service
-@CacheConfig(cacheNames = {"events"})
-public class EventService {
-
- private final Logger log = Logger.getLogger(EventService.class);
-
- private final EventRepository eventRepository;
- private final Source accountStreamSource;
- private final RestTemplate restTemplate;
-
- public EventService(EventRepository eventRepository, Source accountStreamSource, RestTemplate restTemplate) {
- this.eventRepository = eventRepository;
- this.accountStreamSource = accountStreamSource;
- this.restTemplate = restTemplate;
- }
-
- /**
- * Create a new {@link AccountEvent} and append it to the event log of the referenced {@link Account}.
- * After the {@link AccountEvent} has been persisted, send the event to the account stream. Events can
- * be raised as a blocking or non-blocking operation depending on the {@link ConsistencyModel}.
- *
- * @param accountId is the unique identifier for the {@link Account}
- * @param event is the {@link AccountEvent} to create
- * @param consistencyModel is the desired consistency model for the response
- * @return an {@link AccountEvent} that has been appended to the {@link Account}'s event log
- */
- public AccountEvent createEvent(Long accountId, AccountEvent event, ConsistencyModel consistencyModel) {
- event = createEvent(accountId, event);
- return raiseEvent(event, consistencyModel);
- }
-
- /**
- * Raise an {@link AccountEvent} that attempts to transition the state of an {@link Account}.
- *
- * @param event is an {@link AccountEvent} that will be raised
- * @param consistencyModel is the consistency model for this request
- * @return an {@link AccountEvent} that has been appended to the {@link Account}'s event log
- */
- public AccountEvent raiseEvent(AccountEvent event, ConsistencyModel consistencyModel) {
- switch (consistencyModel) {
- case BASE:
- asyncRaiseEvent(event);
- break;
- case ACID:
- event = raiseEvent(event);
- break;
- }
-
- return event;
- }
-
- /**
- * Raise an asynchronous {@link AccountEvent} by sending an AMQP message to the account stream. Any
- * state changes will be applied to the {@link Account} outside of the current HTTP request context.
- *
- * Use this operation when a workflow can be processed asynchronously outside of the current HTTP
- * request context.
- *
- * @param event is an {@link AccountEvent} that will be raised
- */
- private void asyncRaiseEvent(AccountEvent event) {
- // Append the account event to the stream
- accountStreamSource.output()
- .send(MessageBuilder
- .withPayload(getAccountEventResource(event))
- .build());
- }
-
- /**
- * Raise a synchronous {@link AccountEvent} by sending a HTTP request to the account stream. The response
- * is a blocking operation, which ensures that the result of a multi-step workflow will not return until
- * the transaction reaches a consistent state.
- *
- * Use this operation when the result of a workflow must be returned within the current HTTP request context.
- *
- * @param event is an {@link AccountEvent} that will be raised
- * @return an {@link AccountEvent} which contains the consistent state of an {@link Account}
- */
- private AccountEvent raiseEvent(AccountEvent event) {
- try {
- // Create a new request entity
- RequestEntity> requestEntity = RequestEntity.post(
- URI.create("http://localhost:8081/v1/events"))
- .contentType(MediaTypes.HAL_JSON)
- .body(getAccountEventResource(event), Resource.class);
-
- // Update the account entity's status
- Account result = restTemplate.exchange(requestEntity, Account.class)
- .getBody();
-
- log.info(result);
- event.setAccount(result);
- } catch (Exception ex) {
- log.error(ex);
- }
-
- return event;
- }
-
-
- /**
- * Create a new {@link AccountEvent} and publish it to the account stream.
- *
- * @param event is the {@link AccountEvent} to publish to the account stream
- * @return a hypermedia {@link AccountEvent} resource
- */
- @CacheEvict(cacheNames = "events", key = "#id.toString()")
- public AccountEvent createEvent(Long id, AccountEvent event) {
- // Save new event
- event = addEvent(event);
- Assert.notNull(event, "The event could not be appended to the account");
-
- return event;
- }
-
- /**
- * Get an {@link AccountEvent} with the supplied identifier.
- *
- * @param id is the unique identifier for the {@link AccountEvent}
- * @return an {@link AccountEvent}
- */
- public Resource getEvent(Long id) {
- return getAccountEventResource(eventRepository.findOne(id));
- }
-
- /**
- * Update an {@link AccountEvent} with the supplied identifier.
- *
- * @param id is the unique identifier for the {@link AccountEvent}
- * @param event is the {@link AccountEvent} to update
- * @return the updated {@link AccountEvent}
- */
- @CacheEvict(cacheNames = "events", key = "#event.getAccount().getAccountId().toString()")
- public AccountEvent updateEvent(Long id, AccountEvent event) {
- Assert.notNull(id);
- Assert.isTrue(event.getId() == null || Objects.equals(id, event.getId()));
-
- return eventRepository.save(event);
- }
-
- /**
- * Get {@link AccountEvents} for the supplied {@link Account} identifier.
- *
- * @param id is the unique identifier of the {@link Account}
- * @return a list of {@link AccountEvent} wrapped in a hypermedia {@link AccountEvents} resource
- */
- @Cacheable(cacheNames = "events", key = "#id.toString()")
- public List getAccountEvents(Long id) {
- return eventRepository.findAccountEventsByAccountId(id,
- new PageRequest(0, Integer.MAX_VALUE)).getContent();
- }
-
- /**
- * Gets a hypermedia resource for a {@link AccountEvent} entity.
- *
- * @param event is the {@link AccountEvent} to enrich with hypermedia
- * @return a hypermedia resource for the supplied {@link AccountEvent} entity
- */
- private Resource getAccountEventResource(AccountEvent event) {
- return new Resource(event, Arrays.asList(
- linkTo(AccountController.class)
- .slash("events")
- .slash(event.getEventId())
- .withSelfRel(),
- linkTo(AccountController.class)
- .slash("accounts")
- .slash(event.getAccount().getAccountId())
- .withRel("account")));
- }
-
- /**
- * Add a {@link AccountEvent} to an {@link Account} entity.
- *
- * @param event is the {@link AccountEvent} to append to an {@link Account} entity
- * @return the newly appended {@link AccountEvent} entity
- */
- @CacheEvict(cacheNames = "events", key = "#event.getAccount().getAccountId().toString()")
- private AccountEvent addEvent(AccountEvent event) {
- event = eventRepository.saveAndFlush(event);
- return event;
- }
-}
diff --git a/account/account-web/src/main/resources/application.yml b/account/account-web/src/main/resources/application.yml
index e66280b..3210601 100644
--- a/account/account-web/src/main/resources/application.yml
+++ b/account/account-web/src/main/resources/application.yml
@@ -10,8 +10,5 @@ spring:
output:
destination: account
contentType: 'application/json'
- redis:
- host: localhost
- port: 6379
server:
port: 8080
\ No newline at end of file
diff --git a/account/account-web/src/test/java/demo/account/AccountControllerTest.java b/account/account-web/src/test/java/demo/account/AccountControllerTest.java
index 0ae456d..ffe5c8f 100644
--- a/account/account-web/src/test/java/demo/account/AccountControllerTest.java
+++ b/account/account-web/src/test/java/demo/account/AccountControllerTest.java
@@ -1,6 +1,10 @@
package demo.account;
+import demo.account.controller.AccountController;
+import demo.event.AccountEvent;
+import demo.event.AccountEventType;
import demo.event.EventService;
+import demo.event.Events;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@@ -10,6 +14,8 @@ import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
+import java.util.Collections;
+
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
@@ -26,18 +32,22 @@ public class AccountControllerTest {
private AccountService accountService;
@MockBean
- private EventService eventService;
+ private EventService eventService;
@Test
public void getUserAccountResourceShouldReturnAccount() throws Exception {
String content = "{\"firstName\": \"Jane\", \"lastName\": \"Doe\", \"email\": \"jane.doe@example.com\"}";
Account account = new Account("Jane", "Doe", "jane.doe@example.com");
+ account.setIdentity(1L);
- given(this.accountService.getAccount(1L))
- .willReturn(account);
+ given(this.accountService.get(1L)).willReturn(account);
+ given(this.eventService.find(1L)).willReturn(new Events<>(1L, Collections
+ .singletonList(new AccountEvent(AccountEventType
+ .ACCOUNT_CREATED))));
this.mvc.perform(get("/v1/accounts/1").accept(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk()).andExpect(content().json(content));
+ .andExpect(status().isOk())
+ .andExpect(content().json(content));
}
}
diff --git a/account/account-web/src/test/java/demo/account/AccountServiceTests.java b/account/account-web/src/test/java/demo/account/AccountServiceTests.java
index 0e7e33d..c3511d0 100644
--- a/account/account-web/src/test/java/demo/account/AccountServiceTests.java
+++ b/account/account-web/src/test/java/demo/account/AccountServiceTests.java
@@ -3,42 +3,36 @@ package demo.account;
import demo.event.AccountEvent;
import demo.event.AccountEventType;
import demo.event.EventService;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.cache.CacheManager;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
@RunWith(SpringRunner.class)
+@SpringBootTest
public class AccountServiceTests {
@MockBean
- private EventService eventService;
+ private EventService eventService;
@MockBean
private AccountRepository accountRepository;
- @MockBean
- private CacheManager cacheManager;
-
+ @Autowired
private AccountService accountService;
- @Before
- public void before() {
- accountService = new AccountService(accountRepository, eventService, cacheManager);
- }
-
@Test
public void getAccountReturnsAccount() throws Exception {
Account expected = new Account("Jane", "Doe", "jane.doe@example.com");
given(this.accountRepository.findOne(1L)).willReturn(expected);
- Account actual = accountService.getAccount(1L);
+ Account actual = accountService.get(1L);
assertThat(actual).isNotNull();
assertThat(actual.getEmail()).isEqualTo("jane.doe@example.com");
@@ -49,12 +43,12 @@ public class AccountServiceTests {
@Test
public void createAccountReturnsAccount() throws Exception {
Account account = new Account("Jane", "Doe", "jane.doe@example.com");
- account.setAccountId(1L);
+ account.setIdentity(1L);
given(this.accountRepository.findOne(1L)).willReturn(account);
given(this.accountRepository.saveAndFlush(account)).willReturn(account);
- Account actual = accountService.createAccount(account);
+ Account actual = accountService.create(account);
assertThat(actual).isNotNull();
assertThat(actual.getStatus()).isEqualTo(AccountStatus.ACCOUNT_CREATED);
@@ -66,19 +60,20 @@ public class AccountServiceTests {
@Test
public void applyCommandSuspendsAccount() throws Exception {
Account account = new Account("Jane", "Doe", "jane.doe@example.com");
+ account.setIdentity(1L);
account.setStatus(AccountStatus.ACCOUNT_ACTIVE);
AccountEvent accountEvent = new AccountEvent(AccountEventType.ACCOUNT_SUSPENDED);
- accountEvent.setAccount(account);
+ accountEvent.setEntity(account);
accountEvent.setEventId(1L);
+ AccountEvent expected = new AccountEvent(AccountEventType.ACCOUNT_SUSPENDED, account);
given(this.accountRepository.findOne(1L)).willReturn(account);
given(this.accountRepository.exists(1L)).willReturn(true);
given(this.accountRepository.save(account)).willReturn(account);
- given(this.eventService.createEvent(1L, new AccountEvent(AccountEventType.ACCOUNT_SUSPENDED)))
- .willReturn(accountEvent);
+ given(this.eventService.send(expected)).willReturn(accountEvent);
- Account actual = accountService.applyCommand(1L, AccountCommand.SUSPEND_ACCOUNT);
+ Account actual = account.suspend();
assertThat(actual).isNotNull();
assertThat(actual.getStatus()).isEqualTo(AccountStatus.ACCOUNT_SUSPENDED);
@@ -87,19 +82,20 @@ public class AccountServiceTests {
@Test
public void applyCommandUnsuspendsAccount() throws Exception {
Account account = new Account("Jane", "Doe", "jane.doe@example.com");
+ account.setIdentity(1L);
account.setStatus(AccountStatus.ACCOUNT_SUSPENDED);
AccountEvent accountEvent = new AccountEvent(AccountEventType.ACCOUNT_ACTIVATED);
- accountEvent.setAccount(account);
+ accountEvent.setEntity(account);
accountEvent.setEventId(1L);
+ AccountEvent expected = new AccountEvent(AccountEventType.ACCOUNT_ACTIVATED, account);
given(this.accountRepository.findOne(1L)).willReturn(account);
given(this.accountRepository.exists(1L)).willReturn(true);
given(this.accountRepository.save(account)).willReturn(account);
- given(this.eventService.createEvent(1L, new AccountEvent(AccountEventType.ACCOUNT_ACTIVATED)))
- .willReturn(accountEvent);
+ given(this.eventService.send(expected)).willReturn(accountEvent);
- Account actual = accountService.applyCommand(1L, AccountCommand.ACTIVATE_ACCOUNT);
+ Account actual = account.activate();
assertThat(actual).isNotNull();
assertThat(actual.getStatus()).isEqualTo(AccountStatus.ACCOUNT_ACTIVE);
@@ -108,19 +104,20 @@ public class AccountServiceTests {
@Test
public void applyCommandArchivesAccount() throws Exception {
Account account = new Account("Jane", "Doe", "jane.doe@example.com");
+ account.setIdentity(1L);
account.setStatus(AccountStatus.ACCOUNT_ACTIVE);
AccountEvent accountEvent = new AccountEvent(AccountEventType.ACCOUNT_ARCHIVED);
- accountEvent.setAccount(account);
+ accountEvent.setEntity(account);
accountEvent.setEventId(1L);
+ AccountEvent expected = new AccountEvent(AccountEventType.ACCOUNT_ARCHIVED, account);
given(this.accountRepository.findOne(1L)).willReturn(account);
given(this.accountRepository.exists(1L)).willReturn(true);
given(this.accountRepository.save(account)).willReturn(account);
- given(this.eventService.createEvent(1L, new AccountEvent(AccountEventType.ACCOUNT_ARCHIVED)))
- .willReturn(accountEvent);
+ given(this.eventService.send(expected)).willReturn(accountEvent);
- Account actual = accountService.applyCommand(1L, AccountCommand.ARCHIVE_ACCOUNT);
+ Account actual = account.archive();
assertThat(actual).isNotNull();
assertThat(actual.getStatus()).isEqualTo(AccountStatus.ACCOUNT_ARCHIVED);
@@ -129,19 +126,20 @@ public class AccountServiceTests {
@Test
public void applyCommandUnarchivesAccount() throws Exception {
Account account = new Account("Jane", "Doe", "jane.doe@example.com");
+ account.setIdentity(1L);
account.setStatus(AccountStatus.ACCOUNT_ARCHIVED);
AccountEvent accountEvent = new AccountEvent(AccountEventType.ACCOUNT_ACTIVATED);
- accountEvent.setAccount(account);
+ accountEvent.setEntity(account);
accountEvent.setEventId(1L);
+ AccountEvent expected = new AccountEvent(AccountEventType.ACCOUNT_ACTIVATED, account);
given(this.accountRepository.findOne(1L)).willReturn(account);
given(this.accountRepository.exists(1L)).willReturn(true);
given(this.accountRepository.save(account)).willReturn(account);
- given(this.eventService.createEvent(1L, new AccountEvent(AccountEventType.ACCOUNT_ACTIVATED)))
- .willReturn(accountEvent);
+ given(this.eventService.send(expected)).willReturn(accountEvent);
- Account actual = accountService.applyCommand(1L, AccountCommand.ACTIVATE_ACCOUNT);
+ Account actual = account.activate();
assertThat(actual).isNotNull();
assertThat(actual.getStatus()).isEqualTo(AccountStatus.ACCOUNT_ACTIVE);
@@ -150,19 +148,20 @@ public class AccountServiceTests {
@Test
public void applyCommandConfirmsAccount() throws Exception {
Account account = new Account("Jane", "Doe", "jane.doe@example.com");
+ account.setIdentity(1L);
account.setStatus(AccountStatus.ACCOUNT_PENDING);
AccountEvent accountEvent = new AccountEvent(AccountEventType.ACCOUNT_CONFIRMED);
- accountEvent.setAccount(account);
+ accountEvent.setEntity(account);
accountEvent.setEventId(1L);
+ AccountEvent expected = new AccountEvent(AccountEventType.ACCOUNT_CONFIRMED, account);
given(this.accountRepository.findOne(1L)).willReturn(account);
given(this.accountRepository.exists(1L)).willReturn(true);
given(this.accountRepository.save(account)).willReturn(account);
- given(this.eventService.createEvent(1L, new AccountEvent(AccountEventType.ACCOUNT_CONFIRMED)))
- .willReturn(accountEvent);
+ given(this.eventService.send(expected)).willReturn(accountEvent);
- Account actual = accountService.applyCommand(1L, AccountCommand.CONFIRM_ACCOUNT);
+ Account actual = account.confirm();
assertThat(actual).isNotNull();
assertThat(actual.getStatus()).isEqualTo(AccountStatus.ACCOUNT_CONFIRMED);
@@ -171,20 +170,20 @@ public class AccountServiceTests {
@Test
public void applyCommandActivatesAccount() throws Exception {
Account account = new Account("Jane", "Doe", "jane.doe@example.com");
+ account.setIdentity(1L);
account.setStatus(AccountStatus.ACCOUNT_CONFIRMED);
-
AccountEvent accountEvent = new AccountEvent(AccountEventType.ACCOUNT_ACTIVATED);
- accountEvent.setAccount(account);
+ accountEvent.setEntity(account);
accountEvent.setEventId(1L);
+ AccountEvent expected = new AccountEvent(AccountEventType.ACCOUNT_ACTIVATED, account);
given(this.accountRepository.findOne(1L)).willReturn(account);
given(this.accountRepository.exists(1L)).willReturn(true);
given(this.accountRepository.save(account)).willReturn(account);
- given(this.eventService.createEvent(1L, new AccountEvent(AccountEventType.ACCOUNT_ACTIVATED)))
- .willReturn(accountEvent);
+ given(this.eventService.send(expected)).willReturn(accountEvent);
- Account actual = accountService.applyCommand(1L, AccountCommand.ACTIVATE_ACCOUNT);
+ Account actual = account.activate();
assertThat(actual).isNotNull();
assertThat(actual.getStatus()).isEqualTo(AccountStatus.ACCOUNT_ACTIVE);
diff --git a/order/order-web/src/main/java/demo/order/action/ConnectAccount.java b/order/order-web/src/main/java/demo/order/action/ConnectAccount.java
index a504e6e..a51e9f7 100644
--- a/order/order-web/src/main/java/demo/order/action/ConnectAccount.java
+++ b/order/order-web/src/main/java/demo/order/action/ConnectAccount.java
@@ -11,6 +11,11 @@ import org.springframework.stereotype.Service;
import java.util.function.BiConsumer;
+/**
+ * Connects an {@link Order} to an Account.
+ *
+ * @author Kenny Bastani
+ */
@Service
public class ConnectAccount extends Action {
@@ -25,7 +30,7 @@ public class ConnectAccount extends Action {
order = orderService.update(order);
// Trigger the account connected event
- order.sendAsyncEvent(new OrderEvent(OrderEventType.ACCOUNT_CONNECTED));
+ order.sendAsyncEvent(new OrderEvent(OrderEventType.ACCOUNT_CONNECTED, order));
};
}
}
diff --git a/order/order-web/src/main/java/demo/order/action/ConnectPayment.java b/order/order-web/src/main/java/demo/order/action/ConnectPayment.java
index ef830d5..37594da 100644
--- a/order/order-web/src/main/java/demo/order/action/ConnectPayment.java
+++ b/order/order-web/src/main/java/demo/order/action/ConnectPayment.java
@@ -11,6 +11,11 @@ import org.springframework.stereotype.Service;
import java.util.function.BiConsumer;
+/**
+ * Connects a {@link demo.payment.Payment} to an {@link Order}.
+ *
+ * @author Kenny Bastani
+ */
@Service
public class ConnectPayment extends Action {
public BiConsumer getConsumer() {
@@ -25,7 +30,7 @@ public class ConnectPayment extends Action {
order = orderService.update(order);
// Trigger the account connected event
- order.sendAsyncEvent(new OrderEvent(OrderEventType.PAYMENT_CONNECTED));
+ order.sendAsyncEvent(new OrderEvent(OrderEventType.PAYMENT_CONNECTED, order));
};
}
}
diff --git a/order/order-web/src/main/java/demo/order/action/CreatePayment.java b/order/order-web/src/main/java/demo/order/action/CreatePayment.java
index ddcd71f..704951b 100644
--- a/order/order-web/src/main/java/demo/order/action/CreatePayment.java
+++ b/order/order-web/src/main/java/demo/order/action/CreatePayment.java
@@ -20,6 +20,11 @@ import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.util.function.Consumer;
+/**
+ * Creates a {@link Payment} for an {@link Order}.
+ *
+ * @author Kenny Bastani
+ */
@Service
public class CreatePayment extends Action {
diff --git a/order/order-web/src/main/java/demo/order/action/ProcessPayment.java b/order/order-web/src/main/java/demo/order/action/ProcessPayment.java
index faa837e..f53dc2c 100644
--- a/order/order-web/src/main/java/demo/order/action/ProcessPayment.java
+++ b/order/order-web/src/main/java/demo/order/action/ProcessPayment.java
@@ -6,6 +6,11 @@ import org.springframework.stereotype.Service;
import java.util.function.Consumer;
+/**
+ * Processes a {@link demo.payment.Payment} for an {@link Order}.
+ *
+ * @author Kenny Bastani
+ */
@Service
public class ProcessPayment extends Action {
public Consumer getConsumer() {
diff --git a/order/order-web/src/main/java/demo/order/action/ReserveInventory.java b/order/order-web/src/main/java/demo/order/action/ReserveInventory.java
index 5a7d434..e886ef9 100644
--- a/order/order-web/src/main/java/demo/order/action/ReserveInventory.java
+++ b/order/order-web/src/main/java/demo/order/action/ReserveInventory.java
@@ -6,6 +6,11 @@ import org.springframework.stereotype.Service;
import java.util.function.Consumer;
+/**
+ * Reserves inventory for an {@link Order}.
+ *
+ * @author Kenny Bastani
+ */
@Service
public class ReserveInventory extends Action {
public Consumer getConsumer() {