iSeries EGL

All things EGL for the iSeries / i5 / Power System

Archive for October 2012

A Conversational Dialog Box, Events and the InfoBus

leave a comment »

A Dialog Box that uses the InfoBus to Communicate User Driven Events

This post covers the creation of a dialog box and shows how to instantiate it, populate the titles and messages and how to communicate user driven events back to the parent program which launched it. The InfoBus is employed to communicate button events back to the parent program so that it may close the dialog and to act upon those events.

The Problem

The problem which this post addresses centers on the need of the application to launch a process only after asking the user if it is OK to proceed. The application launches a dialog by injecting a specified widget into a DojoDialog. When the dialog is displayed the user can select the “Cancel” or “Approve” button. At this point the event must be communicated back to the parent application so that it can A.) close the dialog and B.) either launch the process that has been approved by the user when selecting the “Proceed” button or do nothing because the user selected the “Cancel” button. The dialog box is shown below.

The dialog box.

 

The source for the dialog box and the code used by the parent application to launch it.

This section presents the source code for the dialog box along with the code used in the parent application which properly sets it up for presentation to the user.

 

The dialog box source.

Looking at the code there are two components that are established for a message title and an area for detail related messages. These are messageTextLabel and messagesTextArea The host program launching the dialog is responsible for populating these. In addition there are two functions which handle the button events. These are ApproveButton_onClick(event Event in) and CancelButton_onClick(event Event in)

package com.mig.widgets.approvedialog;

// RUI Widget

import com.ibm.egl.rui.infobus.infobus;
import com.ibm.egl.rui.widgets.GridLayout;
import com.ibm.egl.rui.widgets.GridLayoutData;
import com.ibm.egl.rui.widgets.GridLayoutLib;
import com.ibm.egl.rui.widgets.Image;
import com.ibm.egl.rui.widgets.TextLabel;
import com.ibm.egl.rui.widgets.html;
import com.mig.claimchecksapproval.libraries.ConstantsLibrary;
import com.mig.claimchecksapproval.libraries.SessionLibrary;
import com.mig.claimchecksapproval.records.GlobalDataRecord;
import com.mig.claimchecksapproval.services.ApproveChecksService;
import com.mig.widgets.waitdialog.waitdialog;
import egl.io.sql.column;
import dojo.widgets.DojoButton;
import dojo.widgets.DojoDialog;
import dojo.widgets.DojoTextArea;

//
//
handler ApproveDialog type RUIWidget{targetWidget = ui, onConstructionFunction = start, cssFile = "css/ClaimChecksApprovalProject.css", @VEWidget{category = "Custom"}}
    ui GridLayout{columns = 3, rows = 5, cellPadding = 4, children = [ GridLayout, messageTextLabel, messagesTextArea]};

    messageTextLabel TextLabel{ layoutData = new GridLayoutData{ row = 2, column = 2,
        horizontalSpan = 1, 
        horizontalAlignment = GridLayoutLib.ALIGN_CENTER }, text="TextLabel",
        fontSize = "14" };

    messagesTextArea DojoTextArea{ layoutData = new GridLayoutData{ row = 4, column = 2,
        horizontalSpan = 1 },  width = 400, height = 100,
        numColumns = 80,
        backgroundColor = "WhiteSmoke",
        id = "messagesTextArea",
        font = "courier",
        fontSize = "12" 
         };

    GridLayout GridLayout{ layoutData = new GridLayoutData{ row = 5, column = 2,
    	horizontalAlignment = GridLayoutLib.ALIGN_RIGHT }, cellPadding = 4, rows = 1, columns = 3,
    	children = [ ApproveButton, CancelButton ] };
    CancelButton DojoButton{ layoutData = new GridLayoutData{ row = 1, column = 3 }, text = "Cancel", onClick ::= CancelButton_onClick };
    ApproveButton DojoButton{ layoutData = new GridLayoutData{ row = 1, column = 2 }, text = "Approve Checks", onClick ::= ApproveButton_onClick };

          
    function start()
    end
        
    function addMessageToApproveDialog(message String in)
        messagesTextArea.value = messagesTextArea.value + message;
    end
    
    function ApproveButton_onClick(event Event in)
        InfoBus.publish(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_APPROVE_EVENT, "noData");
    end 

    function CancelButton_onClick(event Event in)
    	InfoBus.publish(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_CANCEL_EVENT, "noData");
    end 
   
