Low-code Java SDK

Introduction

The service project SDK provides numerous components for the implementation of a low-code project based on the project's design model. That means, whatever you modelled in the design phase will be reflected by pre-generated code.

SDK consists of some main packages under src/main/generated source folder:

  • api: which holds all API namespace's schema models, controllers and delegate classes

  • domain: which holds classes for all entities, services, commands, events and agents that have been modelled in domain namespaces

  • integration: which contains classes and providers that allows for easy integration with dependent API(s) that have been added in integration namespaces

Solution engineers can use these generated classes to implement logic and interact with different modelled components.

Below are the main SDK components that can be used by solution engineers to help to implement project generated implementation files logic.

Attention: Some components are grouped under the namespace that they are modelled.

For example:

// Import Owner entity that was modelled in a namespace with the prefix: cc
import de.knowis.cards.sdk.domain.cc.entity.Owner;

EntityBuilder

  • EntityBuilder is used to provide an easy way to create new instances of entities using the builder pattern

  • EntityBuilder groups all EntityBuilders by their namespace prefix

  • There are two types of EntityBuilders:

    1. Domain EntityBuilder, this can be used to create instances of domain entities

    2. Integration EntityBuilder, this can be used to create instances of integration entities

  1. Example importing DomainEntityBuilder & IntegrationEntityBuilder

import de.knowis.cards.sdk.domain.facade.DomainEntityBuilder;
import de.knowis.cards.sdk.integration.facade.IntegrationEntityBuilder;
  1. Example for declaring and injecting DomainEntityBuilder & IntegrationEntityBuilder


    // Inject DomainEntityBuilder from SDK
    @Autowired
    private DomainEntityBuilder domainEntityBuilder;

    // Inject IntegrationEntityBuilder from SDK
    @Autowired
    private IntegrationEntityBuilder integrationEntityBuilder;

Create entities

Entity builders can be used to create an entity (root entity/entity).

  1. Example for injecting and using entity builder.

   import de.knowis.cards.sdk.domain.facade.DomainEntityBuilder; 

   // Declare and inject Domain Entity Builder
   @Autowired
   private DomainEntityBuilder entityBuilder;
     
   // Create a customer entity that exists in a domain namespace prefixed by cc.
   Customer customer = entityBuilder.cc.customer()
           .setCustomerId("Customer Id")
           .setCustomerName("Joh Doe")
           .setAmixCard(new AmixCard("some id", CardType.debit))
           .build();
Tip: EntityBuilder is also accessible in project generated implementation files (services, commands, agents) derived from their base classes.
  1. Example for using entity builder provided by base class to create entities.

    // Use the DomainEntityBuilder to create an entity that was modelled in a domain namespace with prefix: cc
    Owner owner = this.domainEntityBuilder.getCc().getOwner().build();

    // Use IntegrationnEntityBuilder to create an entity that was modelled in an integration namespace with prefix: cards
    AmexCard amexCard = this.integrationEntityBuilder.getCards().getAmexCard().build();

EventBuilder

  • EventBuilder is used to provide an easy way to create new instances of events using the builder pattern

  1. Example importing DomainEventBuilder

import de.knowis.cards.sdk.domain.facade.DomainEventBuilder;
  1. Example for declaring and injecting DomainEventBuilder


// Inject DomainEventBuilder from SDK
@Autowired
private DomainEventBuilder eventBuilder;
  1. Example for using event builder provided by base class to create events.


// Use the DomainEventBuilder to create an event that was modelled in a domain namespace with prefix: cc
CardCreatedEvent event = this.eventBuilder.getCc().getCardCreatedEvent().build();
event.setPayload(payloadEntity);

Service Facade

Service facade is a class that can be injected into your implementation file and provides access to all your project services grouped by their namespace.

In the below example both (CcService & OpsService) are namespace facades that groups all the services in their namespace where cc & ops are the namespace acronyms.

