Sunday, May 13, 2018

Mule Application Dev: Email Notification With Apache Velocity Engine

Introduction

It is very common to send email notification for important event in the enterprise integration. Mule AnyPoint Platform come with parse-template component, which allow us to pass flow variables, payload, etc to the html template. This approach is very simple and straight forward for the simple email notification. The another approach is to using apache velocity engine to parse more complicated data set to the html template.

In this post, I am going to introduce the both. For the email server, I am going to using Gmail.

The complete code is available at my github repository

The Requirements

The requirement is that clients will pass a json request contains the informaiton as shown in the following:


{
 "subject": "Connection To Oracle Database Not Available",
 "emailTo": "gary.liu1119@gmail.com",
 "emailFrom": "guojiang.liu1119@gmail.com",
 "replyTo" : "gary.liu1119@gmail.com",
 "integrationId" : "OracleDB-To-SFDC",
 "body" : "This is the body message",
 "channel" : "slack channel",
 "footer": "This is generated email. Please DO NOT Reply to this email 
 
 Best Regards, 
 Mule Integration Team",
 "payload" : {
  "header" : ["column_a","column_b","column_c","column_d","column_f"],
  "data": [
   ["column_a_data1","column_b_data1","column_c_data1","column_d_data1","column_f_data1"],
   ["column_a_data2","column_b_data2","column_c_data2","column_d_data2","column_f_data2"],
   ["column_a_data3","column_b_data3","column_c_data3","column_d_data3","column_f_data3"]
   
  ]
 } 
}
The resultant email should look like the following:

Using Template Parser

This is very simple scenario. We will use the <parse-template ...=""> component as the following:
        
The html template is in the following form:
<html>
    <head>
      <title>#[original_payload.subject]</title>
    </head>
    <body>
      Environment: #[environment]
      Date: #[system_date]
      Integration Case ID: #[original_payload.integrationId]      
      #[original_payload.body]
     
      #[original_payload.footer]
 
    </body>
</html>
In the above html code, the #[environment] is the same as #[flowVars.environment] The flows for using parse-template are shown in the following diagram:

Using Velocity

Apache Velocity Engine is a powerful tool for build complicated html template. Here I only introduce the for loop. For more directives, you may refer the following document.

The html template is shown as the following:

<HTML>
    <HEAD>
      <TITLE>$emailInfo.subject</TITLE>
    </HEAD>
    <BODY>
      <BR>
      Environment: $emailInfo.environment     
      <BR><BR>
      Integration ID: $emailInfo.integrationId
      <BR/>
      <BR/>      
      $emailInfo.body     
      <BR/><BR/>   
      <TABLE width="70% "border = "1" cellspacing="0" cellpadding="2" font="5">
        <TR style="text-align: left; font-size: 14px; font-weight: bold; color: #000000;">
        
        #foreach ($headerCol in $emailInfo.payload.header)
                <TH>$headerCol</TH>
        #end
        
        </TR>
        
        #foreach ($data in $emailInfo.payload.data)
            <TR style="text-align: left; font-size: 13px; font-weight: bold; color: #488AC7;">          
            #foreach ($col in $data)
                <TD>$col</TD>
            #end            
            </TR>
        #end
      </TABLE>
     
     <BR/>
     <BR/>
      
     <I>$emailInfo.footer</I>
          
 
    </BODY>
</HTML>

As you can see that for loop takes the following form:

        
        #foreach ($headerCol in $emailInfo.payload.header)
              <TH>$headerCol</TH>
        #end

Where the emailInfo is a java object in the form of: LinkedHashMap emailInfo. The whole idea is MVC, Model, View, Control. The html is the view page, the mode is and java object. Control is the engine injecting data to the view.

The java code is in the following form:


public class VelocityComponent implements Callable
{
 private static Logger logger = LoggerFactory.getLogger(VelocityComponent.class);

 @SuppressWarnings("unchecked")
 @Override
 public Object onCall(MuleEventContext eventContext) throws Exception {
  LinkedHashMap payload = (LinkedHashMap)eventContext.getMessage().getPayload();
  String emailHtml = this.buildEmailHtml(payload);
  return emailHtml;
 }
 
    public String buildEmailHtml(LinkedHashMap emailInfo) throws Exception
    {
        VelocityEngine ve = new VelocityEngine();
        ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());

        ve.init();
        
        String environment = System.getProperty("mule.env");
        
        emailInfo.put("environment", environment);

        VelocityContext context = new VelocityContext();
        context.put("emailInfo", emailInfo);

        Template t = ve.getTemplate("email-notification-template-velocity.vm" );

        StringWriter writer = new StringWriter();

        t.merge( context, writer );

        logger.info( writer.toString() );
        
        return writer.toString();
    }
}

1 comment:

  1. Very informative post for mulesoft developers.You can also visit goformule.com for mulesoft stuff.

    ReplyDelete

Anypoint Studio Error: The project is missing Munit lIbrary to run tests

Anypoint Studio 7.9 has a bug. Even if we following the article: https://help.mulesoft.com/s/article/The-project-is-missing-MUnit-libraries-...