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 implemenation files logic.
For example:
// Import Owner entity that was modelled in a namespace with the prefix: cc
import de.knowis.cards.sdk.domain.cc.entity.Owner;
Entity Builder
Entity Builder is used to provide an easy way to create new instances of Entities using builder pattern.
Entity Builder Groups all EntityBuilders by their namespace prefix.
There are two type of Entity Builders:
Domian Entitiy Builder, This can be used to create instances of Domain Entities.
Integration Entity Builder, This can be used to create instances of Integration Entities.
Example importing DomainEntityBuilder & IntegrationEntityBuilder
import de.knowis.cards.sdk.domain.facade.DomainEntityBuilder;
import de.knowis.cards.sdk.integration.facade.IntegrationEntityBuilder;
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).
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();
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();
Event Builder
Event Builder is used to provide an easy way to create new instances of Events using builder pattern.
Example importing DomainEventBuilder
import de.knowis.cards.sdk.domain.facade.DomainEventBuilder;
Example for declaring and injecting DomainEventBuilder
// Inject DomainEventBuilder from sdk
@Autowired
private DomainEventBuilder eventBuilder;
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 groupped 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.opeations.cards.sdk.domain.facade where:
de.knowis.opeations is your service project base package name.
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 groupped 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.opeations.cards.sdk.domain.facade where:
de.knowis.opeations is your service project base package name.
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 acornym cc.
The class exists in de.knowis.opeations.cards.sdk.domain.cc.facade where:
de.knowis.opeations is your service project base package name.
cards is your service project acronym.
package de.knowis.opeations.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 a repository class associated generated in the SDK.
The Repository Class throught its inheritace 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 avaliable in commands, domain services, external entities and agents base classes.
Example of repository usage for different databse 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 delcared 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 utlity.
//... 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);
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());