end


Fig.1 – Source code for the dialog box (ApproveDialog.egl)

 

The code used by the parent application to present the dialog box

Shown below is the source code for the function in the parent application which launches the dialog box. It shows how it instantiates an object derived from the source presented above and how it injects the object into a DojoDialog box which simply acts as the container or frame for the object which represents its main body. It also shows how those message components are used.

    function presentApproveDialogMenuFunctionReturn(globalDataRecord GlobalDataRecord in)

        //Set title bar text and main body text message for the user instruction.
        title string = "Claim Checks Approval Process Verification";
        processMessage string = "Select 'Approve Checks' or 'Cancel'";
        
        //Set message to inform the user of an outcome of a previous step so they may select the
        //correct button.
        message string = "";        
        if (globalDataRecord.approvalStatus == ConstantsLibrary.CONST_APPROVAL_PROCESS_NOT_APPROVED)
            message = "Claim checks have not yet been approved for the day.\n";
            message = message + "You may proceed by selecting the approval or cancel button. \n";
        end
        if (globalDataRecord.approvalStatus == ConstantsLibrary.CONST_APPROVAL_PROCESS_ONCE_APPROVED)
            message = "** WARNING ! ** Claim checks have already been approved for the day! \n";
            message = message + "You may proceede by approving again or cancel.  If approved \n";
            message = message + "email notification will again be sent and the history screen \n";
            message = message + "will show another group of reports for the day.\n";            
        end
        
        //Create an instance of the ApproveDialog to be injected into a DojoDialog for presentation
        innerApproveDialog ApproveDialog =  new ApproveDialog{messageTextLabel.text = processMessage};
        innerApproveDialog.addMessageToApproveDialog(message);

        //Inject the innerApproveDialog into the DojoDialog and present it to the user.
        approveDialog = new DojoDialog { children = [ innerApproveDialog ]} ;
        approveDialog.title= title;
        approveDialog.draggable = false;
        approveDialog.showDialog();
    end 

Fig. 2 – The Service Return function that launches the dialog box.

The service return function above determines if the process has already been performed. While the process can be performed more than once, it is desirable to inform the user before proceeding. The dialog box is used present the outcome of that process to the user so that they can either cancel or proceed.

Now what?

So far, we’ve shown how a simple widget that acts as the main body for a dialog box is injected into a DojoDialog component that acts as its container. When the DojoDialog is presented to the user they can interact by selecting one of the two available buttons. The buttons then fire the appropriate event functions which we’ll focus on in the next section.

 

Using the InfoBus to provide a communication link

The parent application relies upon the InfoBus to receive information about events taking place between the user and the dialog box. To receive this information the following lines are added to the start() function in the parent application.

   //Register to the InfoBus the callback functions evoked by the ApproveDialog.
   Infobus.subscribe(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_CANCEL_EVENT, ApproveDialogCancelButtonInfoBusCallBack);
   Infobus.subscribe(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_APPROVE_EVENT, ApproveDialogApproveButtonInfoBusCallBack);

Fig.3 – The Parent Application. Register to the InfoBus the names of the callback functions.

See Fig. 5 for details of these functions, also in the parent application.

As seen in figure 2, the parent application “owns” the dialog meaning it holds a reference to the dialog object. When displayed the dialog is holding a conversation with the user who can select one of two buttons. No matter which button is selected, the dialog “owns” that event. There are 2 problems to be solved here, the first being the dialog cannot close itself, since it is the application which holds the object reference to the dialog. Any attempt by the dialog to close itself results in an “object not found” error. The second problem is then how to communicate the button event back to the application so that it can close the dialog, since it holds the reference to it, and then either do nothing or proceed with the process.

