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.
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:
Domain EntityBuilder, this can be used to create instances of domain entities
Integration EntityBuilder, 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();
EventBuilder
EventBuilder is used to provide an easy way to create new instances of events using the 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 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:
de.knowis.operations
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 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:
de.knowis.operations
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 acronym 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.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 extendsSimpleMongoRepository <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);
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());