The class exists in de.knowis.operations.cards.sdk.domain.facade where:

  1. de.knowis.operations is your service project base package name.

  2. cards is your service project acronym.

    package de.knowis.opeations.cards.sdk.domain.facade;

    import org.springframework.stereotype.Component;

    // Importing cc namesapce service facade that provides access to all of its services.
    import de.knowis.opeations.cards.sdk.domain.cc.facade.CcService;

    // Importing ops namesapce service facade that provides access to all of its services.
    import de.knowis.opeations.cards.sdk.domain.ops.facade.OpsService;

    /**
    * Provide access to all Service facades.
    *
    * @Generated
    *
    */
    @Component
    public class Service {

      protected CcService cc;
      protected OpsService ops;


      public Service(CcService cc,OpsService lib) {
      this.cc = cc;
      this.ops = lib;
      }


      public CcService getCc() {
        return cc;
      }

      public OpsService getOps() {
        return ops;
      }
    }

Command facade

Command facade is a class that can be injected into your implementation file and provides access to all your project root entity commands grouped by their namespace.

In the below example both (CcService & OpsService) are namespace facades that groups all the commands in their namespace where cc & ops are the namespace acronyms.

The class exists in de.knowis.operations.cards.sdk.domain.facade where:

  1. de.knowis.operations is your service project base package name.

  2. cards is your service project acronym.

    package de.knowis.opeations.cards.sdk.domain.facade;

    import org.springframework.stereotype.Component;

    // Importing cc namesapce service facade that provides access to all of its commands.
    import de.knowis.opeations.cards.sdk.domain.cc.facade.CcCommand;

    // Importing ops namesapce service facade that provides access to all of its commands.
    import de.knowis.opeations.cards.sdk.domain.ops.facade.OpsCommand;

    /**
    * Provide access to all command facades.
    *
    * @Generated
    *
    */
    @Component
    public class Command {

      protected CcCommand cc;
      protected OpsCommand ops;


      public Service(CcCommand cc,OpsCommand lib) {
      this.cc = cc;
      this.ops = lib;
      }


      public CcCommand getCc() {
        return cc;
      }

      public OpsCommand getOps() {
        return ops;
      }
    }

Namespace Facade

Also, you can only inject one namespace service / command facade and get access to all its services / commands.

In the below example both CcService is a namespace facade that groups all the services in namespace with acronym cc.

The class exists in de.knowis.opeations.cards.sdk.domain.cc.facade where:

  1. de.knowis.opeations is your service project base package name.

  2. cards is your service project acronym.

    package de.knowis.operations.cards.sdk.domain.cc.facade;

    import org.springframework.stereotype.Component;
    /**
    * Provide access to all cc namespace services.
    *
    * @Generated
    *
    */
    @Component
    public class CCService {

      protected CheckBalanceServiceBase checkBalance;
      protected CustomereServiceBase checkCustomer;

      public CCService(CheckBalanceServiceBase checkBalance,CustomereServiceBase customerService) {
      this.checkBalance = checkBalance;
      this.customerService = customerService;
      }


      public CheckBalanceServiceBase getCheckBalance()) {
        return checkBalance;
      }

      public CustomereServiceBase getCustomere() {
        return customerService;
      }
    }

Repository

  • For each root entity there will be an associated repository class generated in the SDK.

  • The Repository Class through its inheritance chain extends SimpleMongoRepository <T, ID>

  • The SimpleMongoRepository provide access to several functionalities such as findBy, findAll, count, save, delete....etc.

  • You can directly inject root entity repository or use it using repo which is a repository facade that is available in commands, domain services, external entities and agents base classes.

