Note:

Creación de una aplicación Java basada en Oracle GraalVM mediante Spring Boot en OKE para almacenar mensajes SOAP en ATP y enviar a OCI Queue

Introducción

Muchos de nuestros clientes confían en la mensajería SOAP (Simple Object Access Protocol) tradicional para permitir la comunicación entre sus aplicaciones. A menudo necesitan almacenar datos transaccionales, garantizar la desvinculación del servicio, lograr el equilibrio de carga de solicitudes entrantes y permitir la comunicación asíncrona de estos mensajes.

En este tutorial, veremos cómo podemos crear una aplicación Java basada en Oracle GraalVM mediante Spring Boot desplegada en la infraestructura de Oracle Cloud Infrastructure Kubernetes Engine (OKE) que se utilizará como integrador transaccional con los diferentes servicios de Oracle Cloud Infrastructure (OCI), como Oracle Autonomous Transaction Processing (ATP) y OCI Queue. Esta configuración permite a los sistemas interactuar sin conexiones directas, facilitando la comunicación entre aplicaciones con diferentes velocidades de procesamiento. Además, una vez que la información se almacena en la base de datos, se puede consultar o analizar.

Utilizaremos las siguientes tecnologías:

Servicios de Oracle Cloud Infrastructure (OCI): OCI es una plataforma en la nube segura y de alto rendimiento que ofrece más de 150 servicios en la nube. Está diseñado para ofrecer escalabilidad, seguridad y rendimiento.

Tecnología Oracle:

Otras tecnologías:

Arquitectura de alto nivel de OCI:

Arquitectura de OCI

Arquitectura de casos de uso

Nota:

Objetivos

Requisitos

Tarea 1: Aprovisionamiento y configuración del cluster de OKE

En esta tarea, aprovisionaremos la plataforma de Kubernetes, donde la aplicación soportará todos los mensajes de alta transaccionalidad de SOAP para almacenar en ATP y enviar cada uno a OCI Queue en tiempo real.

  1. Conéctese a la consola de OCI, vaya a Developer Services, Kubernetes Clusters (OKE) y seleccione Compartment de su preferencia.

    Hay dos formas de crear un cluster de OKE:

    • Creación Rápida.
    • Creación personalizada.
  2. Seleccione Creación rápida, ya que este método es más fácil, rápido y despliega automáticamente todos los elementos requeridos por OKE para su operación, como:

    • Red virtual en la nube (VCN).
    • Gateway de Internet.
    • Gateway de traducción de direcciones de red (NAT).
    • Gateway de servicio.
    • Cluster de Kubernetes.
    • Nodos de trabajador y pool de nodos de Kubernetes.

    Nota: Para los entornos empresariales, donde ya los clientes tienen servicios, red, infraestructura, es importante personalizar el despliegue de OKE, para cumplir, alinearse con la arquitectura del cliente, los recursos y seguir las mejores prácticas.

    Creación Rápida

  3. Haga clic en Crear cluster e introduzca la siguiente información.

    • Nombre: introduzca el nombre del cluster de OKE.
    • Compartimento: seleccione el compartimento creado para este proyecto.
    • Versión de Kubernetes: seleccione la última versión de Kubernetes disponible.
    • Punto final de API de Kubernetes: en este tutorial, seleccione Punto final público, pero también puede seleccionar Punto final privado.
    • Tipo de nodo: seleccione nodos gestionados.
    • Nodos de trabajador de Kubernetes: seleccione Trabajadores privados.
    • Unidad e imagen: seleccione VM.Standard.E5. Flexibilice, personalice el número de OCPU (2) y memoria (16 GB) y conserve la imagen por defecto de Oracle Linux 8.
    • Recuento de nodos: introduzca 2 nodos de trabajador para desplegar con el pool de nodos de OKE.

    Crear cluster de OKE

    Revise que el cluster de OKE esté funcionando.

    OKE en ejecución

Tarea 2: Aprovisionamiento, configuración y acceso a OCI Container Registry Classic

Necesitamos gestionar las imágenes del proyecto en un repositorio. Para ello, aprovisionaremos OCI Container Registry Classic. Una vez que las imágenes se almacenen en OCI Container Registry Classic, podremos desplegarlas en OKE.

  1. Vaya a la consola de OCI, vaya a Developer Services, Containers & Artifacts, Container Registry y haga clic en Create Repository.

  2. Introduzca la siguiente información y haga clic en Crear.

    • Crear en compartimento: seleccione el compartimento creado para este proyecto.
    • Acceso: seleccione Público.
    • Nombre del repositorio: introduzca springboot/tutorialapp.

    Crear Repositorio

  3. Una vez creado el repositorio, desde el host de administrador de Oracle acceda a él mediante el siguiente comando.

    docker login -u 'tenancy_namespace/domain/username' regionID.ocir.io
    
    Password: xxxxxx
    

    Autenticación de Oracle Registry

    CORRECTO

Tarea 3: Aprovisionamiento y configuración de la base de datos sin servidor de Oracle Autonomous Transaction Processing (ATP)

En la base de datos ATP, almacenaremos los datos de cada mensaje SOAP recibido por transacción, aproximadamente cada uno estará en el orden de milisegundos, atendiendo a inserciones paralelas y secuenciales.

  1. Vaya a la consola de OCI, vaya a Oracle Database y haga clic en Autonomous Transaction Processing.

  2. Haga clic en Create Autonomous Database e introduzca la siguiente información.

    • Seleccionar el compartimento: seleccione el compartimento creado para este proyecto.
    • Nombre mostrado: introduzca el nombre mostrado.
    • Mostrar nombre de base de datos: introduzca el nombre de la base de datos.
    • Seleccionar un tipo de carga de trabajo: seleccione Procesamiento de transacciones.
    • Seleccionar un tipo de despliegue: seleccione Sin servidor.
    • Configurar la base de datos:
      • Desarrollador: anule la selección.
      • Seleccionar versión de base de datos: seleccione 23ai.
      • Recuento de ECPU: introduzca 2.
      • Escala automática de recursos informáticos: selecciónela.
      • Almacenamiento: introduzca 1024 GB.
    • Período de retención de copia de seguridad automática en días: deje la opción por defecto en 60 días.
    • Crear credenciales de administrador:
      • Nombre de usuario: es ADMIN por defecto y no se puede editar.
      • Contraseña: introduzca su contraseña preferida.
      • Confirmar contraseña: vuelva a introducir la contraseña.
    • Seleccionar acceso de red: seleccione Solo acceso de punto final privado y, a continuación, seleccione la VCN y la subred creadas para este proyecto. Este valor restringe las conexiones solo a la red privada (VCN) especificada. Sin embargo, puede elegir otras opciones, esto depende de las necesidades de la empresa.

    Crear base de datos de Oracle ATP

    Crear base de datos de Oracle ATP

    Crear base de datos de Oracle ATP

    Revise que la base de datos ATP se esté ejecutando.

    ATP en ejecución

