Observação:

Criar um Aplicativo Java baseado no Oracle GraalVM usando Spring Boot no OKE para Armazenar Mensagens SOAP no ATP e Enviar para o OCI Queue

Introdução

Muitos de nossos clientes confiam nas mensagens tradicionais do Simple Object Access Protocol (SOAP) para permitir a comunicação entre seus aplicativos. Eles geralmente precisam armazenar dados transacionais, garantir o desacoplamento do serviço, obter balanceamento de carga de solicitações recebidas e permitir a comunicação assíncrona dessas mensagens.

Neste tutorial, veremos como podemos criar um aplicativo Java baseado no Oracle GraalVM usando o Spring Boot implantado na infraestrutura do Oracle Cloud Infrastructure Kubernetes Engine (OKE) que será usado como integrador transacional com os diferentes serviços da Oracle Cloud Infrastructure (OCI), como Oracle Autonomous Transaction Processing (ATP) e OCI Queue. Essa configuração permite que os sistemas interajam sem conexões diretas, facilitando a comunicação entre aplicativos com diferentes velocidades de processamento. Além disso, uma vez que as informações são armazenadas no banco de dados, elas podem ser consultadas ou analisadas.

Utilizaremos as seguintes tecnologias:

Oracle Cloud Infrastructure Services (OCI): A OCI é uma plataforma de nuvem segura e de alto desempenho que oferece mais de 150 serviços de nuvem. Ele foi projetado para escalabilidade, segurança e desempenho.

Tecnologia Oracle:

Outras tecnologias:

Arquitetura de Alto Nível do OCI:

Arquitetura do OCI

Arquitetura do Caso de Uso

Observação:

Objetivos

Pré-requisitos

Tarefa 1: Provisionar e Configurar o Cluster do OKE

Nesta tarefa, provisionaremos a plataforma Kubernetes, na qual o aplicativo oferecerá suporte a todas as mensagens de alta transacionalidade SOAP para armazenar no ATP e enviar cada uma para o OCI Queue em tempo real.

  1. Faça log-in na Console do OCI, navegue até Developer Services, Clusters do Kubernetes (OKE) e selecione Compartimento de sua preferência.

    Há duas maneiras de criar um cluster do OKE:

    • Criação Rápida.
    • Criação Personalizada.
  2. Selecione Criação rápida, pois esse método é mais fácil, rápido e implanta automaticamente todos os elementos exigidos pelo OKE para sua operação, como:

    • VCN (Rede Virtual na Nuvem).
    • Gateway de Internet.
    • Gateway NAT (Network Address Translation).
    • Gateway de serviço.
    • Cluster do Kubernetes.
    • Nó(s) de trabalho do Kubernetes e pool de nós.

    Observação: Para os ambientes corporativos, em que os clientes já têm serviços, rede e infraestrutura, é importante personalizar a implantação do OKE para estar em conformidade, alinhada com a arquitetura do cliente, recursos e seguindo as melhores práticas.

    Criação Rápida

  3. Clique em Criar cluster e insira as seguintes informações.

    • Nome: Informe o nome do cluster do OKE.
    • Compartimento: Selecione o compartimento criado para este projeto.
    • Versão do Kubernetes: Selecione a versão mais recente do Kubernetes disponível.
    • Ponto final da API do Kubernetes: Neste tutorial, selecione Ponto final público, mas você também pode selecionar Ponto final privado.
    • Tipo de Nó: Selecione nós Gerenciados.
    • Nós de trabalho do Kubernetes: Selecione Trabalhadores privados.
    • Shape and image: Selecione VM.Standard.E5. Flex, personalize o número de OCPUs (2) e memória (16 GB) e conserve a imagem padrão do Oracle Linux 8.
    • Contagem de Nós: Informe 2 nós de trabalho a serem implantados com o pool de nós do OKE.

    Criar Cluster do OKE

    Verifique se o cluster do OKE está funcionando.

    OKE em Execução

Tarefa 2: Provisionar, Configurar e Acessar o OCI Container Registry Classic

Precisamos gerenciar as imagens do projeto em um repositório. Para isso, provisionaremos o OCI Container Registry Classic. Assim que as imagens forem armazenadas no OCI Container Registry Classic, poderemos implantá-las no OKE.

  1. Vá para a Console do OCI, acesse Developer Services, Containers & Artifacts, Container Registry e clique em Create Repository.

  2. Especifique as seguintes informações e clique em Criar.

    • Criar no Compartimento: Selecione o compartimento criado para este projeto.
    • Acesso: Selecione Público.
    • Nome do repositório: Digite springboot/tutorialapp.

    Criar Repositório

  3. Depois que o repositório for criado, no host do administrador da Oracle, acesse-o usando o comando a seguir.

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

    Autenticação do Oracle Registry

    OK