To accomplish this, the dialog has these button-event functions ApproveButton_onClick(event Event in) and CancelButton_onClick(event Event in), shown below.

    function ApproveButton_onClick(event Event in)
        InfoBus.publish(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_APPROVE_EVENT, "noData");
    end 

    function CancelButton_onClick(event Event in)
    	InfoBus.publish(ConstantsLibrary.CONST_APPROVAL_PROCESS_APPROVE_DIALOG_CANCEL_EVENT, "noData");
    end 

Fig.4 – The dialog’s button-event functions

They are called when either the Approve and Cancel button are selected. These functions use the InfoBus to “publish” the need to call a function that resides in the parent application. Notice that the constants used (their values are arbitrary) are the same constants used by the parent application’s start up processing which registered the call-back functions. Those functions that are in the parent application are going to get called whenever one of the functions are called.

The constants CONST_APPROVAL_PROCESS_APPROVE_DIALOG_APPROVE_EVENT and CONST_APPROVAL_PROCESS_APPROVE_DIALOG_CANCEL_EVENT of the ConstantsLibrary are used by the Infobus.publish command to establish links back to the parent application’s ApproveDialogCancelButtonInfoBusCallBack and ApproveDialogApproveButtonInfoBusCallBack functions. The values of the constants are arbitrary in nature meaning their values don’t really matter. They simply act as a handle or a means by which a lookup can be performed so that the proper function can be called when the user selects either the “Cancel” or “Approve” button.

When the user selects either button provided by the dialog the function in the parent application is called which then closes the dialog and then proceeds with the appropriate processing.

    /**
     * This function is called when the Cancel button of the Approve Dialog is selected.
     */
    function ApproveDialogCancelButtonInfoBusCallBack(event string in, data any in)
        approveDialog.hideDialog();
        approveDialog.destroy();
    end

    /**
     *  Approve the claim checks by calling this service which will;
     *  1.  Create the PDF document containing all table data shown  
     *  2.  Writes all URL values obtained from CLM0002PF to CLM003PF
     *
     */ 
    function ApproveDialogApproveButtonInfoBusCallBack(event string in, data any in)

        //Close the Approval Dialog box and destroy the object reference.
        approveDialog.hideDialog();
        approveDialog.destroy();  

        //Show another wait dialog while the approval process is running
        message string = "Approval Processing is now executing.";
        innerWaitDialog =  new WaitDialog{messageTextLabel.text = message};
        processingDialog = new DojoDialog { children = [ innerWaitDialog ]} ;
        processingDialog.title= "Approval Processing";
        processingDialog.draggable = false;
        processingDialog.showDialog();

       :
       :  Main process occurs here
       :

    end 

Fig. 5 – The event functions for the Approve and Cancel buttons.

 

Shown here is the parent application after the user has selected the “Approve” button. As a result, another dialog is presented which indicates the process has been launched.

A Process in Progress dialog box.

 

Conclusion

This post showed how to create a somewhat reusable dialog box to be injected into a DojoDialog component which was then instantiated, initialized and presented by the parent application. The problem of communicating dialog button events back to the parent application was addressed by the use of the InfoBus which calls the appropriate functions for further processing by the parent program.

 
 

Written by iseriesadmin

October 18, 2012 at 8:44 am

Sending eMail Using Java

leave a comment »

Using Java Mail to Send eMail with or without Attachments

This post presents a single Java class that can be used without modification in any application supporting Java or calls to methods of a Java class such as EGL or RPG.

 

The External Type describing the Java methods

Shown below is the EGL External Type that is used to expose the methods of the Java class used to send email. The details of the methods are revealed by the Java class source code.

package com.mig.claimchecksapproval.externaltypes;

externalType SendMail type JavaObject{PackageName = "com.mig.claimchecksapproval.mail"}

    constructor();
    function setMailServerAddress( value string in );
    function setMailServerPort( value string in );
    function setMailSentFromAddress( value string in ); 
    function setMailSentToAddress( value string in );
    function setMailSentCcToAddress( value string in );    
    function setSubject( value string in );
    function setMessageText( value string in );
    function setMailAttachmentPath( value string in );
    function setMailAttachmentFileName(value string in );
    function sendEmail() returns(string[]);
                          