Tarea 4: Conexión y creación de tablas de proyecto en Oracle Autonomous Transaction Processing (ATP)

Ahora, necesitamos configurar, conectar y crear las tablas del proyecto en la base de datos ATP que se generó en la Tarea 3.

  1. Vaya a la consola de OCI, vaya a Oracle Database, Autonomous Transaction Processing y haga clic en Conexión a base de datos. Seleccione Autenticación TLS, TLS y haga clic en Descargar cartera.

    Conexión a Base de Datos

  2. Descomprima el archivo .zip de cartera y, en tnsnames.ora, puede obtener la URL del origen de datos para obtener la conexión a esta base de datos. Guarde esta URL de origen de datos.

    Por ejemplo:

    tutorialoracleatp_medium = (description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=xxxxxxxx.adb.sa-saopaulo-1.oraclecloud.com))(connect_data=(service_name=xxxxxxxxxxxxxxx_tutorialoracleatp_medium.adb.oraclecloud.com))(security=(ssl_server_dn_match=no)))
    
  3. Ahora es necesario acceder a la base de datos. Cuando se aprovisionó el ATP, se activó el acceso a Oracle REST Data Services (ORDS). Para obtener más información, consulte Oracle REST Data Services.

    Vaya a la página Detalles de Autonomous Database y haga clic en Acciones de base de datos. Tenga en cuenta que solo se puede acceder a ella desde una instancia informática que se ejecute en la misma red virtual en la nube (VCN).

    Acciones de base de datos

  4. Pegue la URL en el explorador y acceda a ORDS mediante el usuario y la contraseña introducidos anteriormente en la base de datos ATP y acceda al módulo Oracle SQL Developer Web.

    ORDS

  5. Utilice las siguientes consultas para crear las tablas USERS, CARS y HOUSES relacionadas con los mensajes de SOAP que recibiremos.

    CREATE TABLE USERS (
    username varchar(50) NOT NULL,
    userlastname varchar(50) NOT NULL,
    id int NOT NULL,
    email varchar(50) NOT NULL,
    dateuser varchar(50) NOT NULL,
    attributeuser varchar(50) NOT NULL  
    );
    
    CREATE TABLE CARS (
    userid int NOT NULL,
    brand varchar(50) NOT NULL,
    color varchar(50) NOT NULL,
    plate varchar(50) NOT NULL  
    );
    
    CREATE TABLE HOUSES (
    userid int NOT NULL,
    floors int NOT NULL,
    locationhouse varchar(50) NOT NULL,
    rooms int NOT NULL,
    bathrooms int NOT NULL
    );
    

    Se han creado tablas en la base de datos

Tarea 5: Aprovisionamiento y configuración de OCI Queue

En OCI Queue, almacenaremos mensajes altamente transaccionales a través de la API HTTP RESTful durante un período de tiempo específico. A continuación, los consumidores pueden leer y suprimir los mensajes inmediatamente o cuando lo deseen, lo que garantiza la disociación y evita la pérdida de datos.

  1. Vaya a la consola de OCI, vaya a Developer Services, Application Integration y haga clic en Queues.

  2. Haga clic en Crear cola, introduzca la siguiente información y haga clic en Crear cola.

    • Nombre: introduzca el nombre adecuado para la cola.
    • Compartimento: seleccione el compartimento de trabajo.
    • Configuración de cola: en este tutorial, seleccionaremos Configuración por defecto, pero si lo prefiere, puede personalizar varias opciones según las necesidades del negocio, como: Timeout de visibilidad, Período de retención máximo, Consumo de canal máximo y configuración de Cola de cartas muertas.
    • Configurar valores de cifrado: seleccione Clave gestionada por Oracle, pero Clave gestionada por el cliente también es una opción.

    Crear Cola

    Revise que OCI Queue se esté ejecutando.

    Ejecución de OCI Queue

Tarea 6: Creación de una aplicación Java basada en Oracle GraalVM con Spring Boot y despliegue en OKE

Ahora, desarrollaremos y desplegaremos una aplicación Java basada en Oracle GraalVM en Spring Boot que realizará las siguientes tareas:

Nota: Antes de comenzar, es importante que se cree un host de administración y un entorno de desarrollo, como se muestra en las secciones Requisitos - Host de administración y Requisitos - Entorno de desarrollo.