Tarefa 3: Provisionar e Configurar o Oracle Autonomous Transaction Processing (ATP) Serverless Database

No banco de dados ATP, armazenaremos os dados de cada mensagem SOAP recebida por transação, aproximadamente cada uma estará na ordem de milissegundos, atendendo a inserções paralelas e sequenciais.

  1. Vá para a Console do OCI, navegue até o Oracle Database e clique em Autonomous Transaction Processing.

  2. Clique em Create Autonomous Database e forneça as informações a seguir.

    • Selecionar o Compartimento: Selecione o compartimento criado para este projeto.
    • Nome para Exibição: Informe o nome para exibição.
    • Exibir Nome do Banco de Dados: Digite o nome do banco de dados.
    • Choose a load type: Selecione Transaction Processing.
    • Selecione um tipo de implantação: Selecione Sem Servidor.
    • Configure o banco de dados:
      • Desenvolvedor: Desmarque-o.
      • Choose database version: Selecione 23ai.
      • Contagem de ECPUs: Digite 2.
      • Dimensionamento automático do Compute: Selecione-o.
      • Armazenamento: Digite 1024 GB.
    • Período de retenção de backup automático em dias: Deixe a opção padrão 60 dias.
    • Criar credenciais de administrador:
      • Nome do Usuário: é ADMIN por padrão e não pode ser editado.
      • Senha: Informe sua senha preferencial.
      • Confirmar senha: Digite a senha novamente.
    • Escolher acesso à rede: Selecione Somente acesso de ponto final privado e escolha a VCN e a sub-rede criadas para esse projeto. Essa definição restringe apenas as conexões com a rede privada (VCN) especificada. No entanto, você pode escolher outras opções, isso depende das necessidades da empresa.

    Criar Banco de Dados Oracle ATP

    Criar Banco de Dados Oracle ATP

    Criar Banco de Dados Oracle ATP

    Verifique se o banco de dados ATP está em execução.

    ATP em execução

Tarefa 4: Conectar e Criar Tabelas de Projeto no Oracle Autonomous Transaction Processing (ATP)

Agora, precisamos configurar, conectar e criar as tabelas de projeto no banco de dados ATP que foi gerado na Tarefa 3.

  1. Vá para a Console do OCI, navegue até Oracle Database, Autonomous Transaction Processing e clique em Conexão de Banco de Dados. Selecione Autenticação TLS, TLS e clique em Fazer Download da Wallet.

    Conexão do Banco de Dados

  2. Descompacte o arquivo .zip da wallet e, em tnsnames.ora, você pode obter o URL da origem de dados para obter a conexão com esse banco de dados. Salve este URL da origem de dados.

    Por exemplo:

    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. O acesso ao banco de dados agora é necessário. Quando o ATP foi provisionado, o acesso ao ORDS (Oracle REST Data Services) foi ativado. Para obter mais informações, consulte Oracle REST Data Services.

    Vá para a página Detalhes do Autonomous Database e clique em Ações do banco de dados. Observe que ele só pode ser acessado de uma instância de computação em execução na mesma rede virtual na nuvem (VCN).

    Database Actions

  4. Cole o URL no browser e acesse o ORDS usando o usuário e a senha informados no banco de dados ATP anteriormente e acesse o módulo Oracle SQL Developer Web.

    ORDS

  5. Use as consultas a seguir para criar as tabelas USERS, CARS e HOUSES relacionadas às mensagens SOAP que receberemos.

    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
    );
    

    Tabelas criadas no banco de dados

Tarefa 5: Provisionar e Configurar o OCI Queue

No OCI Queue, armazenaremos mensagens altamente transacionais por meio da API HTTP RESTful por um período específico. Os consumidores podem ler e apagar as mensagens imediatamente ou à sua conveniência, garantindo a dissociação e evitando a perda de dados.

  1. Vá para a Console do OCI, acesse Developer Services, Application Integration e clique em Queues.

  2. Clique em Criar fila, especifique as seguintes informações e clique em Criar fila.

    • Nome: Informe o nome adequado para sua fila.
    • Compartimento: Selecione seu compartimento de trabalho.
    • Definições da fila: Neste tutorial, selecionaremos Configuração padrão, mas, se preferir, você poderá personalizar várias opções de acordo com as necessidades de negócios, como: Timeout de visibilidade, Período máximo de retenção, Consumo máximo do canal e definições de Fila de cartas mortas.
    • Configurar definições de criptografia: Selecione Chave gerenciada pela Oracle, mas a Chave gerenciada pelo cliente também é uma opção.

    Criar Fila

    Verifique se o OCI Queue está em execução.

    OCI Queue em Execução

Tarefa 6: Criar um aplicativo Java baseado no Oracle GraalVM com o Spring Boot e Implantá-lo no OKE

Agora, desenvolveremos e implantaremos um aplicativo Java baseado no Oracle GraalVM no Spring Boot que executará as seguintes tarefas:

Observação: Antes de iniciar, é importante criar um host de administração e um ambiente de desenvolvimento, conforme mostrado nas seções Pré-requisitos - Host de Administração e Pré-requisitos - Ambiente de Desenvolvimento.

Depois que o host do administrador e o ambiente de desenvolvimento estiverem configurados e prontos, você poderá começar a desenvolver seu projeto Spring Boot.

  1. Vá para Spring initializr e crie o primeiro projeto que nos dará a estrutura de pastas e os arquivos base de um projeto Spring Boot para modificá-lo posteriormente de acordo com nossos requisitos. Especifique as informações a seguir e clique em Gerar. Isso fará download automaticamente do projeto Spring Boot, salvará e descompactará-lo em seu host de desenvolvimento.

    • Projeto: Selecione Maven.
    • Idioma: Selecione Java.
    • Spring boot: Selecione 3.3.6.
    • Metadados do Projeto:
      • Grupo: Digite com.tutorial_springboot.
      • Artefato: Digite o tutorial.
      • Nome: Digite o tutorial.
      • Descrição: Digite Aplicativo de Inicialização Spring (leia SOAP, transforme para JSON, insira ATP e Coloque no OCI Queue).
    • Embalagem: Selecione Jar.
    • Java: Selecione 17.
    • Dependências: Selecione Oracle Driver, Spring Web Services e Spring Web.

    Observação: Podemos adicionar algumas dependências no projeto e, posteriormente, adicionar mais, diretamente no arquivo pom.xml, de acordo com nossas necessidades.

    Projeto Springboot

  2. Agora temos o projeto de estrutura de inicialização de primavera.

    Estrutura Projeto de inicialização Spring

    Revise o arquivo pom.xml, começaremos a trabalhar nele.

    Arquivo POM original

    Atualize o arquivo pom.xml, de acordo com o escopo proposto neste tutorial.

    • Adicione a versão oci sdk e as dependências a seguir.

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

      A aplicação precisará se autenticar com a OCI, conectar e gerenciar serviços da OCI, como o OCI Queue.

    • Nosso arquivo pom.xml já tem a dependência spring-boot-starter-web-services e temos que adicionar a dependência wsdl4j. O principal objetivo é obter os dados recebidos de mensagens SOAP e colocá-los em objetos Java, criando serviços web de primavera manipulando cargas úteis XML, visa facilitar o desenvolvimento do serviço SOAP de contrato em primeiro lugar. Também permite configurar porta, URI e definir esquema XML carregado do arquivo XSD (XML Schema Definition).

    • Adicione dependência JSON. Essa biblioteca será usada para gerar o formato JSON com os dados extraídos da mensagem SOAP.

    • Adicione o plug-in spring-boot-maven-plugin na seção Build. Este plug-in nos permitirá gerar o arquivo do projeto Spring Boot executável jar.

    • Adicione o plug-in jaxb2-maven-plugin na seção Build. Este plug-in usará a API Java para vinculação XML (JAXB), para gerar classes Java de esquemas XML e, dessa forma, podemos transmitir os dados da mensagem SOAP para objetos de classe Java criados por nós.

      Nesta seção de plug-in, é importante colocar a configuração que indicará o caminho, onde o arquivo XSD está incluído em nosso projeto Spring Boot.

      <configuration>
         <sources>
         <source>${project.basedir}/src/main/resources/messages.xsd<source>
         </sources>
      </configuration>
      
    • Adicione a dependência jasypt-spring-boot-starter na seção Dependências e o plug-in jasypt-maven-plugin na seção Build que nos permitirá criptografar parâmetros confidenciais no arquivo application.properties, garantindo o uso seguro em nosso aplicativo.

    Verifique as dependências a seguir adicionadas no arquivo pom.xml.

    Arquivo POM modificado

    Arquivo POM modificado

  3. Faça download das bibliotecas e execute os comandos a seguir.

    1. Em seu ambiente de desenvolvimento, execute o comando a seguir para acessar seu projeto.

      cd tutorial
      

      Pasta do projeto de inicialização Spring

    2. Limpe o projeto e remova todos os arquivos gerados pelo build anterior.

      mvn clean
      

      Limpeza do Maven

    3. Expurgar (excluir e, opcionalmente, resolver novamente) artefatos do repositório maven local.

      mvn dependency:purge-local-repository
      

    Dependências de Expurgação do Maven

  4. Já temos as dependências e o arquivo pom.xml configurados em nosso projeto, vamos continuar a verificar o arquivo XML SOAP, pois ele representa a solicitação do lado do cliente, e o arquivo XSD, que interpreta a solicitação do nosso lado do projeto Spring Boot.

    1. Este arquivo XML SOAP tem duas mensagens, com informações pessoais e outros tipos de atributos de dois clientes diferentes que enviaremos por solicitação, conforme mostrado na imagem a seguir.

      Arquivo Soap

    2. Agora, no nosso projeto Spring Boot, um esquema XML é necessário para definir um domínio de serviço Web que o Spring Web Service exporta automaticamente como WSDL, a imagem a seguir mostra o arquivo messages.xsd definido para este tutorial.

      messages.xsd:

      Arquivo XSD

    3. Salve o arquivo messages.xsd na pasta de recursos do seu projeto Spring Boot.

      Arquivo XSD na pasta

  5. Crie e instale arquivos de projeto em um arquivo jar. Execute o comando a seguir e certifique-se de estar na pasta do projeto Spring Boot.

    mvn install
    

    Observação: Depois que o comando maven install é executado, a pasta de destino é gerada automaticamente e, da mesma forma, dentro dela, as classes Java de acordo com o arquivo XSD criado anteriormente e o arquivo .jar executável do projeto.

    Pasta de Destino

  6. Agora, podemos adicionar as classes Java necessárias ao nosso projeto Spring Boot.

    WebServiceConfig.java Class: Esta classe Java foi desenvolvida para criar web service SOAP:

    • Configura o servlet para tratar solicitações SOAP.
    • Gera uma definição WSDL com base em um esquema XML.
    • Define o ponto final de acesso do web service SOAP.
    • Usa o arquivo de esquema messages.xsd do 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
       }
    }
    

    Observação: Se quiser testar o serviço Web, você poderá executar o projeto Spring Boot na mesma área de trabalho do ambiente de desenvolvimento local e enviar a solicitação HTTP usando curl, da seguinte forma:

    mvn spring-boot:run
    

    Executar projeto de inicialização Spring

    Executar projeto de inicialização Spring

    Quando o projeto estiver em execução e o serviço Web estiver ativo, execute uma solicitação HTTP SOAP local usando curl, da seguinte forma:

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

    E você receberá uma resposta do serviço web exposto em nosso projeto Spring Boot.

    Web Service SOAP

  7. Crie uma pasta chamada model e nessa pasta adicionaremos as seguintes classes Java.

    Pasta de Modelo

    Observação: Essas classes Java Car, House e User recuperarão as informações com base nos dados de cada mensagem SOAP extraída da solicitação SOAP HTTP.

    • Car.java class: Essa classe Java representa um objeto Carro com seus atributos vinculados a cada usuário.

      ```
      //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: Essa classe Java representa um objeto House com seus atributos vinculados a cada usuário.

        //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: Essa classe Java representa um objeto Usuário com seus atributos, contendo objetos Carro e Casa.

        //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. Agora, vamos configurar os parâmetros necessários em nosso projeto Spring Boot para armazenar os dados obtidos no banco de dados OCI ATP. Na pasta resources, você deve encontrar o arquivo application.properties usado para adicionar parâmetros exigidos pelo aplicativo. Ele é gerado automaticamente e carregado pelo Spring Boot quando o aplicativo é iniciado.

    Observação: É realmente importante gerenciar métodos de criptografia e segurança que garantam que informações confidenciais, como senhas ou dados relevantes, não possam ser extraídas ou visualizadas por hackers. Neste tutorial, usamos a biblioteca jasypt configurada no arquivo pom.xml. Para obter mais informações, consulte Como criptografar senhas em um projeto Spring Boot usando o Jasypt. Além disso, em nossas classes Java no Spring Boot, está documentado onde adicionar as anotações e o código-fonte relacionados a essa biblioteca para decriptografar os parâmetros application.properties.

    Adicione os parâmetros apropriados exigidos pelo banco de dados ATP no arquivo application.properties, conforme mostrado na imagem a seguir.

    Arquivo de propriedades do aplicativo

    Crie a classe Java Spring Boot para armazenar cada mensagem no banco de dados, ela estará na pasta database, conforme mostrado na imagem a seguir.

    Pasta do Banco de Dados

    • SoapObjectRepository.java: Esta classe Java Spring Boot permite inserir em formato transacional em tempo real, cada mensagem no ATP, usando o driver 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());
         }
      
      
      }
      

      Agora, adicione o código de software JSON, primeiro criando a pasta json_message e sua classe Java Spring Boot, conforme mostrado na imagem a seguir.

      Pasta Json

    • JsonBuilder.java: Esta classe Java Spring Boot converte do formato XML SOAP para o 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. Agora, podemos enviar as mensagens no formato JSON para o OCI Queue. Crie a pasta oci_queue e sua classe Java Spring Boot, conforme mostrado na imagem a seguir.

    Pasta da fila

    Observação: Na classe OCIQueue.java, precisaremos definir o acesso do OKE ao OCI Queue. Para este tutorial, usaremos o Acesso a Cargas de Trabalho para conceder acesso aos recursos do OCI, sem precisar tratar informações confidenciais, como usuário, senhas, OCIDs associados à sua tenancy. Para obter mais informações, consulte Concedendo Acesso de Cargas de Trabalho aos Recursos do OCI.

    Antes de começar a desenvolver a classe OCIQueue.java, configuraremos o acesso às cargas de trabalho em nossa tenancy. Primeiro, precisamos criar um namespace para associar ao nosso aplicativo Java baseado no Oracle GraalVM. Verifique se você está no host do administrador.

    kubectl create ns-tutorial
    

    Em seguida, crie uma conta de serviço do Kubernetes para o aplicativo.

    kubectl create serviceaccount tutorialserviceaccount --namespace ns-tutorial
    

    Agora, defina uma política do OCI IAM para permitir que a carga de trabalho acesse os recursos necessários do OCI. Neste tutorial, OCI Queue.

    Vá para a Console do OCI, navegue até Identidade e Segurança, Políticas e clique em Criar política. Especifique as seguintes informações e clique em Criar.

    • Nome: Informe o nome da política preferencial.
    • Descrição: Digite Acesso do oke à fila do oci.
    • Construtor de Políticas:

      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 acesso a cargas de trabalho

    Depois de configurar a política de acesso à carga de trabalho, o namespace e a conta de serviço, poderemos continuar.

    No arquivo application.properties, adicione os parâmetros de fila necessários para conectar e gerenciar a Fila do OCI específica criada na Tarefa 5.

    Definições de OCIID

    • OCIQueue.java: Esta classe Java Spring Boot permite acessar e colocar as mensagens no 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. Assim que você tiver as classes Java Spring Boot para banco de dados, JSON e OCI Queue, poderemos prosseguir com a classe MessagesEndpoint.java.

    Para isso, criaremos uma pasta chamada endpoint e sua classe Spring Boot Java.

    Pasta do Ponto Final

    Observação: Em MessagesEndpoint.java, precisamos importar algumas classes geradas automaticamente. Para fazer isso, adicione a seguinte origem na seção Configuração do arquivo pom.xml:

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

    O arquivo pom.xml deve ser semelhante.

    Caminho de Origens Geradas

    • MessagesEndpoint.java: A finalidade desta classe Java Spring Boot é extrair a solicitação HTTP SOAP e mapear seus valores para os objetos Java Usuário, Carro e Casa de cada mensagem. Em seguida, ele armazena os dados extraídos em um banco de dados ATP para cada transação XML SOAP, converte os dados do formato XML para JSON e coloca as mensagens em uma Fila do OCI. Essas mensagens podem ser recuperadas e excluídas posteriormente da fila pelos 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. Agora que terminamos toda a construção do projeto Spring Boot, criaremos o Dockerfile na pasta do projeto.

  1. Execute o comando a seguir para criar e enviar a imagem do projeto no repositório local do Docker.

    docker build . -t springbootapp:latest
    

    Criar imagem do Docker

  2. Execute o comando a seguir para verificar a imagem no repositório local do Docker.

    docker images
    

    Repositório local da imagem do Docker

  3. Podemos marcar com tag a imagem do aplicativo Spring Boot com o caminho completo do seu repositório do OCI Container Registry Classic.

    docker tag springbootapp:latest gru.ocir.io/xxxxxxxxxx/springboot/tutorialapp:latest
    
  4. Execute o comando a seguir para verificar no repositório local do Docker.

    docker images
    

    Aplicativo OKE de Tag

  5. Execute o comando a seguir para enviar a imagem ao OCI Container Registry Classic.

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

    Enviar Aplicativo do OKE

  6. Para revisar o aplicativo de imagem do OKE no OCI Container Registry Classic, vá para Developer Services, Containers & Artifacts e clique em Container Registry.

    Imagem no Registro de Containe do OKE

    Quando a imagem estiver no OCI Container Registry Classic, poderemos ir para nosso ambiente de desenvolvimento e implantar essa imagem no OKE. Para este tutorial, execute o comando a seguir para criar as configurações necessárias.

    Observação: Como o namespace e a conta de serviço foram configurados antes, ele requer o segredo.

    1. Execute o comando a seguir para acessar a pasta do projeto.

      cd tutorial/
      
    2. Execute o comando a seguir para criar um segredo para o OKE.

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

      Criar secretar oke

  7. Já temos o ambiente do OKE pronto; portanto, implante a imagem do aplicativo do OCI Container Registry Classic para o OKE.

    Observação: Para implantar a imagem do aplicativo, é necessário ter um arquivo de manifesto. Neste tutorial, o arquivo yaml a seguir é o arquivo de manifesto, ele é usado para implantar o aplicativo e criar o serviço de entrada representado em um Balanceador de Carga do OCI que está fazendo listening usando a porta 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. Execute o comando kubectl na pasta em que salvou o arquivo de manifesto.

    kubectl apply -f springboot_application.yaml
    

    Agora, o aplicativo é implantado e o serviço do balanceador de carga de entrada é criado no OKE.

    Aplicar Manifesto no OKE

  9. Para validar o pod e o serviço criados no OKE, execute o comando a seguir.

    kubectl get pods -A
    

    OKE PODS

    kubectl get svc -A
    

    Serviços do OKE

    Observação: Faça download do projeto de aplicativo Java baseado no Spring Boot do Oracle GraalVM aqui: tutorial.zip.

Tarefa 7: Testar o Aplicativo Oracle Graal VM Spring Boot usando JMeter

Para obter mais informações sobre a instalação do JMeter, consulte Conceitos Básicos do JMeter.

Depois que JMeter for instalado e configurado, você poderá enviar solicitações HTTP POST SOAP. Por exemplo, defina o número de threads como 2 para representar 2 usuários ou aplicativos simultâneos e defina a Contagem de Loops como 3000, o que significa que cada usuário ou aplicativo enviará 3000 solicitações, para um total de 6000 solicitações SOAP.

Mensagens SOAP

Em JMeter, defina o IP do Balanceador de Carga do OCI, o caminho configurado no projeto Spring Boot e o XML SOAP no corpo.

Solicitação SOAP HTTP

Execute JMeter com 6000 transações SOAP e verifique.

Observação: Como estamos simulando as mensagens SOAP de aplicativos cliente, para cada solicitação HTTP SOAP, as informações são as mesmas que são vistas no arquivo XML SOAP mostrado acima e não mudam, mas em um ambiente de cliente real, as informações certamente variarão.

Execute a seguinte instrução:

  1. Para ver o total de dados armazenados no ATP.

    Oracle ATP

  2. Para ver detalhes dos dados armazenados em cada tabela no ATP.

    • CARROS:

      CARROS

    • CASAS:

      CASAS

    • USERS:

      USERS

  3. Para ver o total de solicitações do OCI Queue armazenadas no OCI Queue.

    Total de solicitações do OCI Queue

  4. Para ver detalhes da mensagem no OCI Queue no formato JSON.

    Detalhes das mensagens do OCI Queue

Confirmações

Mais Recursos de Aprendizagem

Explore outros laboratórios em docs.oracle.com/learn ou acesse mais conteúdo de aprendizado gratuito no canal Oracle Learning YouTube. Além disso, visite education.oracle.com/learning-explorer para se tornar um Oracle Learning Explorer.

Para obter a documentação do produto, visite o Oracle Help Center.