Java API to work transparently with Ontologies/Entities
This feature is available since version 2.0.2-RELEASE of the client Library, and 2.0.0-fireball of onesait Platform
Introduction
As we already know, onesait Platform’s architecture is Data Centric, in which ontologies (abstraction of database entities) are the core of the platform, this is the reason why all platform’s modules need them to work properly. Read: https://onesaitplatform.atlassian.net/wiki/spaces/PT/pages/333316099
The platform offers an abstraction to work transparently with ontologies through a Spring Repository:(Client APIS) What is the Spring client librery, aka Client4SpringBoot, and how to use it?
However, there are situations in which due to technical requirements or other decisions, it is preferred to work directly with the database entities using frameworks such as Spring Data, iBatis ..., and CRUD operations are performed with these frameworks, instead of being the platform that performs them.
In many of these cases, in turn, it is interesting to use the modules of the platform, so how can we use the platform, so that it can transparently handle the concept of Ontology?
The Onesait Platform Java client library now provides a client -NotifierClient- that allows us to create the ontologies from Java classes and notify the platform of the CRUD operations that we perform with our framework, so that although the platform does not perform these operations, it will be aware of them, and as the ontology definition exists, all modules can be used seamlessly.
Notifier Client
Provided Operations
The client provides the following operations:
Create/Update ontology from a Java class: a JSON Schema will be generated from a Java class to create the ontology in the platform.
JSON validation of the Java entity: this operations should be executed just before creating/updating a instance: the entity will be serialized in JSON, and the platform will validate it against the JSON Schema of the ontology referenced.
CRUD notifications: this operation should be executed just after the Java CRUD operations/process. When using CRUD operations in the Java application, we shall notify the platform. This operation is available in a synchronous format as well as asynchronous.
Client instatiation
We can create a client in two different ways:
With a platform API key (X-OP-APIKey)
With username and password: Oauth 2 will be used for authentication
Example:
The last argument of the constructor allows you to avoid SSL verification, in cases where certificates are self-signed.
Creating ontology from Java Class
Suppose we have a Spring Data entity over MongoDB -Message.java-
Note the @Attributes annotation, it is used to mark the attribute as required in the JSON Schema inference, as we used the JJSchema for this process.
A suitable moment for creating the ontology could be the application startup. In such case, we will be sure that the ontology exists and its updated to its latest version.
This code will generate the following Ontology.
JSON Schema Validation
Whenever you want to store or update ontology data, you can use this method to check if data is valid. We can call it with the Java object itself, or with the name of the Ontology and the serialized object (JSON String).
If the validation happen to fail, an exception of the type NotifierException will be thrown giving you the error description.
ERROR com.minsait.onesait.platform.client.NotifierClient - Validation failed with following errors Error processing data:{"message":"hello"}by:{"level":"error","schema":{"loadingURI":"#","pointer":""},"instance":{"pointer":""},"domain":"validation","keyword":"required","message":"object has missing required properties ([\"idMessage\",\"toMessage\"])","required":["idMessage","toMessage"],"missing":["idMessage","toMessage"]}
On the other hand, if validation passes, then code flow will continue.
Notifications to the onesait Platform
You can choose the sync/async version to fit your needs.
You need to pass the Notification Java object that will have the following attributes :
QueryType: only for QUERY operations. Enum {SQL, NATIVE}
Query: only for QUERY operations, and it will carry the query.
Payload: for INSERT/UPDATE, it will contain the JSON serialized object.
Operation: Enum {INSERT,UPDATE,DELETE,QUERY}
Id: instance id for cases such as DELETE/UPDATE by ID
Here’s an example
Practice Example
You can make use of these operations inside your business logic, for example, when a new message is stored in the database, you can validate its content previously, and then notify the platform:
In this case, if you have a flow in the Flow Engine that works with ontology Message, it will be notified as if the platform was making the CRUD operations.
Here’s the link to the full example: GitHub - onesaitplatform/onesaitplatform-spring-boot-example: Spring Boot 2 example application using the onesait Platform
Spring Boot Wrapper for the library
For applications developed with Spring Boot, a wrapper is provided to easy the use of this library.
Properties
In addition to the dependency inyection:
<dependency>
<groupId>com.minsait.onesait.platform</groupId>
<artifactId>onesaitplatform-iotclient4springboot</artifactId>
<version>2.1.0-RELEASE</version>
</dependency>
The following properties will be needed:
onesaitplatform:
notifierclient:
enabled: true
server: https://development.onesaitplatform.com
username: developer
password: P4SSw0rd!
#apikey: alternativa a username + password
We can configure the client to use username + password credentials, or an API key.
@OPEntity annotation
This annotation will be used in our Entity Model classes. For example, if you use Spring Data:
@Document(collection = "Message")
@OPEntity
public class Message {
public enum MessageType {
MAIL, SMS
}
@Id
@Attributes(required = true)
private String idMessage;
private String txtMessage;
private MessageType typeMessage;
@Attributes(required = true)
private String fromMessage;
}
The use of this annotation will cause the creation/update of the ontology from its referenced Java Class at the application startup.
For the Java attributes to be marked as required in the JSON Schema, you’ll need to use the following annotation:
@Attributes(required = true)
@OPValidateSchema annotation
This annotation will attempt to validate the serialized Java object with its ontology schema synchronously, so if it fails, an exception will be thrown. It is used at attribute/argument level.
@Override
Message save(@OPValidateSchema Message entity);
@OPNotifierOperation annotation
This annotation allows you to notify the platform with CRUD operations performed at the Spring Boot application, either synchronously or asynchronously. It is used at method level, and has the following attributes:
async: boolean default false. Wether the notification is performed sync/async.
ontology: Ontology name. f.e. Message
operationType: QUERY, INSERT, UPDATE, DELETE. Operation type
queryType: SQL, NATIVE, default NATIVE. As query operations will be made with Spring Data interface or similar frameworks, this attribute can be left empty.
id: SpEL expression that references the id of the Java object. This id is the unique identifier of the object . f.e. “#p0” default is #p0
payload: SpEL expression that references the object that will be send as the payload in the notification. f.e. “#p1”. default is #p0
Use examples:
INSERT
@OPNotifierOperation(ontology = "Message", operationType = OperationType.INSERT, async = true)
public void createMessage(@OPValidateSchema Message message) {
....
}
QUERY
@OPNotifierOperation(ontology = "Message", async = true)
List<Message> findByToMessage(String toMessage);
@OPNotifierOperation(ontology = "Message", async = false)
Message findByIdMessage(String idMessage);
UPDATE
@Override
@OPNotifierOperation(ontology = "Message", id = "#p0.idMessage", payload = "#p0", operationType = OperationType.UPDATE, async = true)
public void updateMessage(@OPValidateSchema Message message) {
messageRepository.save(message);
}
DELETE
@OPNotifierOperation(async = false, ontology = "Message", operationType = OperationType.DELETE, id = "#p0")
public void deleteMessage(String idMessage) {
messageRepository.deleteById(idMessage);
}
There’s a full example on how to use this wrapper in: