Fresche Solutions

Java et l’i (deuxième partie) : Exécuter l'application Spring Boot sur IBM i

juillet 3, 2019
Claudio Lawira

1. Introduction

Voici la deuxième partie d’une série d’articles techniques sur l’intégration de Java et d’IBM i, intitulée « Java et l’i ». Nous nous basons sur la première partie, où il s’agissait de connecter Spring Boot à une base de données IBM Db2, pour desormais exécuter l’application REST Spring Boot sur un serveur IBM i.

Sur votre PC, vous nécessiterez cet outil additionnel :

• Soit HTTPie (https://httpie.org/) ou Postman (https://www.getpostman.com/downloads/). Ils peuvent tous deux être utilisés pour effectuer des demandes REST au format JSON. J'ai une préférence pour HTTPie car il s'agit d'une ligne de commande facile à utiliser. Pour ceux habitués à wget ou curl, l'utilisation de HTTPie est intuitive et naturelle. De plus, sa coloration syntaxique et sa mise en forme JSON sont agréables à regarder.

2. L'application Spring Boot

L’application de la partie 1 pourrait être JAR fournie avec Maven et exécutée telle quelle sur IBM i avec «java -jar» dans Qshell (https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#getting-started-introducing-spring-boot). La construction Maven par défaut génère un artefact JAR exécutable sur Java contenant un serveur Servlet intégré (Tomcat).

Néanmoins, une application Spring Boot est généralement déployée dans un dossier de départ organisé comme suit. Prenons l’application boottest dans Qshell :

/home/boottest
    /config
        application.yml
    /lib
        gs-accessing-data-rest-0.1.0.jar
    /logs
        boottest.log
        boottest.log.2019-06-19.0.gz
        boottest.log.2019-06-20.0.gz
        boottest.log.2019-06-21.0.gz
    start.sh 

 

• Le dossier de configuration est l'emplacement du fichier de configuration application.yml : (https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-application-property-files)

• Le répertoire lib contient l'artefact JAR gs-accessing-data-rest-0.1.0.jar construit par Maven.

• Le répertoire des logs contient le journal de l'application (boottest.log) et son archive évolutive.

• Le répertoire de script start.sh contient le script permettant de démarrer l'application boottest.

3. Changement des paramètres de configuration dans l’EDI

Afin d’avoir une expérience plus agréable, axée sur les caractéristiques de production, nous ajouterons le Spring Boot Actuator et quelques nouveaux paramètres de configuration d’application.

3.1. Changement du fichier pom.xml de Maven

Nous ajouterons le Spring Boot Actuator en tant que dépendance à l’application boottest. Voyez https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production-ready. Cette dépendance sera ajouté à la liste de dépendances :

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> 

 

Le fichier POM restant demeure le même.

3.2. Changement du répertoire de configuration de l’application

Ouvrez le fichier /src/main/resources/application.yml. Remplacez tout son contenu par le suivant :

server:
  port: 8880
  servlet.context-path: /boottest

spring:
  datasource:
    url: jdbc:as400://[ibm_i_ip_address];naming=system;libraries=BOOTTEST;socket timeout=30000;thread used=false;transaction isolation=read committed;translate binary=true;date format=iso;prompt=false
    username: [db2_for_i_database_username]
    driver-class-name: com.ibm.as400.access.AS400JDBCDriver
    hikari.connection-test-query: values 1
  jpa:
    open-in-view: true
    database-platform: org.hibernate.dialect.DB2400Dialect
    hibernate.ddl-auto: none

management:
  endpoints:
    web.exposure.include: "*"
    jmx.exposure.include: "*"
  endpoint:
    health:
      show-details: always

logging:
  level:
    root: info
    org.springframework.web.servlet.DispatcherServlet: debug
    org.hibernate.SQL: debug

 

La valeur complète de l'URL de la source de données doit figurer sur une seule ligne. Le texte de nos exemples peut être affiché sur plusieurs lignes à des fins de formatage.

Vous remarquerez que le mot de passe de la base de données IBM Db2 pour l’i n’est pas définit dans le fichier de configuration. La valeur secrète doit être cachée du code source.

Dans la première partie, nous avons démontré comment le définir dans l'EDI. Nous verrons comment nous pourrons le définir plus tard sur IBM i.

La valeur du port du serveur, 8880, est le port HTTP de l'application boottest pour les demandes et les connexions HTTP. Vérifiez que le port 8880 n'est pas déjà utilisé par un autre service sur votre serveur IBM i.

La configuration des nœuds finaux de gestion concerne le Spring Boot Actuator.

Nous avons également ajouté une configuration de journalisation qui affichera toutes les requêtes et réponses HTTP entrantes. Les demandes de données SQL seront également affichées dans le journal.

3.3. Exécution des ApplicationTests dans l’EDI

Avec la même configuration d'ApplicationTests (partie 1), nous pouvons exécuter les ApplicationTests et obtenir les mêmes résultats verts que la partie 1. Les tests continuent de s'exécuter correctement.

4. Exécution de l'application depuis l'EDI

Au lieu des ApplicationTests, nous exécuterons l'application boottest localement, à partir de l'EDI, avant de l'exécuter sur IBM i. Dans la sous-fenêtre Projet, cliquez avec le bouton droit sur la classe Application et choisissez Exécuter ‘Application.main()’. L'application boottest semble fonctionner, mais elle ne peut pas se connecter à la base de données. L'erreur est « Caused by: com.ibm.as400.access.AS400SecurityException: Password is not set. »

Nous devons configurer la variable d'environnement SPRING_DATASOURCE_PASSWORD pour l'application dans l'EDI. Dans IntelliJ, allez à : Run menu > Edit Configurations… > Application et définissez le mot de passe de la manière suivante :

Lorsque vous exécuterez l'application principale, vous obtiendrez ceci dans la console :

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-06-25 14:26:18.678  INFO 18502 --- [           main] hello.Application : Starting Application on mars with PID 18502 

. . .


2019-06-25 14:26:24.173  INFO 18502 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 15 endpoint(s) beneath base path '/actuator'
2019-06-25 14:26:24.249  INFO 18502 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8880 (http) with context path '/boottest'
2019-06-25 14:26:24.251  INFO 18502 --- [           main] hello.Application                        : Started Application in 5.963 seconds (JVM running for 6.313)

 

Vous pouvez maintenant soumettre des requêtes HTTP à l'application boottest, car le serveur Web Tomcat est prêt et démarré. En utilisant l'outil HTTPie, nous pouvons soumettre des requêtes HTTP à partir de la ligne de commande. Par exemple :

Pour la ligne de commande :

http localhost:8880/boottest/people/search/findByLastName?name=Baggins

 

Nous pourrions voir :

HTTP/1.1 200 
Content-Type: application/hal+json;charset=UTF-8
Date: Tue, 25 Jun 2019 18:34:05 GMT
Transfer-Encoding: chunked

{
    "_embedded": {
        "people": [
            {
                "_links": {
                    "person": {
                        "href": "http://localhost:8880/boottest/people/201"
                    },
                    "self": {
                        "href": "http://localhost:8880/boottest/people/201"
                    }
                },
                "firstName": "Bilbo Jr.",
                "lastName": "Baggins"
           }
        ]
    },
    "_links": {
        "self": {
            "href": 
"http://localhost:8880/boottest/people/search/findByLastName?name=Baggins"
        }
    }
}

 

5. Déploiement de l'application boottest sur IBM i

L'application boottest s'exécute localement. Nous sommes maintenant prêts à déployer sur IBM i. Il existe plusieurs manières de transférer des fichiers de votre PC vers IBM i : avec le système de fichiers intégré à partir des solutions client IBM i Access, FTP (si le serveur FTP est actif), SSH et SCP (si le serveur SSH est actif), etc. Je préfère utiliser un script qui automatise le déploiement à l'aide de SSH et de SCP.

Créons un dossier ibm_i à la racine du projet contenant les fichiers du déploiement IBM i. Là, nous aurions trois fichiers pour le moment :

• application.yml

• deploy.sh

• start.sh

5.1. /ibm_i/application.yml

Ce fichier application.yml contient des paramètres qui remplacent les paramètres /src/main/resources/application.yml. Voici un exemple du fichier /ibm_i/application.yml :

spring:
  main:
    banner-mode: "off"
  output:
    ansi:
      enabled: never

logging:
  file: logs/boottest.log

 

Par défaut, la bannière Spring Boot est activée et le journal de la console contient des caractères de couleur ANSI qui ne sont pas pris en charge sur IBM i.

La journalisation est envoyée par défaut à la console. En spécifiant un fichier, Spring Boot enverra la journalisation à ce fichier. Et il gérera automatiquement l'archive de défilement du fichier de journalisation.

Ce fichier sera déployé dans le dossier /home/boottest/config sous IBM i.

5.2. /ibm_i/start.sh

Voici un script Qshell qui démarre dans l’application Java boottest :

cd /home/boottest && /QOpenSys/QIBM/ProdData/JavaVM/jdk80/64bit/jre/bin/java -Xquickstart -Xshareclasses:name=boottest -Xscmx128m -jar lib/gs-accessing-data-rest-0.1.0.jar

 

La commande entière doit être contenue dans une ligne. Le texte final peut être affiché sur plusieurs lignes à des fins de formatage.

Ce fichier sera déployé dans le dossier /home/boottest folder sur IBM i.

Assurez-vous de disposer du dernier IBM JDK 8 sur votre serveur IBM i. À ce jour, voici un exemple de cette version dans Qshell :

> /QOpenSys/QIBM/ProdData/JavaVM/jdk80/64bit/jre/bin/java -version                                                    
   java version "1.8.0_201"                                                                                            
   Java(TM) SE Runtime Environment (build 8.0.5.30 - pap6480sr5fp30-20190207_01(SR5 FP30))                             
   IBM J9 VM (build 2.9, JRE 1.8.0 OS/400 ppc64-64-Bit Compressed References 20190124_408237 (JIT enabled, AOT enabled)
   OpenJ9   - 9c77d86                                                                                                  
   OMR      - dad8ba7                                                                                                  
   IBM      - e2996d1)                                                                                                 
   JCL - 20190207_01 based on Oracle jdk8u201-b09                                                                      
   $                                                                                                                   

 

5.3. /ibm_i/deploy.sh

J'utilise un poste de travail Linux, ce script est donc en BASH. Si vous utilisez Windows, vous devez adapter ce script à un script Windows deploy.bat, sauf si vous utilisez le sous-système Windows pour Linux. Je n’ai pas essayé ce script sur macOS. Cela devrait fonctionner, car macOS utilise également BASH.

Voici un exemple de ce script :

#!/usr/bin/env bash

mvn clean package -DskipTests

sshpass -f ~/.ssh/ibmipwd ssh [your_ibm_i_login]@[ibm_i_ip_address] "mkdir -p /home/boottest/config | chmod 777 /home/boottest/config"
sshpass -f ~/.ssh/ibmipwd ssh [your_ibm_i_login]@[ibm_i_ip_address] "mkdir -p /home/boottest/lib | chmod 777 /home/boottest/lib"
sshpass -f ~/.ssh/ibmipwd ssh [your_ibm_i_login]@[ibm_i_ip_address] "mkdir -p /home/boottest/logs | chmod 777 /home/boottest/logs"

sshpass -f ~/.ssh/ibmipwd scp [your_project_root_path]/gs-accessing-data-rest/complete/ibm_i/application.yml [your_ibm_i_login]@[ibm_i_ip_address]:/home/boottest/config
sshpass -f ~/.ssh/ibmipwd scp [your_project_root_path]/gs-accessing-data-rest/complete/ibm_i/start.sh [your_ibm_i_login]@[ibm_i_ip_address]:/home/boottest
sshpass -f ~/.ssh/ibmipwd scp [your_project_root_path]/gs-accessing-data-rest/complete/target/gs-accessing-data-rest-0.1.0.jar [your_ibm_i_login]@[ibm_i_ip_address]:/home/boottest/lib

 

Mon mot de passe IBM i est stocké dans le fichier ~/.ssh/ibmipwd en texte clair. Une fois que ibm_i/deploy.sh est exécuté, nous disposerons d’une organisation de dossiers sur IBM i qui ressemble à celle illustrée ci-dessus dans la section 2. L’application Spring Boot.

6. Exécution de l'application boottest sur IBM i

Vous pouvez maintenant vous connecter au serveur IBM i. Si vous utilisez votre profil utilisateur pour démarrer l'application boottest, vous devez définir la variable d'environnement SPRING_DATASOURCE_PASSWORD. Le meilleur moyen pour le moment est de définir la variable une fois, dans votre fichier «.profile» (/home/[your_ibm_i_login]/.profile). Cette autorisation de fichier doit être 600 ou «-rw -------», car vous êtes le seul à pouvoir lire et écrire ce fichier. Vous devez redémarrer Qshell pour obtenir la variable définie.

Voici un exemple de mon fichier .profile :

 > cat .profile                                                
                                                               
   alias ll='ls -ali'                                          
   alias ..='cd ..'                                            
                                                               
   export SPRING_DATASOURCE_PASSWORD=[db2_for_i_database_password]                  
   export JAVA_HOME=/QOpenSys/QIBM/ProdData/JavaVM/jdk80/32bit

 

Nous pourrions aller dans le dossier /home/boottest et lancer le shell ./start.sh pour lancer l'application boottest. (Mais attention à tous les utilisateurs Unix/Windows/macOS/Linux/BSD, une fois que vous quittez Qshell via la touche F3 = Exit, vous supprimez également le processus JVM boottest !

Vous pouvez utiliser la touche F12 = Disconnect pour sortir du travail Qshell sans le tuer. Mais cela n’est pas viable en tant que procédure d’exécution de l’application Spring Boot. Le meilleur moyen consiste à utiliser la méthode IBM i.

6.1. Démarrer l'application Spring Boot sur IBM i

Pour soumettre un travail par lots sur IBM i, vous pouvez utiliser la commande SBMJOB Submit Job. Cependant, nous devons d’abord définir la session du profil utilisateur pour rediriger la sortie de la console à none. Nous avons déjà configuré l'application Spring Boot pour qu'elle se connecte à un fichier (boottest.log) sur IBM i. Cette commande est :

ADDENVVAR ENVVAR(QIBM_QSH_CMD_OUTPUT) VALUE(*NONE)

 

Puis, pour démarrer l’appli boottest, nous devons soumettre la commande suivante :

SBMJOB CMD(QSH CMD('/home/boottest/start.sh')) JOB(BOOTTEST) JOBQ(QSYSNOMAX)

 

6.2. Vérification de l’exécution sur IBM i

Les commandes WRKACTJOB ou WRKUSRJOB montrent l’exécution de l’appli boottest, tel que :

WRKUSRJOB STATUS(*ACTIVE)

Nous pouvons aussi vérifier le fichier de journalisation en utilisant la commande WRKLNK :

WRKLNK OBJ('/home/boottest/logs/boottest.log')

Nous pouvons voir que, en date du 2019-06-26 08:45:46, l’appli boottest fut démarré avec SBMJOB et start.sh.

En suite, après 29 secondes, l’appli boottest a complètement débuté sur le port 8880 (context path/boottest).

6.3. Soumission d’une requête à l’IBM i

Soumettons maintenant des requêtes REST à l’appli boottest sur IBM i. Le premier sera identique à celui de la section 4. Exécution de l'application depuis l'EDI, mais en utilisant l’adresse IP IBM i, qui est protégé par XX.XX.XX.XX :

http XX.XX.XX.XX:8880/boottest/people/search/findByLastName?name=Baggins

 

Le résultat est :

HTTP/1.1 200 
Content-Type: application/hal+json;charset=UTF-8
Date: Wed, 26 Jun 2019 09:30:11 GMT
Transfer-Encoding: chunked

{
    "_embedded": {
        "people": [
            {
                "_links": {
                    "person": {
                        "href": "http://XX.XX.XX.XX:8880/boottest/people/201"
                    },
                    "self": {
                        "href": "http://XX.XX.XX.XX:8880/boottest/people/201"
                    }
                },
                "firstName": "Bilbo Jr.",
                "lastName": "Baggins"
            }
        ]
    },
    "_links": {
        "self": {
            "href": "http://XX.XX.XX.XX:8880/boottest/people/search/findByLastName?name=Baggins"
        }
    }
}

 

Créons un nouvel enregistrement :

http POST XX.XX.XX.XX:8880/boottest/people lastName=Wayne firstName=Bruce

 

La réplique HTTP est :

HTTP/1.1 201 
Content-Type: application/json;charset=UTF-8
Date: Wed, 26 Jun 2019 10:28:16 GMT
Location: http://XX.XX.XX.XX:8880/boottest/people/202
Transfer-Encoding: chunked

{
    "_links": {
        "person": {
            "href": "http://XX.XX.XX.XX:8880/boottest/people/202"
        },
        "self": {
            "href": "http://XX.XX.XX.XX:8880/boottest/people/202"
        }
    },
    "firstName": "Bruce",
    "lastName": "Wayne"
}

 

Lors de la recherche du nouvel enregistrement, le fichier journalier est tracé. Essayons cette requête :

http XX.XX.XX.XX:8880/boottest/people/search/findByLastName?name=Wayne

 

Vous pouvez consulter le fichier journalier à l'aide de la commande WRKLNK, mais nous pouvons également télécharger le fichier boottest.log à l'aide du système de fichiers intégré à partir de IBM i Access Client Solutions. Accédez au dossier /home/boottest/logs et téléchargez le fichier boottest.log. Il est plus facile de visualiser le fichier sur un PC, car les journaux ont généralement plus de 80 colonnes.

À la fin du journal, nous pouvons voir la trace de la demande et le code SQL qui a été exécuté pour obtenir les données.

2019-06-26 11:07:27.815 DEBUG 1699 --- [http-nio-8880-exec-10] o.s.web.servlet.DispatcherServlet        : GET "/boottest/people/search/findByLastName?name=Wayne", parameters={masked}
2019-06-26 11:07:27.825 DEBUG 1699 --- [http-nio-8880-exec-10] org.hibernate.SQL                        : select person0_.id as id1_0_, person0_.first_name as first_na2_0_, person0_.last_name as last_nam3_0_ from boottest.tperson person0_ where person0_.last_name=?
2019-06-26 11:07:27.869 DEBUG 1699 --- [http-nio-8880-exec-10] o.s.web.servlet.DispatcherServlet        : Completed 200 OK

 

6.4. L’arrêt de l’appli Spring Boot sur IBM i

Comme nous avons donné un nom à notre travail par lots, nous pourrions le terminer en lançant la commande ENDJOB :

ENDJOB JOB(BOOTTEST) OPTION(*IMMED) LOGLMT(0)

 

Cela arrête gracieusement l'application boottest de manière immédiate. La commande WRKUSRJOB nous donnera :

L'application boottest n'est plus active. Toutes requêtes REST vers ce serveur et le port 8880 reçoivent une erreur de connexion.

6.5. Quelques commentaires

Le secret de SPRING_DATASOURCE_PASSWORD a été défini pour le profil qui lance le travail de soumission (voir ci-dessus 6. Exécution de l'application boottest sur IBM i). Il serait préférable de le définir une seule fois dans le profil utilisateur BOOTTEST (caché dans son fichier .profile). Ensuite, exécutez le travail d'envoi avec le profil utilisateur BOOTTEST comme tel :

SBMJOB CMD(QSH CMD('/home/boottest/start.sh')) JOB(BOOTTEST) USER(BOOTTEST) JOBQ(QSYSNOMAX)

 

Si vous avez des questions, n'hésitez pas à me contacter. Je travaille également avec de nombreuses personnes très qualifiées à ce sujet - et nous pouvons vous aider à démarrer.


S’inscrire au Blog

Articles Similaires

cross