JPA and Entities OP: How to use the Java API to work transparently with JPA and Entities?

Esta funcionalidad está disponible a partir de la versión 2.0.2-RELEASE de la librería cliente, y 2.0.0-fireball de la onesait Platform.

A partir de la versión 10.0.0 , la librería es compatible con Spring Boot 3.0 +.

La versión de plataforma debería ser 5.1.0-survivor como mínimo.

Demo

Introducción

Como sabemos, Onesait Platform posee una arquitectura Data Centric, en la que las Ontologías (abstracción de la entidad de base de datos) son el núcleo de la Plataforma, es por esto que todos los módulos de la plataforma necesitan de su existencia para operar correctamente. Leer: https://onesaitplatform.atlassian.net/wiki/spaces/PT/pages/56066346

La plataforma ofrece una abstracción de las ontologías para trabajar con ellas a través de un Repository Spring: https://onesaitplatform.atlassian.net/wiki/spaces/DOC/pages/2215909434

No obstante, hay situaciones en las que por requisitos técnicos u otras decisiones, se prefiere trabajar directamente con las entidades de base de datos utilizando frameworks como Spring Data, iBatis…, y se realizan las operaciones CRUD con estos frameworks, en vez de ser la plataforma la que las realiza.

En muchos de estos casos a su vez, interesa utilizar los módulos de la plataforma, entonces ¿Cómo podemos utilizar la plataforma, de modo que pueda manejar de forma transparente el concepto de Ontología?

La librería cliente de Java de la Onesait Platform ahora provee un cliente -NotifierClient- de bajo nivel y con un wrapper para Spring Boot, que nos permite crear las ontologías desde clases Java e informar a la plataforma de las operaciones CRUD que realizamos con nuestro framework, de tal forma que aunque la plataforma no realice estas operaciones, estará al tanto de ellas, y al existir la definición de la ontología, se podrán usar todos los módulos sin ningún inconveniente.

 

Creación de la Entidad

Operaciones provistas

Este cliente provee las siguientes operaciones:

  • Creación/actualización de una ontología en base a una clase Java: a partir de una clase Java, se generará un JSON Schema para posteriormente crear la ontología.

  • Validación de un JSON de una entidad esta operació debería ejecutarse antes de su inserción o actualización: plataforma comprobará que el JSON es válido comparándolo con el JSON Schema de la ontología referenciada.

  • Notificación de operaciones CRUD: esta operación se debe ejecutar tras completarse el proceso en mi aplicación Java, cuando realicemos operaciones de CRUD, podremos usar el cliente para notificar a plataforma. Esta operación está tanto en formato síncrono como asíncrono.

Creación del cliente

Podemos crear el cliente de dos formas:

  1. Con un token de API de plataforma (X-OP-APIKey)

  2. Con usuario y contraseña: se utilizará OAuth2 para la autenticación

Ejemplo:

El último parámetro del constructor sirve para saltarse la validación SSL para el caso de entornos que tengan certificados auto-firmados.

Creación de la Entidad partir de la clase Java

A continuación se muestra un ejemplo de entidad JPA

 

Para la generación/actualización de la entidad en plataforma, se hará uso de todas las anotaciones de la librería Jackson Fasterxml. Por ejemplo, @JsonProperty(required = true) para propiedades requeridas, @JsonIgnore @JsonManagedReference para evitar bucles infinitos de serialización, etc.

Un buen momento para crear la Entidad en plataforma de nuestra entidad JPA puede ser al inicio de la aplicación. De esta forma siempre nos aseguraremos de que nuestra entidad existe y está actualizada a su última versión del JSON Schema.

Como vemos, esto nos creará la Ontología con el siguiente JSON Schema:

 

Validación del JSON Schema

Cuando queramos guardar datos o actualizarlos, podremos usar este método para comprobar que la instancia JSON es correcta. Deberemos pasarle o bien el nombre de la ontología y el JSON en formato String, o bien el objeto que será serializado a JSON internamente:

Si la validación fallase, se lanzaría una excepción del tipo NotifierException con los errores de validación, por ejemplo:

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"]}

En caso contrario, el código seguirá su flujo.

Notificación a Onesait Platform