Example of repository usage for different database operations.

    // Build a credit card root entity that exists in a domain namespace prefixed by cc.
    CreditCard creditCard = this.entityBuilder.cc.creditCard()
        .setBankName("MyBank")
        .setCardType(CardType.debit)
        .setCustomer(customer)
        .setIssueDate(OffsetDateTime.now())
        .build();

    // Save a credit card root entity.
    creditCard = this.repo.cc.creditCard.save(creditCard);

    // Retrieve all credit card root entities
    List<CreditCard> cards = this.repo.cc.creditCard.findAll();

    // Update credit card root entity
    creditCard.setCardType(CardType.credit);
    repo.cc.creditCard.save(creditCard);

    // Delete credit card root entity
    repo.cc.creditCard.delete(creditCard);

    //Count all credit card root entities
    long count = this.repo.cc.creditCard.count();

Example of using inside a command implementation using declared repository from command base class.

    //... imports

    @Service
    public class CardCommand extends CardCommandBase {

      private static Logger log = LoggerFactory.getLogger(CardCommand.class);
      
      public CardCommand(DomainEntityBuilder entityBuilder, DomainEventBuilder eventBuilder, EventProducerService eventProducer, Repository repo) {
        super(entityBuilder, eventBuilder, eventProducer, repo);
      }


      @Override
      public Card createCreditCard(CreditCard creditCard) throws CreditCardCreationError {

        log.info("CardCommands.createCreditCard()");
            // ..... command logic

            // Using this.repo to find and save an updated Card root entity
            try {

                Optional<Card> cardRootEntity = this.repo.getCc().getCard().findById(creditCard.getId());
            
              // Update card if it exists
              if(cardRootEntity.isPresent()){

                cardRootEntity.setActive(true);

                log.info("Updated Credit Card Root Entity with Id {}", cardRootEntity.getId());
                
                // Save updated card
                this.repo.getCc().getCard().save(cardRootEntity);
                } else {
                  throw CardNotFoundException("Could not find card with Id {}", creditCard.getid());
                }

        } catch(Exception e) {
          // ... Exception handling logic
        }

        return cardRootEntity;
      }

Example of injecting and using CardRepository in a mapper utility.

    //... imports

    // Importing *CardRepository*
    import de.knowis.cards.sdk.domain.card.repository.CardRepository;

    @Service
    public class Mapper {

      private static Logger log = LoggerFactory.getLogger(Mapper.class);

        // Injecting *CardRepository*
        @Autowired
        private CardRepository cardRepo;

      @Override
      public Optional<Card> mapToRootEntity(String cardId){
            
            Optional<Card> card= cardRepo.findById(cardId);

        return card;
      }

API dependency provider

For each API dependency added in integration namespaces, there will be a provider that allows for making REST calls to that dependent API endpoints.

    // Declare and inject a Provider class for an API Dependency called Cnr inside a namespace prefix intns.
    @Autowired
    private CnrApiIntns cnr;  

    // retrieve an offer from CNR API.
    ResponseEntity<Offer> offer = cnr.adjustOffer(customerNeedId,offerId);

Event producer service

Publish domain events to Kafka topics.

Each event is assigned to a Kafka topic and the event producer service can be used by solution engineers to publish events.

    // Declare Event Prodcuer Service
    @Autowired
    private EventProducerService eventProdcuer;

    // Declare entity builder
    @Autowired
    private EntityBuilder entityBuilder;  

    // Create payload entity
    SuccessEventPayload payloadEntity = entityBuilder.cc.successEventPayload().build();

    // Create domain event
    SuccessEvent event = eventBuilder.cc.successEvent().setPayload(payloadEntity).build();

    // Publish a domain event.
    eventProducer.publish(event);
Tip: Dedicated event publish function(s) are available within project stubs (services, commands, agents) that are configured to publish events.

Logging

Logging can be using slf4j logger factory to create a logger instance.

slf4j provides the info,warn,debug,trace log levels.

    // Add imports for slf4j
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    // Create logger instance
    private static Logger log = LoggerFactory.getLogger(CardRECommand.class);

    // logging examples
    log.info("Saved a new Credit Card Root Entity with Id {}", cardRootEntity.getId());