18 10 2012
Aujourd’hui, une problématique est apparue dans la banque où je travaille : pouvoir envoyer un simple mail dans des transactions de gestion des tiers.
Autrement dit : Pouvoir envoyer un email sans sortir des écrans Cobol (As400 – Db2)
Comment procéder?
Tout d’abord, un petit schéma qui va nous guider pour la suite :
Pour cela, vous aurez besoin de différentes librairies :
- Pour l’envoi de mail (Le package ici)
- Pour la connexion à l’AS400 (Documentation ici)
Une petite explication s’impose :
Tout d’abord, pourquoi utiliser un Cobol alors que la commande RUNJVA permet d’appeler une classe Java en lui passant X paramètres?
Tout simplement parce que la longueur des paramètres sont limités. Par exemple, si vous devez envoyer un email de 1500 caractères, vous ne pourrez tout simplement pas. La longueur, de mémoire, est de 250 maximum. Autrement dit, vous serez aussi limité sur le nombre de destinataires.
Pour contourner cela, je suis passé par un fichier physique (CGDSNDP000) qui va nous garder les informations le temps d’exécuter notre Java et que ce dernier les récupère afin de les envoyer. C’est pour cela qu’il y a une colonne « FLAG » : 0 => Mail non envoyé, 1 ==> Mail envoyé. De plus, notre premier Cobol appelé va nous générer une clef sur 15 caractères avec un code application afin d’éviter les doublons. A la fin de notre traitement, notre programme Java va alimenter une data aéra (SNDEML) afin de faire remonter le code erreur.
Ainsi, en transmettant ces deux paramètres, nous serons à même de prendre les bonnes informations et d’envoyer le tout.
- CGDBSNDEML : Permet la création de notre clef (sur 15 carac.) via le programme CGDBRDM001 et insert le tout dans notre fichier CGDSNDP000
- CGDCSNDEML : Permet d’effectuer l’appel à notre classe Java. Important:Nous créons notre data aéra dans la session de l’utilisateur d’où la récupération de sa bibliothèque
- CGDSNDP000 : Notre fichier physique
- CGDSNDEMLI : Notre working
- SndMail : Notre classe java pour l’envoi du mail
- SndMailPrepare : Notre classe qui va aller prendre les données dans notre fichier CGDSNDP000
Et voici les sources :
IDENTIFICATION DIVISION.
PROGRAM-ID. CGDBSNDEML.
ENVIRONMENT DIVISION.
*----------------------------------------------------------------
CONFIGURATION SECTION.
*----------------------------------------------------------------
SOURCE-COMPUTER. IBM-AS400.
OBJECT-COMPUTER. IBM-AS400.
SPECIAL-NAMES.
C01 IS CANAL-1
REQUESTOR IS UD
LOCAL-DATA IS MD-LOCAL-DATA
CURRENCY SIGN IS "F"
DECIMAL-POINT IS COMMA.
*----------------------------------------------------------------
INPUT-OUTPUT SECTION.
*----------------------------------------------------------------
FILE-CONTROL.
*****************************************************************
DATA DIVISION.
*****************************************************************
*----------------------------------------------------------------
FILE SECTION.
*----------------------------------------------------------------
WORKING-STORAGE SECTION.
01 WW-DOUBLE-COTE PIC X(1) VALUE X"7F".
01 WW-SAUT-LIGNE PIC X(2) VALUE X"0D25".
01 WS-BODY PIC X(100).
* Date du jour *
01 WS-CURRENT-DATE PIC S9(8).
* Pour le login
01 WS-JOB PIC X(10).
01 WS-LOGIN PIC X(10).
* Pour la clé aléatoire de longueur 15
01 WW-CALL-LEN PIC 9(02) VALUE 15.
01 WW-CALL-TYPE PIC X(01) VALUE "Z".
01 WW-CLE PIC X(15).
01 WW-CDAPP PIC X(20).
* Zones de communication SQL
EXEC SQL
INCLUDE SQLCA
END-EXEC.
01 WS-NOEFFE PIC X(07).
LINKAGE SECTION.
01 LK-FROMMAIL PIC X(150).
01 LK-FROMNAME PIC X(50).
01 LK-TOMAIL PIC X(1500).
01 LK-TOMAILCC PIC X(1000).
01 LK-SUBJECT PIC X(500).
01 LK-BODY PIC X(10000).
01 LK-FORMAT PIC X(4).
01 LK-CDAPP PIC X(10).
01 LK-TOMAILREC PIC X(0300).
01 LK-RETOUR PIC X(02).
*----------------------------------------------------------------
*****************************************************************
PROCEDURE DIVISION USING LK-FROMMAIL LK-FROMNAME LK-TOMAIL
LK-TOMAILCC LK-SUBJECT LK-BODY LK-FORMAT LK-CDAPP
LK-TOMAILREC LK-RETOUR.
*****************************************************************
* Date du jour ?
ACCEPT WS-CURRENT-DATE FROM DATE YYYYMMDD.
* Code de l application
MOVE LK-CDAPP TO WW-CDAPP.
* Génération de la clef : longueur 15
* MOVE 15 TO WW-CALL-LEN.
* Z : AlphaNumeric. Ex : 1AE25DFER541AD1
* A : Alpha EX : ADFRERFDDDSEERD
* N : Numéric EX : 547852145120124
* MOVE "Z" TO WW-CALL-TYPE.
CALL "CGDBRDM001" USING WW-CALL-LEN
WW-CALL-TYPE
WW-CLE.
* Mise majuscules de la cle
MOVE FUNCTION UPPER-CASE(WW-CLE) TO WW-CLE
* Login de l utilisateur appelant le module?
CALL "CAB105C" USING WS-JOB
WS-LOGIN.
* Insertion dans la table MINSDMP000
EXEC SQL
INSERT INTO CGDSNDP000 (CLE, LOGIN, FLAG, DTMAJ,
FROMMAIL, FROMNAME, TOMAIL, TOMAILCC, SUBJECT,
BODY, FORMAT, CDAPP, TOMAILREC)
VALUES(
:WW-CLE,
:WS-LOGIN,
"0",
:WS-CURRENT-DATE,
:LK-FROMMAIL,
:LK-FROMNAME,
:LK-TOMAIL,
:LK-TOMAILCC,
:LK-SUBJECT,
:LK-BODY,
:LK-FORMAT,
:LK-CDAPP,
:LK-TOMAILREC)
END-EXEC.
* Appel du CL
CALL "CGDCSNDEML" USING WW-CLE WW-CDAPP WS-JOB LK-RETOUR.
* DISPLAY LK-RETOUR.
FIN-PROGRAMME.
*
*
TESTSQL-FIN.
GOBACK.
Notre CL CGDCSNDEML appelé dans le programme Cobol ci-dessus :
PGM PARM(&Key &CdApp &BIBUSER &RetCode)
/* Déclaration des variables */
DCL VAR(&Key) TYPE(*CHAR) LEN(15)
DCL VAR(&CdApp) TYPE(*CHAR) LEN(10)
DCL VAR(&RetCode) TYPE(*CHAR) LEN(2)
DCL VAR(&Retour) TYPE(*CHAR) LEN(150)
DCL VAR(&BIB) TYPE(*CHAR) LEN(10)
DCL VAR(&NOMENV) TYPE(*CHAR) LEN(10)
DCL VAR(&ENV) TYPE(*CHAR) LEN(10)
DCL VAR(&BIBUSER) TYPE(*CHAR) LEN(10)
DCL VAR(&ERROR) TYPE(*CHAR) LEN(1)
CHGVAR var(&ERROR) VALUE("0")
/* Détermination de l'environnement */
RTVNETA SYSNAME(&ENV)
/*En production, cette variable renvoit "FRANCE". */
/*Il faut donc la forcer en "MOGAETH01*/
IF COND(&ENV *EQ 'FRANCE') THEN(DO)
CHGVAR VAR(&ENV) VALUE('MOGAETH01')
ENDDO
/* Test la cle et le code application. Si pas remplis, on a une erreur*/
IF COND(&Key *EQ ' ') THEN(DO)
CHGVAR VAR(&ERROR) VALUE('1')
CHGVAR VAR(&RetCode) VALUE('23')
GOTO FINPGM
ENDDO
IF COND(&CdApp *EQ ' ') THEN(DO)
CHGVAR VAR(&ERROR) VALUE('1')
CHGVAR VAR(&RetCode) VALUE('23')
GOTO FINPGM
ENDDO
/*Ajout des variables d'environnement*/
ADDENVVAR ENVVAR(QIBM_JAVA_PROPERTIES_FILE) +
VALUE('/JVACgd/Mail/properties/Mail.sysproperties'+
) REPLACE(*YES)
/*Nécessaire pour la connexion à la base AS400 pour les requêtes.*/
CHGJOB CCSID(37)
/*Bibliothèque du fichier CGDSNDP000?*/
RTVOBJD OBJ(CGDSNDP000) OBJTYPE(*FILE) RTNLIB(&BIB)
/*Création de la DtAara pour la remontée des erreurs*/
DLTDTAARA DTAARA(&BIBUSER/SNDEML)
MONMSG MSGID(CPF0000)
CRTDTAARA DTAARA(&BIBUSER/SNDEML) TYPE(*CHAR) LEN(150)
/*Apppel du Java*/
RUNJVA CLASS('SndMailPrepare') PARM(&Key &CdApp &BIB &ENV +
&BIBUSER &RetCode) OUTPUT(*PRINT)
/*Au cas où une erreur java apparaitrait*/
MONMSG JVA0122 EXEC(CHGVAR &RetCode '99')
/*On remet par défaut*/
CHGJOB CCSID(65535)
/* Code Retour? */
RTVDTAARA DTAARA(&BIBUSER/SNDEML) RTNVAR(&Retour)
/* Code sur 2 caractères...*/
CHGVAR VAR(&RetCode) VALUE(%SST(&Retour 1 2))
GOTO FINPGM
FINPGM:
ENDPGM
Notre fichier de données
***************************************************************** * Fichier : CONTENU DES MAILS ENVOYES * * Flag => 0 : Non envoyé / 1 : Envoyé * ***************************************************************** R SNDMSG CLE 00015A LOGIN 00010A CDAPP 00010A FLAG 00001A DTMAJ 00008S FROMMAIL 00150A FROMNAME 00050A TOMAIL 01500A TOMAILREC 00300A TOMAILCC 01000A SUBJECT 00500A BODY 10000A FORMAT 00004A K CLE
Notre fichier Java SndMailPrepare :
import java.util.Properties;
import com.ibm.as400.access.*;
import java.sql.*;
public class SndMailPrepare
{
/* Connexion AS400 */
static Connection conn = null;
static String resultat = "0";
private static void Connexion() {
/* Enregistrement du Driver */
try {
Connection connexion = null;
DriverManager.registerDriver(new com.ibm.as400.access.AS400JDBCDriver());
} catch (SQLException e) {
e.printStackTrace();
p.WriteDtArea("23Erreur à la connexion. Voir Log.");
return;
}
try{
as400 = new AS400(env);
}catch(Exception e){
e.printStackTrace();
p.WriteDtArea("23Erreur à la connexion DtArea. Voir Log.");
return;
}
try {
Class.forName("com.ibm.db2.jdbc.app.DB2Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
p.WriteDtArea("23Erreur de chargement du Driver DB2. Voir Log.");
return;
}
System.out.println("Driver DB2 Charge");
try {
/*env = RECETTE, PREPROD1 etc.*/
conn = DriverManager.getConnection("jdbc:db2://*LOCAL;behavior override=1",
"TRFASMICAS", "PCTMA4A4M");
if (conn != null) {
System.out.println("Connexion OK");
} else {
System.out.println("Echec Connexion");
}
} catch (SQLException e) {
e.printStackTrace();
p.WriteDtArea("23Erreur de connexion DB2. Voir Log.");
return;
} catch (Exception e) {
e.printStackTrace();
p.WriteDtArea("23Erreur de connexion DB2 non gérée. Voir Log.");
return;
}
}
public static void Deconnexion(){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
p.WriteDtArea("23Déconnexion Impossible. Voir Log.");
return;
}
}
private static void GetTheFields(){
try {
String Sql = "";
boolean IsTheResultat = false;
Sql = "Select cle, FromMail, FromName, ToMail, ToMailCC, Subject, Body, Format, ToMailRec from " + bib + ".CGDSNDP000";
Sql = Sql + " where cle = '" + cle + "'";
Sql = Sql + " and cdapp = '" + cdapp + "'";
System.out.println("Récupération des champs pour la cle : " + cle + " / Application : " + cdapp);
// System.out.println("Nom du serveur : " + java.net.InetAddress.getLocalHost().getHostName());
System.out.println("Sql:" + Sql);
Statement requete = conn.createStatement();
ResultSet resultatDest = requete
.executeQuery(Sql);
while (resultatDest.next()) {
IsTheResultat = true;
FromMail = resultatDest.getString(2).trim();
FromName = resultatDest.getString(3).trim();
ToMail = resultatDest.getString(4).trim();
ToMailCC = resultatDest.getString(5).trim();
Subject = resultatDest.getString(6).trim();
Body = resultatDest.getString(7).trim();
Format = resultatDest.getString(8).trim();
ToMailRec = resultatDest.getString(9).trim();
/*Si ToMailRec est valorisé => tests en recette*/
if(ToMailRec != null && !ToMailRec.equals("") && (env.equals("RECETTE") || env.equals("PREPROD1"))){
Body = Body + "##";
Body = Body + "##";
Body = Body + "Attention : Destinaire(s) en production :";
Body = Body + "##";
Body = Body + "=>" + ToMail.toString();
if(ToMailCC != null && !ToMailCC.equals("")){
Body = Body + "##";
Body = Body + "Mail en Copie :";
Body = Body + "##";
Body = Body + "=>" +ToMailCC.toString();
}
ToMail = ToMailRec.toString();
ToMailCC = "";
}
/*Si pas de résultat*/
if(IsTheResultat == false){
p.WriteDtArea("23Erreur, la requête est vide. Voir Log.");
return;
}
System.out.println("Parametres charges : OK");
};
return;
} catch (SQLException e) {
e.printStackTrace();
p.WriteDtArea("23Erreur sur la requête. Voir Log.");
return;
} catch (Exception e) {
e.printStackTrace();
p.WriteDtArea("23Erreur non Gérée (1). Voir Log.");
return;
}
}
public static void SndMail() {
try{
SndMail m = new SndMail();
resultat = m.mail(FromMail, FromName, ToMail, ToMailCC, Subject, Body, Format);
System.out.println("Resultat de l envoi du mail : " + resultat);
if(resultat.equals("00")){
try{
/*Mise à jour du flag*/
Statement requete = conn.createStatement();
String sql = "Update " + bib + ".CGDSNDP000 set flag = 1 where cle = '" + cle + "' and cdapp = '" + cdapp + "'";
int resultat = requete.executeUpdate(sql);
if(resultat == 0){
p.WriteDtArea("23Erreur de MAJ du flag. Voir Log.");
return;
}
}
catch(SQLException e){
e.printStackTrace();
p.WriteDtArea("23Erreur de MAJ du flag. Voir Log.");
return;
}
catch(Exception e){
e.printStackTrace();
p.WriteDtArea("23Erreur de MAJ du flag non gérée. Voir Log.");
return;
}
}else{
p.WriteDtArea(resultat.toString());
return;
}
}catch(Exception e){
p.WriteDtArea("23Erreur SndMail. Voir Log.");
return;
}
}
static QSYSObjectPathName path;
static CharacterDataArea dataArea;
static AS400 as400;
public static void CreateDtArea(){
path = new QSYSObjectPathName(bibuser, "SNDEML", "DTAARA");
dataArea = new CharacterDataArea(as400, path.getPath());
}
public static void WriteDtArea(String result){
try{
dataArea.write(result);
}
catch(AS400SecurityException e){
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
}
public static String ReadDtArea(){
try{
return dataArea.read();
}
catch(AS400SecurityException e){
e.printStackTrace();
return "23";
}catch(Exception e){
e.printStackTrace();
return "23";
}
}
static String cle;
static String cdapp;
static String bib;
static String FromMail;
static String FromName;
static String ToMail;
static String ToMailCC;
static String Subject;
static String Body;
static String Format;
static String ToMailRec;
static String env;
static String bibuser;
static SndMailPrepare p;
public static void main(String[] args) {
cle = args[0];
cdapp = args[1];
bib = args[2];
env = args[3];
bibuser = args[4];
System.out.println("cle => " + args[0]);
System.out.println("cdapp => " + args[1]);
System.out.println("bib => " + args[2]);
System.out.println("env => " + args[3]);
System.out.println("bibuser => " + args[4]);
p = new SndMailPrepare();
p.Connexion();
p.CreateDtArea();
p.GetTheFields();
p.Deconnexion();
p.Connexion();
p.SndMail();
p.Deconnexion();
/*Si tout est OK*/
String resultat = p.ReadDtArea();
resultat = resultat.replaceAll(" ", "");
if(resultat.equals("")){
p.WriteDtArea("00");
}
}
}
Et enfin, notre classe d’envoi de mail :
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Transport;
import javax.mail.internet.*;
public class SndMail
{
public static String mail(String FromMail, String FromName, String ToMail, String ToMailCC, String Subject, String Body, String Format){
String etat = "0";
//System.setProperty( "file.encoding", "iso-8859-1" );
//String emailCc = "elle.himself@wanadoo.fr";
String messageText = "Ceci est un test d'envoi d'un mail à partir de Java";
String sujet = "Envoi d'un mail via JAVA";
System.out.println("Fct SndMail");
try
{
FromMail = FromMail.replaceAll(" ", "");
FromName = FromName.trim();
ToMail = ToMail.replaceAll(" ", "");
ToMailCC = ToMailCC.replaceAll(" ", "");
Subject = Subject.trim();
Format = Format.replaceAll(" ", "");
if(FromMail.length() == 0){
System.out.println("Mail Expediteur vide");
FromMail = "exploit@intranet.fr";
}else{
System.out.println("Expediteur => " + FromMail);
}
if(FromName.length() == 0){
System.out.println("Nom Expediteur vide");
FromName = "AS400";
}else{
System.out.println("Nom Exp => " + FromName);
}
if(ToMail.length() == 0){
System.out.println("Destinataire vide");
ToMail = "exp@monsite.Fr";
}else{
System.out.println("Dest => " + ToMail);
}
if(Subject.length() == 0){
System.out.println("Sujet vide");
Subject = sujet;
}else{
System.out.println("Sujet => " + Subject);
}
if(Body.length() == 0){
System.out.println("Texte vide");
Body = messageText;
}else{
System.out.println("Texte => " + Body);
}
if(Format.length() == 0){
System.out.println("Format vide : TEXT");
Format = "TEXT";
}else{
System.out.println("Format => " + Format);
}
String emailFrom = "\"" + FromName + "\"<" + FromMail + ">";
Properties props = System.getProperties();
// laisser "mail.smtp.host" en dur
props.put("mail.smtp.host", "magnesium");
// javax.mail.Session pour que ça fonctionne aussi avec WebObjects
javax.mail.Session maSession = javax.mail.Session.getDefaultInstance(props, null);
MimeMessage message = new MimeMessage(maSession);
message.setFrom(new InternetAddress(emailFrom));
if(ToMail.indexOf(";") == 0){
message.addRecipient(Message.RecipientType.TO, new InternetAddress(ToMail));
}else{
String str[] = ToMail.split(";");
for(int i=0; i 0){
if(ToMailCC.indexOf(";") == 0){
message.addRecipient(Message.RecipientType.CC, new InternetAddress(ToMail));
}else{
String str[] = ToMailCC.split(";");
for(int i=0; i");
message.setContent(Body, "text/html");
}else{
Body = Body.trim().replaceAll("##", "\n");
message.setText(Body);
}
Transport.send(message);
System.out.println("Envoi du mail : OK");
etat = "00";
}
catch (AddressException e) {
System.out.println("Erreur 1");
e.printStackTrace();
etat = "23Erreur sur le mail ou adresse. Voir Log.";
}
catch (MessagingException e) {
System.out.println("Erreur 2");
e.printStackTrace();
etat = "23Erreur non gérée. Voir Log.";
}
return etat;
}
public static void main(String[] args) {
/*SndMail temp = new SndMail();
String resultat = temp.mail(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
System.out.println(resultat);
*/
}
}
Et enfin pour que vous ayez un exemple d’appel du premier Cobol CGDBSNDEML :
IDENTIFICATION DIVISION.
PROGRAM-ID. CGDEXPEML.
ENVIRONMENT DIVISION.
*----------------------------------------------------------------
CONFIGURATION SECTION.
*----------------------------------------------------------------
SOURCE-COMPUTER. IBM-AS400.
OBJECT-COMPUTER. IBM-AS400.
SPECIAL-NAMES.
C01 IS CANAL-1
REQUESTOR IS UD
LOCAL-DATA IS MD-LOCAL-DATA
CURRENCY SIGN IS "F"
DECIMAL-POINT IS COMMA.
*----------------------------------------------------------------
INPUT-OUTPUT SECTION.
*----------------------------------------------------------------
FILE-CONTROL.
*****************************************************************
DATA DIVISION.
*****************************************************************
*----------------------------------------------------------------
FILE SECTION.
*----------------------------------------------------------------
WORKING-STORAGE SECTION.
COPY CGDSNDEMLI OF QCCOSRC REPLACING ==()== BY ==WS==.
LINKAGE SECTION.
*----------------------------------------------------------------
*****************************************************************
PROCEDURE DIVISION.
*****************************************************************
* Titre du Mail
MOVE "Test d'envoi d'un mail depuis Cobol" TO WS-SUBJECT.
* Corps du mail en mode Texte
STRING "Bonjour,"
"##"
"##"
"Ceci est une ligne avec des caractères accentués "
"et un lien vers Intranet : http://intranet-fr/"
"##"
"##"
"Ceci est la suite de mon paragraphe pour montrer que tout "
"fonctionne correctement."
"##"
"##"
"Cordialement,"
"##"
"Damien"
DELIMITED BY SIZE INTO WS-BODY.
MOVE "TEXT" TO WS-FORMAT.
* Corps du mail en mode Html MOT mettra MOT en gras
* STRING "Bonjour,"
* "##"
* "##"
* "Ceci est une ligne en gras avec des caractères "
* "accentués "
* "et un lien vers Intranet : http://intranet-fr/"
* "##"
* "##"
* "Ceci est la suite de mon paragraphe pour montrer que tout "
* "fonctionne correctement."
* "##"
* "##"
* "Documentation de ce module :"
* "##"
* "Cordialement,"
* "##"
* "Damien"
* DELIMITED BY SIZE INTO WS-BODY.
* MOVE "HTML" TO WS-FORMAT.
* Expediteur : Mail
MOVE "exp@intranet.Fr" TO WS-FROMMAIL.
* Expediteur : Nom
MOVE "Damien" TO WS-FROMNAME.
* Pour les tests, mail du destinataire
STRING "mail1@intranet.Fr;"
* "mail2@intranet.Fr;"
* "mail3@intranet.Fr;"
DELIMITED BY SIZE INTO WS-TOMAILREC.
* Destinataires
* Si plusieurs adresses, les séparer par un ';'
STRING "mail1@intranet.Fr;"
"mail2@intranet.fr;"
"mail3@intranet.fr;"
DELIMITED BY SIZE INTO WS-TOMAIL.
* Destinataires en copie. Laisser blanc si pas besoin
* MOVE " " TO WS-TOMAILCC.
STRING "mail1@Intranet.Fr;"
DELIMITED BY SIZE INTO WS-TOMAILCC.
* Code de l applicatif?
MOVE "CTRLTIERS" TO WS-CDAPP.
* Appel module pour envoi du mail
CALL "CGDBSNDEML" USING WS-FROMMAIL
WS-FROMNAME
WS-TOMAIL
WS-TOMAILCC
WS-SUBJECT
WS-BODY
WS-FORMAT
WS-CDAPP
WS-TOMAILREC
WS-RETOUR.
IF WS-RETOUR(1:2) NOT = "00"
DISPLAY "ANOMALIE APPEL MODULE ENVOI E-MAIL"
END-IF.
FIN-PROGRAMME.
*
*
TESTSQL-FIN.
GOBACK.
Et voilà, vous avez tout pour envoyer un mail depuis cobol.
N’hésitez pas à commenter si vous avez des questions.
LeBonCoin.Fr et les arnaques… MYSQL : Décomposition en Jour(s) Heure(s) et Minute(s)
Les commentaires sont fermés.