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);
	}
}
Tip:

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;
}
Warning:

Message key will be ignored in case of publishing event 1.0 (Entity payload).