end

Fig.1 – The EGL External Type

To send email, the EGL developer needs only to call the ‘Setter’ functions to provide the values needed by the process. Once the values have been established, to send the email, call the function ‘sendEmail()’. Present is a detailed list of the functions showing how to use them and what to expect.

  • function setMailServerAddress( value string in )
    This is the Address of the eMail server i.e. 123.456.789.1
    This value is mandatory.

  • function setMailServerPort( value string in )
    Port of the eMail server i.e. 25
    This value is mandatory.

  • function setMailSentFromAddress( value string in )
    The address of the sender i.e. DoNotReply@yourcompany.com
    This value is mandatory.

  • function setMailSentToAddress( value string in )
    The destination address i.e. rmendez@yourcompany.com
    This value is mandatory.

  • function setMailSentCcToAddress( value string in )
    The list of addresses for the carbon-copy i.e. rmendez@yourcompany.com, rmcdonald@yourcompany.com
    This value is optional. One or more addresses can be supplied but must be separated with commas.

  • function setSubject( value string in )
    The subject of the email
    This value is mandatory.

  • function setMessageText( value string in )
    The Message text
    This value is optional.

  • function setMailAttachmentPath( value string in )
    The path of the directory containing the attachment file i.e.

    During development:
      C:/Desk/AppDevEGL/ClaimChecksApproval/ClaimChecksApprovalProject/WebContent/content/
      		or
    During Testing:
      tomcat\TomcatTEST\webapps\ClaimChecksApproval\content\
      		or
    For production:
      tomcat\TomcatPROD\webapps\ClaimChecksApproval\content\ 
    

    This property is optional however, if the setMailAttachmentFileName is provided this is
    mandatory.

  • function setMailAttachmentFileName(value string in )
    The file name of the attachment file i.e.

    20121010151427ApprovedClaimChecks.pdf
    

    This property is optional however, if the MailAttachmentPath is provided this is
    mandatory.

  • function sendEmail() returns(string[])
    Once all of the required properties have been established, call this method to send the email.
    The method returns a list of messages related to the process indicating success or failure and
    are suitable for logging which is highly recommended.

 

The Java Class

Below is the Java class. The details behind the functions presented in the EGL External Type (Fig 1) above are revealed.
 

package com.app.utilities.general;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import com.app.utilities.general.StringRoutines;


/**
 * 
 * This class provides the ability to create an email with an attachment which can be a
 * file of any type.   For attachments all that is required is the path and file name.
 * 
 * @author benfoster
 *
 */
public class SendMail {

	private String emailServerAddress = null;
	private String emailServerPort = null;
	
	private String emailSentFromAddress = null;
	private String emailSentToAddress = null;
	private String emailSentCcToAddress = null;	
	private String emailSubject = null;
	private String emailMessageText = null;
	private String emailMailAttachmentPath = null;
	private String emailMailAttachmentFileName = null;
	
	List listOfEvents = new ArrayList();
	
	
	/**
	 * Constructor
	 */
	public SendMail() {

	}

	
	/**
	 * This is the Address of the eMail server i.e. 192.168.128.1
	 * @param value
	 */
	public void setMailServerAddress(String value) {
		this.emailServerAddress = value;
	}
	
	/**
	 * Port of the eMail server i.e. 25
	 * @param value
	 */
	public void setMailServerPort(String value) {
		this.emailServerPort = value;
	}
	
	/**
	 * The address of the sender i.e. DoNotReply@manhattanlife.com
	 * @param value
	 */	
	public void setMailSentFromAddress(String value) {
		this.emailSentFromAddress = value;
	}
	
	/**
	 *  The destination address i.e. bfoster@manhattanlife.com
	 * @param value
	 */	
	public void setMailSentToAddress(String value) {
		this.emailSentToAddress = value;
	}
	