Una vez que el host de administración y el entorno de desarrollo estén configurados y listos, puede comenzar a desarrollar su proyecto Spring Boot.

  1. Vaya a Spring initializr y cree el primer proyecto que nos proporcione la estructura de carpetas y los archivos base de un proyecto Spring Boot para modificarlo más adelante según nuestros requisitos. Introduzca la siguiente información y haga clic en Generar. De esta forma, se descargará automáticamente el proyecto Spring Boot, se guardará y se descomprimirá en el host de desarrollo.

    • Proyecto: seleccione Maven.
    • Idioma: seleccione Java.
    • Inicio de Spring: seleccione 3.3.6.
    • Metadatos del Proyecto:
      • Grupo: introduzca com.tutorial_springboot.
      • Artefacto: introduzca tutorial.
      • Nombre: introduzca tutorial.
      • Descripción: introduzca Aplicación de inicio Spring (lea SOAP, transforme en JSON, inserte ATP y Put en OCI Queue).
    • Empaquetado: seleccione Jar.
    • Java: seleccione 17.
    • Dependencies: seleccione Oracle Driver, Spring Web Services y Spring Web.

    Nota: Podemos agregar algunas dependencias en el proyecto y, posteriormente, agregar más directamente en el archivo pom.xml, según nuestras necesidades.

    Proyecto Springboot

  2. Ahora tenemos el proyecto de estructura de bota de primavera.

    Estructura Spring boot project

    Revise el archivo pom.xml, empezaremos a trabajar en él.

    Archivo POM original

    Actualice el archivo pom.xml, según el ámbito propuesto en este tutorial.

    • Agregue la versión oci sdk y las siguientes dependencias.

      • oci-java-sdk-common.
      • oci-java-sdk-queue.
      • oci-java-sdk-addons-oke-workload-identity.
      • oci-java-sdk-common-httpclient-jersey3.

      La aplicación deberá autenticarse con OCI, conectarse y gestionar servicios de OCI, como OCI Queue.

    • Ya nuestro archivo pom.xml tiene la dependencia spring-boot-starter-web-services y tenemos que agregar la dependencia wsdl4j. El objetivo principal es obtener los datos recibidos de los mensajes SOAP y ponerlos en objetos Java, creando servicios web de Spring manipulando cargas útiles XML, con el objetivo de facilitar el desarrollo de servicios SOAP de primer contrato. También permite configurar el puerto, URI y definir el esquema XML cargado desde el archivo de definición de esquema XML (XSD).

    • Agregue la dependencia de JSON. Esta biblioteca se utilizará para generar formato JSON con los datos extraídos del mensaje SOAP.

    • Agregue el plugin spring-boot-maven-plugin en la sección Build. Este plugin nos permitirá generar el archivo de proyecto de Spring Boot ejecutable de jar.

    • Agregue el plugin jaxb2-maven-plugin en la sección Build. Este plugin utilizará la API Java para el enlace XML (JAXB), para generar clases Java a partir de esquemas XML y, de esta forma, podemos transferir los datos del mensaje SOAP a los objetos de clase Java creados por nosotros.

      En esta sección del plugin, es importante poner la configuración que indicará la ruta, donde se incluye el archivo XSD en nuestro proyecto Spring Boot.

      <configuration>
         <sources>
         <source>${project.basedir}/src/main/resources/messages.xsd<source>
         </sources>
      </configuration>
      
    • Agregue la dependencia jasypt-spring-boot-starter en la sección Dependencias y el plugin jasypt-maven-plugin en la sección Creación que nos permitirá cifrar parámetros confidenciales en el archivo application.properties, garantizando un uso seguro dentro de nuestra aplicación.

    Revise las siguientes dependencias agregadas en el archivo pom.xml.

    Archivo POM modificado

    Archivo POM modificado

  3. Descargue las bibliotecas y ejecute los siguientes comandos.

    1. En el entorno de desarrollo, ejecute el siguiente comando para acceder al proyecto.

      cd tutorial
      

      Carpeta de proyecto de inicio Spring

    2. Limpie el proyecto y elimine todos los archivos generados por la compilación anterior.

      mvn clean
      

      Limpieza de Maven

    3. Depure (suprima y, opcionalmente, vuelva a resolver) los artefactos del repositorio de maven local.

      mvn dependency:purge-local-repository
      

    Dependencias de depuración de Maven

  4. Ya tenemos las dependencias y el archivo pom.xml configurados en nuestro proyecto, procederemos a comprobar el archivo XML SOAP, ya que representa la solicitud desde el lado del cliente, y el archivo XSD, que interpreta la solicitud en nuestro lado del proyecto Spring Boot.

    1. Este archivo XML SOAP tiene dos mensajes, con información personal y otros tipos de atributos de dos clientes diferentes que enviaremos por solicitud como se muestra en la siguiente imagen.

      Archivo de jabón

    2. Ahora, en nuestro proyecto Spring Boot, es necesario un esquema XML para definir un dominio de servicio web que Spring Web Service exporta automáticamente como WSDL, en la siguiente imagen se muestra el archivo messages.xsd definido para este tutorial.

      messages.xsd:

      archivo XSD

    3. Guarde el archivo messages.xsd en la carpeta de recursos del proyecto Spring Boot.

      Archivo XSD en carpeta

  5. Crear e instalar archivos de proyecto en un archivo jar. Ejecute el siguiente comando y asegúrese de que está en la carpeta de proyecto Spring Boot.

    mvn install
    

    Nota: Una vez ejecutado el comando maven install, se genera automáticamente la carpeta de destino y, de la misma forma, las clases Java según el archivo XSD creado anteriormente y el archivo .jar ejecutable del proyecto.

    Carpeta de Destino

  6. Ahora, podemos agregar las clases Java necesarias a nuestro proyecto Spring Boot.

    WebServiceConfig.java Class: Esta clase Java se ha desarrollado para crear el servicio web SOAP:

    • Configura el servlet para manejar solicitudes de SOAP.
    • Genera una definición WSDL basada en un esquema XML.
    • Define el punto final de acceso del servicio web SOAP.
    • Utiliza el archivo de esquema messages.xsd de la classpath.
    //Imports
    import org.springframework.boot.web.servlet.ServletRegistrationBean; //import the ServletRegistrationBean class
    import org.springframework.context.ApplicationContext; //import the ApplicationContext class
    import org.springframework.context.annotation.Bean; //import the Bean class
    import org.springframework.context.annotation.Configuration; //import the Configuration class
    import org.springframework.core.io.ClassPathResource; //import the ClassPathResource class
    import org.springframework.ws.config.annotation.EnableWs; //import the EnableWs class
    import org.springframework.ws.config.annotation.WsConfigurerAdapter; //import the WsConfigurerAdapter class
    import org.springframework.ws.transport.http.MessageDispatcherServlet; //import the MessageDispatcherServlet class
    import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition; //import the DefaultWsdl11Definition class
    import org.springframework.xml.xsd.SimpleXsdSchema; //import the SimpleXsdSchema class
    import org.springframework.xml.xsd.XsdSchema; //import the XsdSchema class
    
    //Configuration class for the Web Service configuration
    @EnableWs //Enable the Web Service
    @Configuration //Define the class as a Configuration class 
    
    public class WebServiceConfig extends WsConfigurerAdapter {
    
       //Create a ServletRegistrationBean object to register the MessageDispatcherServlet object with the application context
       @Bean
       public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
          MessageDispatcherServlet servlet = new MessageDispatcherServlet(); //Create a MessageDispatcherServlet object
          servlet.setApplicationContext(applicationContext); //Set the application context for the MessageDispatcherServlet object
          servlet.setTransformWsdlLocations(true); //Set the transformWsdlLocations property to true
          return new ServletRegistrationBean<>(servlet, "/ws/*"); //Return a new ServletRegistrationBean object with the MessageDispatcherServlet object and the URL pattern
       }
    
       //Create a DefaultWsdl11Definition object to define the WSDL
       @Bean(name = "messages")
       public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema messagesSchema) {
          DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition(); //Create a DefaultWsdl11Definition object
          wsdl11Definition.setPortTypeName("MessagesPort"); //Set the port type name
          wsdl11Definition.setLocationUri("/ws"); //Set the location URI
          wsdl11Definition.setTargetNamespace("http://tutorial_example.com/ns0"); //Set the target namespace
          wsdl11Definition.setSchema(messagesSchema); //Set the schema
          return wsdl11Definition; //Return the DefaultWsdl11Definition object
       }
    
       //Create a XsdSchema object to define the schema
       @Bean
       public XsdSchema messagesSchema() {
          return new SimpleXsdSchema(new ClassPathResource("messages.xsd")); //Return a new SimpleXsdSchema object with the messages.xsd file
       }
    }
    

    Nota: Si desea probar el servicio web, puede ejecutar el proyecto Spring Boot en el mismo escritorio de entorno de desarrollo local y enviar la solicitud HTTP mediante curl, de la siguiente forma:

    mvn spring-boot:run
    

    Ejecutar proyecto de inicio Spring

    Ejecutar proyecto de inicio Spring

    Una vez que el proyecto se esté ejecutando y el servicio web esté activo, ejecute una solicitud HTTP de SOAP local mediante curl, de la siguiente forma:

    curl --location 'http://localhost:8080/ws/'
    

    Y obtendrá una respuesta del servicio web expuesto en nuestro proyecto Spring Boot.

    Servicio Web de SOAP

  7. Cree una carpeta denominada model y en esta carpeta agregaremos las siguientes clases Java.

    Carpeta de Modelo

    Nota: Estas clases Java Car, House y User recuperarán la información basada en los datos de cada mensaje de SOAP extraído de la solicitud de SOAP HTTP.

    • Car.java class: Esta clase Java representa un objeto Car con sus atributos enlazados a cada usuario.

      ```
      //Imports
      import org.springframework.stereotype.Component; // For component scanning
      import org.springframework.context.annotation.Scope; // For defining bean scope
      
      @Component // Marks a class as a Spring-managed component
      @Scope("prototype") //A new instance is created every time the bean is requested
      
      public class Car {
      
         //Attributes
      
         private String brand; 
         private String color; 
         private String plate; 
      
         //"getter" and "setter" methods to get and set the information in each object
      
         public String getBrand(){
         return brand;
         }
      
         public void setBrand(String brand){
         this.brand = brand;
         }
      
         public String getColor(){
         return color;
         }
      
         public void setColor(String color){
         this.color = color;
         }
      
         public String getPlate(){
         return plate;
         }
      
         public void setPlate(String plate){
         this.plate = plate;
         }
      
      }
      ```
      
      • House.java class: Esta clase Java representa un objeto Casa con sus atributos enlazados a cada usuario.

        //Imports
        import org.springframework.stereotype.Component; // For component scanning
        import org.springframework.context.annotation.Scope; // For defining bean scope
        
        @Component // Marks a class as a Spring-managed component
        @Scope("prototype") //A new instance is created every time the bean is requested
        
        public class House {
        
           //Attributes
        
           private int floors;
           private String location;
           private int rooms;
           private int bathrooms;
        
        
           //"getter" and "setter" methods to get and set the information in each object
        
           public int getFloors(){
              return floors;
           }
        
           public void setFloors(int floors){
              this.floors = floors;
           }
        
           public String getLocation(){
              return location;
           }
        
           public void setLocation(String location){
              this.location = location;
           }
        
           public int getRooms(){
              return rooms;
           }
        
           public void setRooms(int rooms){
              this.rooms = rooms;
           }
        
           public int getBathRooms(){
              return bathrooms;
           }
        
           public void setBathRooms(int bathrooms){
              this.bathrooms = bathrooms;
           }
        
        }
        
      • User.java class: Esta clase Java representa un objeto User con sus atributos, que contiene objetos Car y House.

        //Imports
        import org.springframework.stereotype.Component; // For component scanning
        import org.springframework.context.annotation.Scope; // For defining bean scope
        
        @Component // Marks a class as a Spring-managed component
        @Scope("prototype") //A new instance is created every time the bean is requested
        
        
        public class User {
        
           //Attributes
        
           private String username; 
           private String userlastname;
           private int id;
           private String email;
           private String date;
           private String attribute;
           private Car car;
           private House house;
        
        
           //"getter" and "setter" methods to get and set the information in each object
        
           public String getUserName(){
           return username;
           }
        
           public void setUserName(String username){
           this.username = username;
           }
        
           public String getUserLastName(){
           return userlastname;
           }
        
           public void setUserLastName(String userlastname){
           this.userlastname = userlastname;
           }    
        
           public int getID(){
           return id;
           }
        
           public void setID(int id){
           this.id = id;
           }        
        
           public String getEmail(){
           return email;
           }
        
           public void setEmail(String email){
           this.email = email;
           }
        
           public String getDate(){
           return date;
           }
        
           public void setDate(String date){
           this.date = date;
           }
        
           public String getAttribute(){
           return attribute;
           }
        
           public void setAttribute(String attribute){
           this.attribute = attribute;
           }
        
           public Car getCar(){
           return car;
           }
        
           public void setCar(Car car){
           this.car = car;
           }
        
           public House getHouse(){
           return house;
           }
        
           public void setHouse(House house){
           this.house = house;
           }
        }
        
  8. Ahora configuraremos los parámetros necesarios en nuestro proyecto Spring Boot para almacenar los datos obtenidos en la base de datos ATP de OCI. En la carpeta resources, debe buscar el archivo application.properties utilizado para agregar los parámetros que necesita la aplicación. Se genera automáticamente y se carga mediante Spring Boot cuando se inicia la aplicación.

    Nota: Es muy importante gestionar métodos de cifrado y seguridad que garanticen que los hackers no puedan extraer ni ver información confidencial, como contraseñas o datos relevantes. En este tutorial, utilizamos la biblioteca de jasypt configurada en el archivo pom.xml. Para obtener más información, consulte How to encrypt password in a Spring Boot project using Jasypt. Además, en nuestras clases Java de Spring Boot se documenta dónde agregar las anotaciones y el código fuente relacionados con esta biblioteca para descifrar los parámetros application.properties.

    Agregue los parámetros adecuados requeridos por la base de datos ATP en el archivo application.properties, como se muestra en la siguiente imagen.

    Archivo de propiedades de aplicación

    Cree la clase Java de Spring Boot para almacenar cada mensaje en la base de datos; estará en la carpeta database, como se muestra en la siguiente imagen.

    Database Folder

    • SoapObjectRepository.java: Esta clase Java de Spring Boot permite insertar en formato transaccional en tiempo real, cada mensaje en ATP, mediante el controlador JDBC.

      //Java Classes USER, CAR, HOUSE Imports
      import com.oracle_springboot_tutorial.tutorial.model.*;
      
      //Spring Boot Imports
      import org.springframework.stereotype.Repository;
      import org.springframework.jdbc.core.JdbcTemplate;
      import org.springframework.beans.factory.annotation.Autowired;
      
      //Repository Class to save SOAP Messages in the Database
      @Repository
      public class SoapObjectRepository {
         private JdbcTemplate template;
         private User user;
      
         //Getters and Setters for JdbcTemplate template object
         public JdbcTemplate getTemplate(){
            return template;
         }
      
         //Autowired annotation to inject JdbcTemplate object into the template object
         @Autowired
         public void setTemplate(JdbcTemplate template){
            this.template = template;
         }
      
         //Method to save User SOAP Message in the Database
         public void saveUserSOAPMessage(User user){
            this.user = user;
            String sql = "INSERT INTO USERS (username, userlastname, id, email, dateuser, attributeuser) VALUES(?, ?, ?, ?, ?, ?)";
            template.update(sql, user.getUserName(), user.getUserLastName(), user.getID(), user.getEmail(), user.getDate(), user.getAttribute());
         }
      
         //Method to save Car SOAP Message in the Database
         public void saveCarSOAPMessage(Car car){
            String sql = "INSERT INTO CARS (userid, brand, color, plate) VALUES(?, ?, ?, ?)";
            template.update(sql, user.getID(), car.getBrand(), car.getColor(), car.getPlate());
         }
      
         //Method to save House SOAP Message in the Database
         public void saveHouseSOAPMessage(House house){
            String sql = "INSERT INTO HOUSES (userid, floors, locationhouse, rooms, bathrooms) VALUES(?, ?, ?, ?, ?)";
            template.update(sql, user.getID(), house.getFloors(), house.getLocation(), house.getRooms(), house.getBathRooms());
         }
      
      
      }
      

      Ahora, agregue el código de software JSON, creando primero la carpeta json_message y su clase Java Spring Boot como se muestra en la siguiente imagen.

      Carpeta Json

    • JsonBuilder.java: Esta clase Java de Spring Boot se convierte del formato XML SOAP al formato JSON.

      //Imports to be used for JSON
      import org.json.JSONArray;
      import org.json.JSONObject;
      
      //Imports to be used for the User class
      import com.oracle_springboot_tutorial.tutorial.model.*;
      
      
      //Imports to be used for the ArrayList class
      import java.util.ArrayList;
      
      
      public class JsonBuilder {
      
         //The buildJsonMessage method creates a JSON object from the ArrayList of User objects
         public JSONObject buildJsonMessage(ArrayList<User> usersMessageArray) {
      
            JSONObject rootJson = new JSONObject(); //Create a new JSON object called rootJson
            JSONObject messagesJson = new JSONObject(); //Create a new JSON object called messagesJson
            JSONArray messageArray = new JSONArray(); //Create a new JSON array called messageArray
      
      
            //Iterate through the ArrayList of User objects and create a JSON object for each User object in the ArrayList
            for (User user : usersMessageArray) {
                  JSONObject messageJson = new JSONObject();
                  messageJson.put("username", user.getUserName()); //Add the username of the user to the messageJson object
                  messageJson.put("userlastname", user.getUserLastName()); //Add the userlastname of the user to the messageJson object
                  messageJson.put("id", user.getID()); //Add the id of the user to the messageJson object
                  messageJson.put("email", user.getEmail()); //Add the email of the user to the messageJson object
                  messageJson.put("date", user.getDate()); //Add the date of the user to the messageJson object
                  messageJson.put("attribute", user.getAttribute()); //Add the attribute of the user to the messageJson object
      
      
                  //
                  JSONObject bodyJson = new JSONObject(); //Create a new JSON object called bodyJson
                  JSONObject envelopeJson = new JSONObject(); //Create a new JSON object called envelopeJson
      
                  //Switch statement to check the attribute of the User object
                  switch (user.getAttribute()) {
                     case "CAR":
                              Car car = user.getCar();
                              envelopeJson.put("brand", car.getBrand()); //Add the brand of the car to the envelopeJson object
                              envelopeJson.put("color", car.getColor()); //Add the color of the car to the envelopeJson object
                              envelopeJson.put("plate", car.getPlate()); //Add the plate of the car to the envelopeJson object                       
                        break;
                     case "HOUSE":
                              House house = user.getHouse();
                              envelopeJson.put("floors", house.getFloors()); //Add the floors of the house to the envelopeJson object
                              envelopeJson.put("location", house.getLocation()); //Add the location of the house to the envelopeJson object
                              envelopeJson.put("rooms", house.getRooms()); //Add the rooms of the house to the envelopeJson object
                              envelopeJson.put("bathrooms", house.getBathRooms()); //Add the bathrooms of the house to the envelopeJson object                     
                        break;
                     default:
                        System.out.println("Unknown subject: " + user.getAttribute());
                  }
      
      
                  bodyJson.put("envelope", envelopeJson); //Add the envelopeJson object to the bodyJson object
      
                  messageJson.put("body", bodyJson); //Add the bodyJson object to the messageJson object
      
               messageArray.put(messageJson); //Add the messageJson object to the messageArray array
            }
      
            messagesJson.put("message", messageArray); //Add the messageArray array to the messagesJson object
            rootJson.put("messages", messagesJson); //Add the messagesJson object to the rootJson object
      
            return rootJson;
         }
      }
      
  9. Ahora, podemos enviar los mensajes en formato JSON a OCI Queue. Cree la carpeta oci_queue y su clase Java Spring Boot como se muestra en la siguiente imagen.

    Carpeta de cola

    Nota: En la clase OCIQueue.java, tendremos que definir el acceso de OKE a OCI Queue. En este tutorial, utilizaremos Acceso a cargas de trabajo para otorgar acceso a los recursos de OCI, sin tener que manejar información confidencial como usuario, contraseñas, OCID asociados a su arrendamiento. Para obtener más información, consulte Otorgamiento de acceso de cargas de trabajo a recursos de OCI.

    Antes de empezar a desarrollar la clase OCIQueue.java, configuraremos el acceso a las cargas de trabajo en nuestro arrendamiento. En primer lugar, necesitamos crear un espacio de nombres para asociarlo a nuestra aplicación Java basada en Oracle GraalVM. Asegúrese de que está en el host de administración.

    kubectl create ns-tutorial
    

    A continuación, cree una cuenta de servicio de Kubernetes para la aplicación.

    kubectl create serviceaccount tutorialserviceaccount --namespace ns-tutorial
    

    Ahora, defina una política de OCI IAM para permitir que la carga de trabajo acceda a los recursos de OCI necesarios. En este tutorial, OCI Queue.

    Vaya a la consola de OCI, vaya a Identidad y seguridad, Políticas y haga clic en Crear política. Introduzca la siguiente información y haga clic en Crear.

    • Nombre: introduzca el nombre de política preferido.
    • Descripción: introduzca Acceso de oke a cola de oci.
    • Creador de política:

      Allow any-user to use queues in compartment id ocid1.compartment.oc1..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx where all {request.principal.type = 'workload', request.principal.namespace = 'ns-tutorial', request.principal.service_account = 'tutorialserviceaccount', request.principal.cluster_id = 'ocid1.cluster.oc1.sa-saopaulo-1.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}
      

    Política de acceso a cargas de trabajo

    Una vez que configure la política de acceso de carga de trabajo, el espacio de nombres y la cuenta de servicio, podemos continuar.

    En el archivo application.properties, agregue los parámetros de cola necesarios para conectar y gestionar la cola de OCI específica creada en la tarea 5.

    Configuración de OCIID

    • OCIQueue.java: Esta clase Java de Spring Boot permite acceder y colocar los mensajes en OCI Queue.

      //Imports
      import com.oracle.bmc.auth.okeworkloadidentity.OkeWorkloadIdentityAuthenticationDetailsProvider; //Import OkeWorkloadIdentityAuthenticationDetailsProvider to enable access and use OCI Workload Identity
      import com.oracle.bmc.queue.QueueClient; //Import QueueClient to have access and manage of OCI Queue
      import com.oracle.bmc.queue.model.PutMessagesDetails; //Import PutMessagesDetails to send messages to the OCI Queue
      import com.oracle.bmc.queue.model.PutMessagesDetailsEntry; //Import PutMessagesDetailsEntry to send messages to the OCI Queue
      import com.oracle.bmc.queue.requests.PutMessagesRequest; //Import PutMessagesRequest to send messages to the OCI Queue
      
      //Imports for the ArrayList and List
      import java.util.ArrayList;
      import java.util.List;
      
      public class OCIQueue {
         //Set the required parameters to access to OCI and the Queue
      
         //Variables
         private String queueId; 
         private String endPoint;
         private String region;
      
         //Constructor to initialize the OCI Queue object with the required parameters
         public OCIQueue(String queueId, String endPoint, String region){
            this.queueId = queueId;
            this.endPoint = endPoint;
            this.region = region;   
         }
      
      
         //The sendMessages method sends a message to the OCI Queue
         public void sendMessages(String jsonMessage){
            try{    
      
                  //Create an OkeWorkloadIdentityAuthenticationDetailsProvider object to authenticate the OCI Queue
                  OkeWorkloadIdentityAuthenticationDetailsProvider provider = new OkeWorkloadIdentityAuthenticationDetailsProvider.OkeWorkloadIdentityAuthenticationDetailsProviderBuilder().build();
      
                  //Create a QueueClient object to send the message to the OCI Queue
                  QueueClient queueClient = QueueClient.builder().build(provider);
                  queueClient.setRegion(region);
                  queueClient.setEndpoint(endPoint);
      
      
      
                  //Create a PutMessagesDetailsEntry object to send the message
                  PutMessagesDetailsEntry message = PutMessagesDetailsEntry.builder()
                     .content(jsonMessage)
                     .build();
      
                  //Create a List of PutMessagesDetailsEntry objects to send the message
                  List<PutMessagesDetailsEntry> messages = new ArrayList<>();
                  messages.add(message);
      
                  //Create a PutMessagesDetails object to send the message
                  PutMessagesDetails putMessagesDetails = PutMessagesDetails.builder()
                     .messages(messages)
                     .build();
      
      
                  //  Create a PutMessagesRequest object to send the message
                  PutMessagesRequest putMessagesRequest = PutMessagesRequest.builder()
                     .queueId(queueId)
                     .putMessagesDetails(putMessagesDetails)
                     .build();
      
                  // Send the request and get the response
                  queueClient.putMessages(putMessagesRequest);
      
            }catch(Exception e){
                  System.out.println("Exception sending message to OCI Queue: "+e);
            }
         }
      }
      
  10. Una vez que tenga las clases Java de Spring Boot para la base de datos, JSON y OCI Queue, podemos continuar con la clase MessagesEndpoint.java.

    Para ello, crearemos una carpeta denominada endpoint y su clase Java Spring Boot.

    Carpeta de punto final

    Nota: En MessagesEndpoint.java, necesitamos importar algunas clases generadas automáticamente. Para ello, agregue el siguiente origen en la sección Configuración del archivo pom.xml:

    <configuration>
       <sources>
       <source>${project.build.directory}/generated-sources</source>
       </sources>
    </configuration>
    

    El archivo pom.xml debe tener un aspecto similar.

    Ruta de acceso de orígenes generados

    • MessagesEndpoint.java: La finalidad de esta clase Java de Spring Boot es extraer la solicitud HTTP de SOAP y asignar sus valores a los objetos Java User, Car y House para cada mensaje. A continuación, almacena los datos extraídos en una base de datos ATP para cada transacción XML de SOAP, convierte los datos de XML a formato JSON y coloca los mensajes en una cola de OCI. Estos mensajes pueden ser recuperados y eliminados posteriormente de la cola por los consumidores.

      //Imports
      import com.oracle_springboot_tutorial.tutorial.model.*; //Import all the classes from the model package
      import com.oracle_springboot_tutorial.tutorial.oci_queue.OCIQueue; //Import the OCIQueue class from the oci_queue package
      
      
      import com.tutorial_example.ns0.Messages;//Import the Messages class from the tutorial_example.ns0 package (Auto generated Java Classes from the WSDL)
      import com.tutorial_example.ns0.MessageType; //Import the MessageType class from the tutorial_example.ns0 package (Auto generated Java Classes from the WSDL)
      
      //Import the ArrayList class from the java.util package
      import java.util.ArrayList;
      
      //Spring Boot imports to be used for the SOAP Web Service
      import org.springframework.beans.factory.annotation.Autowired; //Import the @Autowired annotation to inject the SoapObjectRepository object
      import org.springframework.beans.factory.annotation.Value; //Import the @Value annotation to inject the values from the application.properties file
      import org.springframework.stereotype.Component; //Import the @Component annotation to register the class with Spring
      
      //Spring Boot imports 
      import org.springframework.ws.server.endpoint.annotation.Endpoint; //Import the @Endpoint annotation to register the class with Spring WS
      import org.springframework.ws.server.endpoint.annotation.PayloadRoot; //Import the @PayloadRoot annotation to specify the namespace URI and local part of the request payload
      import org.springframework.ws.server.endpoint.annotation.RequestPayload; //Import the @RequestPayload annotation to map the request payload to the method parameter
      import org.springframework.ws.server.endpoint.annotation.ResponsePayload; //Import the @ResponsePayload annotation to map the returned value to the response payload
      
      //Imports to be used storing SOAP information in the database 
      import com.oracle_springboot_tutorial.tutorial.database.SoapObjectRepository; //Import the SoapObjectRepository class from the database package
      
      //Imports to be used for JSON
      import com.oracle_springboot_tutorial.tutorial.json_message.JsonBuilder; //Import the JsonBuilder class from the json_message package 
      import org.json.JSONObject; //Import the JSONObject class from the org.json package
      
      
      //The @Endpoint annotation registers the class with Spring WS.
      //The @Component annotation registers the class with Spring to be used as a Spring Bean.
      @Endpoint
      @Component
      public class MessagesEndpoint {
      
         //Inject not encrypted and decrypted values using jasypt library from the application.properties file
         @Value("${oci.queue.queueId}")
         private String queueId;
         @Value("${oci.queue.endPoint}")
         private String endPoint;
         @Value("${oci.queue.region}")   
         private String region;
         @Value("${spring.datasource.password}")
         private String datasourcePassword;
      
         //The @Autowired loads JDBC template in SoapObjectRepository.
         @Autowired
         private SoapObjectRepository soapObjectRepository = new SoapObjectRepository();
         //Create a new instance of the JsonBuilder class
         JsonBuilder jsonBuilder = new JsonBuilder();
      
      
         //The namespace URI
         private static final String NAMESPACE_URI = "http://tutorial_example.com/ns0";
      
         //The handleMessagesRequest method is annotated with @PayloadRoot, which means that it is invoked when a request with the specified namespace URI and local part is received.
         @PayloadRoot(namespace = NAMESPACE_URI, localPart = "messages")
         //The @ResponsePayload annotation makes Spring WS map the returned value to the response payload.
         @ResponsePayload
         //The handleMessagesRequest method processes the request and sends the message to the OCI Queue.
         public void handleMessagesRequest(@RequestPayload Messages request) {
            OCIQueue ociQueue = new OCIQueue(queueId, endPoint, region);
      
            //Create an ArrayList to store the users
            ArrayList<User> usersMessageArray = new ArrayList<User>();
      
            //Iterate over the messages, extracting the SOAP Messages and storing in the Java Objects (Car, House, User) 
            for (MessageType message : request.getMessage()) {
      
                  User user = new User();
                  user.setUserName(message.getUsername());
                  user.setUserLastName(message.getUserlastname());
                  user.setID(message.getId());
                  user.setEmail(message.getEmail());
                  user.setDate(message.getDate());
                  user.setAttribute(message.getAttribute());
      
                  //Insert User in Oracle ATP
                  soapObjectRepository.saveUserSOAPMessage(user);
      
                  //Process the attributes Car or House depending of the kind of User
                  processMessage(user, message);
                  //Add the user to the ArrayList
                  usersMessageArray.add(user);
            }
      
      
            //Convert to JSON format
            JSONObject jsonObject = jsonBuilder.buildJsonMessage(usersMessageArray);
      
            //Send the JSON message to OCI Queue
            ociQueue.sendMessages(jsonObject.toString());
      
         }
      
         //The processMessage method processes the message based on the user's attribute.
         private void processMessage(User user, MessageType message) {
            String subject = user.getAttribute();
            switch (subject) {
                  case "CAR":
                     handleCAR(user, message);
                     break;
                  case "HOUSE":
                     handleHouse(user, message);
                     break;
                  default:
                     System.out.println("Unknown subject: " + subject);
            }
         }
      
         //The handleCAR method processes the CAR message.
         private void handleCAR(User user, MessageType message) {
            Car car = new Car();
            car.setBrand(message.getBody().getEnvelope().getBrand());
            car.setColor(message.getBody().getEnvelope().getColor());
            car.setPlate(message.getBody().getEnvelope().getPlate());
      
            user.setCar(car);
            //Insert Car in Oracle ATP
            soapObjectRepository.saveCarSOAPMessage(user.getCar());
      
         }
      
         //The handleHouse method processes the HOUSE message.
         private void handleHouse(User user, MessageType message) {
            House house = new House();
            house.setFloors(message.getBody().getEnvelope().getFloors());
            house.setLocation(message.getBody().getEnvelope().getLocation());
            house.setRooms(message.getBody().getEnvelope().getRooms());
            house.setBathRooms(message.getBody().getEnvelope().getBathrooms());
      
            user.setHouse(house);
      
            //Insert Houses in Oracle ATP
            soapObjectRepository.saveHouseSOAPMessage(user.getHouse());
      
         }
      }
      
  11. Ahora que hemos terminado toda la construcción del proyecto Spring Boot, crearemos Dockerfile en la carpeta del proyecto.

  1. Ejecute el siguiente comando para crear y transferir la imagen del proyecto en el repositorio de Docker local.

    docker build . -t springbootapp:latest
    

    Compilar imagen de Docker

  2. Ejecute el siguiente comando para verificar la imagen en el repositorio de Docker local.

    docker images
    

    Repositorio local de imagen de Docker

  3. Podemos etiquetar la imagen de la aplicación Spring Boot con la ruta de acceso completa del repositorio de OCI Container Registry Classic.

    docker tag springbootapp:latest gru.ocir.io/xxxxxxxxxx/springboot/tutorialapp:latest
    
  4. Ejecute el siguiente comando para verificarlo en el repositorio de Docker local.

    docker images
    

    Etiquetar aplicación de OKE

  5. Ejecute el siguiente comando para transferir la imagen a OCI Container Registry Classic.

    docker push gru.ocir.io/xxxxxxxxxx/springboot/tutorialapp:latest
    

    Insertar aplicación de OKE

  6. Para revisar la aplicación de imagen de OKE en OCI Container Registry Classic, vaya a Developer Services, Containers & Artifacts y haga clic en Container Registry.

    Imagen en OKE Containe Registry

    Una vez que la imagen esté en OCI Container Registry Classic, podemos ir a nuestro entorno de desarrollo y desplegar esta imagen en OKE. Para este tutorial, ejecute el siguiente comando para crear las configuraciones necesarias.

    Nota: Como el espacio de nombres y la cuenta de servicio se han configurado antes, necesita el secreto.

    1. Ejecute el siguiente comando para acceder a la carpeta del proyecto.

      cd tutorial/
      
    2. Ejecute el siguiente comando para crear un secreto para OKE.

      kubectl create secret -n ns-tutorial generic ocir --from-file=.dockerconfigjson=../.docker/config.json --type=kubernetes.io/dockerconfigjson
      

      Crear Oke Secreto

  7. Ya tenemos listo el entorno de OKE, por lo que debe desplegar la imagen de aplicación de OCI Container Registry Classic en OKE.

    Nota: Para desplegar la imagen de la aplicación, es necesario tener un archivo de manifiesto. En este tutorial, el siguiente archivo yaml es el archivo de manifiesto. Se utiliza para desplegar la aplicación y crear el servicio de entrada representado en un equilibrador de carga de OCI que recibe mediante el puerto 80.

    • springboot_application.yaml:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
      name: soap-oci-queue-app
      namespace: ns-tutorial 
      labels:
         app: soap-oci-queue-app
      spec:
      replicas: 6
      selector:
         matchLabels:
            app: soap-oci-queue-app
      template:
         metadata:
            labels:
            app: soap-oci-queue-app
         spec:
            serviceAccountName: tutorialserviceaccount
            automountServiceAccountToken: true      
            containers:
            - name: soap-oci-queue-app
            image: gru.ocir.io/xxxxxxxxxxxx/springboot/tutorialapp:latest
            ports:
            - containerPort: 8080
            imagePullSecrets:
            - name: ocir-docker-config
      ---
      
      apiVersion: v1
      kind: Service
      metadata:
      name: svc-dev-app 
      namespace: ns-tutorial 
      spec:
      selector:
         app: soap-oci-queue-app
      ports:
         - port: 80
            targetPort: 8080
      type: LoadBalancer
      
  8. Ejecute el comando kubectl en la carpeta en la que ha guardado el archivo de manifiesto.

    kubectl apply -f springboot_application.yaml
    

    Ahora, la aplicación se despliega y el servicio de equilibrador de carga de entrada se crea en OKE.

    Aplicar manifiesto en OKE

  9. Para validar el pod y el servicio creados en OKE, ejecute el siguiente comando.

    kubectl get pods -A
    

    OKE PODS

    kubectl get svc -A
    

    Servicios de OKE

    Nota: Descargue el proyecto de aplicación Java basado en Oracle GraalVM de Spring Boot desde aquí: tutorial.zip.

Tarea 7: Prueba de la aplicación Oracle Graal VM de Spring Boot con JMeter

Para obtener más información sobre la instalación de JMeter, consulte Introducción a JMeter.

Una vez instalado y configurado JMeter, puede enviar solicitudes SOAP de HTTP POST. Por ejemplo, defina el número de threads en 2 para representar 2 usuarios o aplicaciones simultáneos y defina Recuento de Bucle en 3000, lo que significa que cada usuario o aplicación enviará 3000 solicitudes, para un total de 6000 solicitudes de SOAP.

Mensajes de SOAP

En JMeter, defina nuestra IP de OCI Load Balancer, la ruta configurada en el proyecto Spring Boot y el XML de SOAP en el cuerpo.

Solicitud SOAP HTTP

Ejecute JMeter con 6000 transacciones SOAP y verifíquelo.

Nota: Al simular la mensajería de SOAP de las aplicaciones cliente, para cada solicitud HTTP de SOAP la información es la misma que se ve en el archivo XML de SOAP mostrado anteriormente, y no cambia, pero en un entorno de cliente real la información seguramente variará.

Ejecute la siguiente sentencia:

  1. Para ver los datos totales almacenados en ATP.

    Oracle ATP

  2. Para ver los detalles de los datos almacenados en cada tabla en ATP.

    • CARS:

      COCHES

    • CASAS:

      CASAS

    • USERS:

      USERS

  3. Para ver el total de solicitudes de OCI Queue almacenadas en OCI Queue.

    Total de solicitudes de OCI Queue

  4. Para ver los detalles del mensaje en OCI Queue en formato JSON.

    Detalle de mensajes de OCI Queue

Agradecimientos

Más recursos de aprendizaje

Explore otros laboratorios en docs.oracle.com/learn o acceda a más contenido de formación gratuita en el canal YouTube de Oracle Learning. Además, visite education.oracle.com/learning-explorer para convertirse en un explorador de Oracle Learning.

Para obtener documentación sobre el producto, visite Oracle Help Center.