Implement Domain Services
Every service comes with an automatically generated implementation file, which allows to implement business logic. Domain services can have input and output defined, which needs to be considered during implementation. Typically, a domain service implements logic which loads data from the database, publish events or throws errors.
Service Base
For each service there will be an abstract class Service Base generated in the SDK.
The Service Base provides access to the repository, the entity builder, the event builder and the event producer.
The Service Base contains one abstract method named execute.
This execute method needs to be implemented in the generated implementation file for the service.
Input & output entity
Service execute method will take a modelled Input Entity as a parameter.
Service execute method will return a modelled Output Entity as a return type.
Business errors
- If a service is modelled with Business Errors, it will be added as
throws
declaration to service execute method.
Events
If a service is modelled with Events, for each event there will be four inherited methods in the Service Base class to publish the event with the following signatures.
- Event only
- Event and messageKey
- Event and messageHeaders
- Event, messageKey and messageHeaders
It is also possible to publish events with any publish method mentioned above using EventProducerService directly.
Implementation example
Example of Balance service implementation file.
//... imports import myproj.sdk.domain.schemas.SchemaGroup.BalanceCheckedSchema; @Service public class BalanceService extends BalanceServiceBase { private static Logger log = LoggerFactory.getLogger(BalanceService.class); public BalanceService(DomainEntityBuilder entityBuilder, DomainEventBuilder eventBuilder, EventProducerService eventProducer, Repository repo) { super(entityBuilder, eventBuilder, eventProducer, repo); } // Example of a service implementation logic @NewSpan @Override public Balance execute(CreditCard creditCard) throws CreditCardNotFoundError { log.info("BalanceService.execute()"); // Use repository to get card instance Optional<Card> cardRootEntity = this.repo.getCc().getCard().findById(creditCard.getId()); if(cardRootEntity.isPresent()) { // Use Domain Entity Builder from base class to create an instance of Balance entity Balance balance = this.entityBuilder.getCc().getBalance().build(); balance.setAvaliableBalance(cardRootEntity.getBalance()); balance.setHoldAmount(cardRootEntity.getHoldAmount()); // Publish event, if the event is using a schema from the schema registry as payload BalanceCheckedEvent schemaEvent = this.eventBuilder.getCc().getBalanceCheckedEvent().build(); // Create the payload BalanceCheckedSchema schema = new BalanceCheckedSchema(); schema.setProperty1("value"); schemaEvent.setPayload(schema); // Publish the event this.publishBalanceCheckedEvent(schemaEvent); /** * Create an event and set payload entity, if the event is using an entity as payload * only available for event support 1.0 * @deprecated use schemas from the schema registry instead */ BalanceUpdatedEvent entityEvent = this.eventBuilder.getCc().getBalanceUpdatedEvent().build(); // Using an entity as event payload entityEvent.setPayload(balance); // Publish the event this.publishBalanceUpdatedEvent(entityEvent); return balance; } else { String errorMessage = String.format("Credit card with id %s not found", creditCard.getId()); throw new CreditCardNotFoundError(errorMessage); } }
The @NewSpan
annotation creates a new span which will be a child of the existing span via the underneath springframework.cloud.sleuth that helps with microservice tracing.
Example for the alternative ways to publish event from a service.
//... imports import myproj.sdk.domain.schemas.SchemaGroup.BalanceCheckedSchema; @Service public class BalanceService extends BalanceServiceBase { private static Logger log = LoggerFactory.getLogger(BalanceService.class); @NewSpan @Override public Balance execute(CreditCard creditCard) throws CreditCardNotFoundError { log.info("BalanceService.execute()"); // Create event BalanceCheckedEvent schemaEvent = this.eventBuilder.getCc().getBalanceCheckedEvent().build(); // Create the payload BalanceCheckedSchema schema = new BalanceCheckedSchema(); schema.setProperty1("value"); schemaEvent.setPayload(schema); // Publish the event this.publishBalanceCheckedEvent(schemaEvent); // publish the event with custom messageKey this.publishBalanceCheckedEvent(schemaEvent, "customMessageKey"); // publish the event with messageHeaders HashMap<String, Object> map = new HashMap(); map.put("headerKey", "headerValue"); MessageHeaders headers = new MessageHeaders(map); this.publishBalanceCheckedEvent(schemaEvent, headers); // publish the event with messageKey and messageHeaders this.publishBalanceCheckedEvent(schemaEvent, "customMessageKey", headers); /** * Event 1.0 with entity payload * @deprecated use schemas from the schema registry instead */ BalanceUpdatedEvent entityEvent = this.eventBuilder.getCc().getBalanceUpdatedEvent().build(); // Using an entity as event payload entityEvent.setPayload(balance); // Publish the event this.publishBalanceUpdatedEvent(entityEvent); // Publish the event with messageHeaders HashMap<String, Object> map = new HashMap(); map.put("headerKey", "headerValue"); MessageHeaders headers = new MessageHeaders(map); this.publishBalanceUpdatedEvent(entityEvent, headers); return balance; }
Message key will be ignored in case of publishing event 1.0 (Entity payload).