Podemos utilizar la versión síncrona o la asíncrona, en función de nuestras necesidades.

Deberemos pasarle un objeto Notification, en el que le indicaremos:

  • QueryType: Solo si es operación QUERY. Enum {SQL, NATIVE}

  • Query: Solo si es operación QUERY. La query en sí.

  • Payload: Para INSERT/UPDATE, contendrá la instancia de la ontología serializada, el equivalente a un toString()

  • Operation: Enum {INSERT,UPDATE,DELETE,QUERY}

  • Id: id de la instancia, para casos como el DELETE/UPDATE por ID

Veamos un ejemplo:

Ejemplo de uso

Podemos hacer uso de estas operaciones descritas en nuestra lógica de negocio, por ejemplo, cuando se cree un mensaje nuevo en base de datos, podemos previamente validar su contenido, y posteriormente notificar a la plataforma:

De esta forma, si por ejemplo tenemos un flujo creado en el FlowEngine que trabaja con la entidad/ontología Message, recibiremos las notificaciones como si fuese la plataforma quien estuviese haciendo las operaciones:

 

Tenemos un ejemplo de uso de esta librería con tests en: https://github.com/onesaitplatform/platform-entities-jpa

Hay que cambiar las credenciales asociadas al cliente y al usuario (API Key) para que funcione en el application.yml:

onesaitplatform: iotclient: token: 3b8a25fe233b4a45a19d1308bbb9073a deviceTemplate: client device: client urlRestIoTBroker: https://development.onesaitplatform.com notifierclient: enabled: true server: https://development.onesaitplatform.com username: fjgcornejo password: apikey: 5e29a14ab02c4cc08a404e71358d9bd5

Wrapper para Spring Boot

Para el desarrollo de aplicaciones con Spring Boot, se provee un wrapper con el objetivo de facilitar el uso de esta librería.

Properties

Además de inyectar la dependencia correspondiente:

<dependency> <groupId>com.minsait.onesait.platform</groupId> <artifactId>onesaitplatform-iotclient4springboot</artifactId> <version>2.1.0-RELEASE</version> <!-- For Spring Boot 3.X+ <version>10.0.0</version> --> </dependency>

 

Se deberán indicar las siguientes propiedades:

Podemos configurar el cliente para que use credenciales de usuario y contraseña, o que utilice una API Key de plataforma.

Anotación @OPEntity

Esta anotación se utilizará en las clases del modelo de nuestra aplicación, por ejemplo si utilizamos Spring Data:

El uso de esta anotación provocará una creación/actualización de una ontología a partir de la propia clase Java en el arranque de la aplicación.

Para que los atributos queden como requeridos en el JSON Schema creado a partir de la clase, se deberá hacer uso de la anotación de Jackson:

Anotación @OPValidateSchema

Esta anotación lanzará una validación contra el schema de la ontología de manera síncrona, por lo que si falla, se lanzará una excepción y alterará el flujo del código. Se utiliza a nivel de atributo/argumento.

 

Anotación @OPNotifierOperation

Esta anotación permite notificar a la plataforma de operaciones que ocurren en nuestra aplicación, tanto de manera síncrona como de manera asíncrona. Se utiliza a nivel de método, y tiene los siguientes argumentos:

  • async: boolean default false. Indica si la notificación se manda de manera síncrona o asíncrona.

  • ontology: nombre de la ontología. P.e. Message

  • operationType: QUERY, INSERT, UPDATE, DELETE. Tipo de operación que se realiza

  • queryType: SQL, NATIVE, default NATIVE. Cómo en la mayoría de los casos se hará uso de las interfaces de Spring Data / JPA, no se hará uso de este campo.

  • id: expresión SpEL que indica que argumento/valor del método se utilizará como id para la notificación. Este id es el identificador único de la instancia con la que se está operando. P.e. “#p0”

  • payload: expresión SpEL que indica que argumento/valor del método se utilizará como cuerpo de la notificación. P.e. “#p1”.

Ejemplos de uso:

INSERT

 

QUERY

UPDATE

DELETE

 

Podéis encontrar un ejemplo que hace uso de esta librería en:

https://github.com/onesaitplatform/platform-entities-jpa