	/**
	 *  The list of addresses for the carbon-copy i.e. bfoster@manhattanlife.com, klubin@manhattanlife.com
	 * @param value
	 */	
	public void setMailSentCcToAddress(String value) {
		this.emailSentCcToAddress = value;
	}	
	
	/**
	 * The subject of the email
	 * @param value
	 */	
	public void setSubject(String value) {
		this.emailSubject = value;
	}

	/**
	 * The Message text  
	 * @param value
	 */	
	public void setMessageText(String value) {
		this.emailMessageText = value;
	}

	/**
	 * The path of the directory containing the attachment file i.e.
	 * C:/Desk/AppDevEGL/ClaimChecksApproval/ClaimChecksApprovalProject/WebContent/content/
	 * 		or
	 * tomcat\Tomcat6032T\webapps\ClaimChecksApproval\content\
	 * 
	 * This property is optional however, if  the setMailAttachmentFileName is provided this is
	 * mandatory.
	 *  
	 * @param value
	 */
	public void setMailAttachmentPath (String value) {
		this.emailMailAttachmentPath = value;
	}

	
	/**
	 *  The file name of the attachment file i.e. 20121010151427ApprovedClaimChecks.pdf
	 *  
	 * This property is optional however, if  the MailAttachmentPath is provided this is
	 * mandatory.
	 * 
	 * @param value
	 */
	public void setMailAttachmentFileName(String value) {
		this.emailMailAttachmentFileName = value;
	}
	
	
	/**
	 * Once all of the required properties have been established, call this method to send the email.
	 * 
	 * @return List A list of messages related to the process indicating success or failure.
	 */
	public List sendEmail() {

		if ( emailServerAddress == null || emailServerPort == null || emailSentFromAddress == null || 
		 emailSentToAddress == null || emailSentCcToAddress == null ||  emailSubject == null  
		) {
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): One or more required parameters are missing. Process aborted.");	
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): Failed" + emailMailAttachmentFileName);				
			return listOfEvents;
		}
		
		
		//String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
		
		Properties props = new Properties();
		props.put("mail.smtp.host", emailServerAddress);
		props.put("mail.smtp.port", emailServerPort);
        	//props.put("mail.transport.protocol.", "smtp");
        	//props.put("mail.smtp.auth", "false");
        	//props.put("mail.smtp.", "true");
        	props.put("mail.from", emailSentFromAddress);
        	props.put("mail.to", emailSentToAddress);
        	props.put("mail.cc", emailSentCcToAddress);
        	props.put("mail.smtp.socketFactory.fallback", "false");
        	//props.put("mail.smtp.socketFactory.class", SSL_FACTORY);		
		
        	Session mailSession = Session.getInstance(props, null);
        	mailSession.setDebug(true);
        
        	//Initialize a StringRoutines object.
        	StringRoutines sr = new StringRoutines();
        
        
		//Test for supplied emailMailAttachmentPath and emailMailAttachmentFileName
		if( !sr.isBlank(this.emailMailAttachmentPath) && sr.isBlank(this.emailMailAttachmentFileName) ){
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): emailMailAttachmentPath supplied but emailMailAttachmentFileName is blank.");	
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): emailMailAttachmentPath value is " + emailMailAttachmentPath);	
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): emailMailAttachmentFileName value is " + emailMailAttachmentFileName);	
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): Failed" + emailMailAttachmentFileName);	
			return listOfEvents;        	
		}
		if( sr.isBlank(this.emailMailAttachmentPath) && !sr.isBlank(this.emailMailAttachmentFileName) ){
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): emailMailAttachmentPath is blank but emailMailAttachmentFileName is supplied.");	
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): emailMailAttachmentPath value is " + emailMailAttachmentPath);	
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): emailMailAttachmentFileName value is " + emailMailAttachmentFileName);	
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): Failed" + emailMailAttachmentFileName);	
			return listOfEvents;        	
		}        
        
        
		String pathAndFile = this.emailMailAttachmentPath + emailMailAttachmentFileName;

		try {
			// create a message
			MimeMessage msg = new MimeMessage(mailSession);
			msg.setFrom(new InternetAddress(emailSentFromAddress));

			InternetAddress[] address = {new InternetAddress(emailSentToAddress)};
			msg.setRecipients(Message.RecipientType.TO, address);

			//This uses the StringRoutines class of the AppUtilities project in which this class
			//also resides.  It accepts a token-separated list of string values and separates them
			//into a vector i.e. an array list that can be used in a loop to operate upon the 
			//individual entries.  In this case we are using the values as entries in the Cc part
			//of an email.
			Vector vectorOfAddresses = sr.separateWordsUsingToken(emailSentCcToAddress, ",");
			for(int idx = 0; idx < vectorOfAddresses.size(); idx++) {
			  String ccEmailAddress = (String)vectorOfAddresses.get(idx);
			  msg.addRecipient( Message.RecipientType.CC, new InternetAddress(ccEmailAddress) );
			}

			msg.setSubject(emailSubject);

			// create and fill the first message part
			MimeBodyPart mbp1 = new MimeBodyPart();
			mbp1.setText(emailMessageText);

			//If pathAndFile is not blank add the file specified as an attachment.
			if( !sr.isBlank(pathAndFile) ) {
			      // create the second message part
			      MimeBodyPart mbp2 = new MimeBodyPart();

			      // attach the file to the message
			      FileDataSource fds = new FileDataSource(pathAndFile);
			      mbp2.setDataHandler(new DataHandler(fds));
			      mbp2.setFileName(fds.getName());

			      // create the Multipart and add its parts to it
			      Multipart mp = new MimeMultipart();
			      mp.addBodyPart(mbp1);
			      mp.addBodyPart(mbp2);

			      // add the Multipart to the message
			      msg.setContent(mp);
			}

			// set the Date: header
			msg.setSentDate(new Date());

			// send the message
			Transport.send(msg);

			listOfEvents.add("SendMail.sendApprovalProcessEmail(): Email sent.");
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): Success" + emailMailAttachmentFileName);			      
		} catch (MessagingException mex) {
			mex.printStackTrace();
			Exception ex = null;
			if ((ex = mex.getNextException()) != null) {
			  ex.printStackTrace();
			}
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): Email failed with exception : " + mex);
			listOfEvents.add("SendMail.sendApprovalProcessEmail(): Failed" + emailMailAttachmentFileName);	
		}
		

		return(listOfEvents);
		
	}
}



Fig.2 – The Java Class that does all the work.

 

The EGL Code that goes into the Service program.

Shown below is the segment of code that is added to the Service part. In addition to the External Type shown in Fig 1., it is all the code required by the EGL developer to create and send an email.

All of the heavy work is being accomplished by the Java class, SendMail shown in Fig. 2.

            //************************************************************
            // Email the PDF document created in a previous step to the
            // recipients designated in the applicationConfig.xml file.
            //************************************************************           
            sendMail Sendmail = new SendMail();
            sendMail.setMailServerAddress(globalDataRecord.emailServerAddress);
            sendMail.setMailServerPort(globalDataRecord.emailServerPort);
            sendMail.setMailSentFromAddress(globalDataRecord.emailFromAddress);
            sendMail.setMailSentToAddress(globalDataRecord.emailTo);
            sendMail.setMailSentCcToAddress(globalDataRecord.emailCcTo);
            sendMail.setSubject("Claim Checks Print Request");
            sendMail.setMessageText(" "); 
            sendMail.setMailAttachmentPath(globalDataRecord.pdfFilesLocation);
            sendMail.setMailAttachmentFileName(pdfFileName);
            events String[] = sendMail.sendEmail();

Fig.3 – The EGL code used to eMail from an EGL Service

 

Conclusion

As can be seen, sending eMail from EGL is easily accomplished by the use of a simple Java class. Packaged into a .jar file and included in any EGL project it can be reused across many projects.

 
 

Written by iseriesadmin

October 11, 2012 at 9:23 am