In my previous post I described how to send an email with attachment from Oracle BPEL (https://technology.amis.nl/2012/02/05/sending-an-email-with-attachment-from-oracle-bpel/). This post described a rather simple approach to send emails. In this post I will describe an advanced email component as an alternative.
In the ‘simple’ approach the used variables of the email activity are a combination of static and dynamic parts. Static in the way that it often contains a default subject and/or body. Optionally extended with the content of BPEL variables (dynamic). Changes in the static parts result in a redeployment of the composite. Especially in the subject and body part this happens quite often.
The advanced component that I will describe overcomes the redeployment disadvantage. Instead of directly entering the content in the email variables/fields, the (static) content of the subject and body part is loaded as a template from an external source. For the example I will get it from a database table (see definition below). After loading the template, the dynamic content is appended.
Database table:
CREATE TABLE moa_mailtemplates ( id NUMBER NOT NULL , mailtemplate_code VARCHAR2(50 BYTE) NOT NULL , mailtemplate_onderwerp VARCHAR2(2000 BYTE) NOT NULL , mailtemplate_tekst CLOB NOT NULL , CONSTRAINT moa_mailtemplates_pk PRIMARY KEY (id) );
Sample content:
INSERT INTO MOA_MAILTEMPLATES(MAILTEMPLATE_CODE, MAILTEMPLATE_ONDERWERP ,MAILTEMPLATE_TEKST) VALUES ('CustomBill', 'public event license $LOCATION$ on $EVENTDATE$', 'Could you please construct the bill for a public event license?<br>Key numbers:<br><br> - Location: $LOCATION$<br> - Event date: $EVENTDATE$);
The process – How does it work?
The process is triggered by a createAndSendMail request. The request consists of:
- MailTemplate
- MailParameters
- MailAddressInfoTo addresses (max 10)
From addresses (max 10)
ReplyTo addresses (max 10)
CC addresses (max 10)
BCC addresses (max 10) - MailAttachments (max 10)AttachmentName
mimeType
Content
Some of the items in the request, like the email addresses, is limited to a maximum (10). This is not done because of technical limitation but for user friendliness. This way Item can be wired very easily in a transformation. An example request:
<InvokeEmailService_createAndSendMail_InputVariable> <part name="payload"> <CreateAndSendMailRequest> <ns2:mailTemplate>CustomBill</ns2:mailTemplate> <ns2:mailParameters> <parameter> <LOCATION>DownTown</LOCATION> <EVENTDATE>20 Mar 2012</EVENTDATE> </parameter> </ns2:mailParameters> <ns2:MailAddressInfo> <ns2:To> <ns2:Address-1>marcel.van.de.glind@amis.nl</ns2:Address-1> </ns2:To> <ns2:ReplyTo> <ns2:Address-1>marcel.van.de.glind@amis.nl</ns2:Address-1> </ns2:ReplyTo> </ns2:MailAddressInfo> <ns2:MailAttachments> <ns2:Attachment-1> <ns2:attachmentName/> </ns2:Attachment-1> </ns2:MailAttachments> </CreateAndSendMailRequest> </part> </InvokeEmailService_createAndSendMail_InputVariable>
Later on I will show how to construct the request in BPEL. Now I will continue explaining how the request is processed by describing the individual components of the solution. Before I do this I will first give an overview of the solution in the appearance of the composite.
EmailProcessor
The incoming request is picked up by the MailService mediator and routed to EmailProcessor BPEL process. As shown in the picture below, this process invokes the EmailBodyCreator BPEL process (via the MailService mediator) to construct the email message.
The payload of this request is a subset of the incoming payload (template and variables).
The EmailBodyCreator BPEL process I will explain later on. Now I will continue with the received output payload of it in the EmailProcessor BPEL process. This output payload together with the input payload of the EmailProcessor BPEL process is used as payload when invoking the EmailSender BPEL process (via the MailService mediator) to send the email message.
Subsequently, the output payload of this EmailSender BPEL process together with the output payload of the EmailBodyCreator BPEL process is sent back as the output payload of the initial request.
EmailBodyCreator
The EmailBodyCreator routes the received ‘template name’ (as part of the input payload) via a mediator to a database adapter to get the requested template.
The database is making use of the following database package (only the body is shown) to find the template.
Database package body:
create or replace PACKAGE BODY SOA_PCK_MAIL AS PROCEDURE zoekMailtemplate( p_mailtemplate_code in out VARCHAR2 , p_mailtemplate_tekst out CLOB , p_mailtemplate_onderwerp out VARCHAR2) AS BEGIN SELECT mailtemplate_tekst, mailtemplate_onderwerp into p_mailtemplate_tekst, p_mailtemplate_onderwerp FROM moa_mailtemplates WHERE mailtemplate_code = p_mailtemplate_code; END zoekMailtemplate; END SOA_PCK_MAIL;
For now it is a very straight forward procedure, but it is prepared for possible future changes. The procedure decouples the underlying table.
The received email template together with the received payload is after transformation sent to the MailCreator Spring component.
The actual transformation
This transformation transforms the input payload into the required format of the Spring component. An example: the following payload :
<CreateMailRequest> <ns2:mailTemplate>CustomBill</ns2:mailTemplate> <ns2:mailParameters> <parameter> <LOCATION>DownTown</LOCATION> <EVENTDATE>20 Mar 2012</EVENTDATE> </parameter> </ns2:mailParameters> <ns2:MailAddressInfo> <ns2:To> <ns2:Address-1>marcel.van.de.glind@amis.nl</ns2:Address-1> </ns2:To> <ns2:ReplyTo> <ns2:Address-1>marcel.van.de.glind@amis.nl</ns2:Address-1> </ns2:ReplyTo> </ns2:MailAddressInfo> <ns2:MailAttachments> <ns2:Attachment-1> <ns2:attachmentName/> </ns2:Attachment-1> </ns2:MailAttachments> </CreateMailRequest>
In transformed into:
<CreateMail_InputVariable> <part name=”parameters”> <createMail> <arg0>'public event license $LOCATION$ on $EVENTDATE$'</arg0> <arg1> 'Could you please construct the bill for a public event license?<br>Key numbers:<br><br> - Location: $LOCATION$<br> - Event date: $EVENTDATE$ </arg1> <arg2> <replaceValue>DownTown</replaceValue> <tag>LOCATION</tag> </arg2> <arg2> <replaceValue>16 Mar 2012</replaceValue> <tag>EVENTDATE</tag> </arg2> </createMail> <part> </CreateMail_InputVariable>
The MailCreator Spring component source:
The functionality of this component is implemented in the MailCreator java class.
package nl.arnhem.midoffice.mailservice; import java.util.List; public class MailCreator implements IMailCreator { public MailCreator() { super(); } public MailCreatorOutput createMail(String templateText, String templateTitle, List<ReplaceTag> params) { MailCreatorOutput result = new MailCreatorOutput(); String resultBody = templateText; String resultTitle = templateTitle; for (ReplaceTag param : params) { resultBody = resultBody.replaceAll("\\$"+param.getTag()+"\\$", param.replaceValue); } result.setBody(resultBody) for (ReplaceTag param : params) { resultTitle = resultTitle.replaceAll("\\$"+param.getTag()+"\\$", param.replaceValue); } result.setTitle(resultTitle); result.setBody(resultBody); return result; } }
The createMail method replaces al variables in the template and then returns the email body en title. Subsequently these are returned to the EmailProcessor BPEL process.
EmailSender
The EmailSender BPEL process transforms it’s payload to the required format of the email task.
The relevant part of this transformation is show below (design mode view of this transformation is not supported by JDeveloper).
<xsl:template match="/"> <ns0:EmailPayload> <!-- Email Addresses --> <ns0:FromAccountName> <xsl:value-of select="/tns:SendMailRequest/tns:MailAddressInfo/tns:From/tns:Address-1"/> </ns0:FromAccountName> <ns0:To> <xsl:apply-templates select="/tns:SendMailRequest/tns:MailAddressInfo/tns:To" mode="address"/> </ns0:To> <ns0:ReplyToAddress> <xsl:apply-templates select="/tns:SendMailRequest/tns:MailAddressInfo/tns:ReplyTo" mode="address"/> </ns0:ReplyToAddress> <ns0:Cc> <xsl:apply-templates select="/tns:SendMailRequest/tns:MailAddressInfo/tns:CC" mode="address"/> </ns0:Cc> <ns0:Bcc> <xsl:apply-templates select="/tns:SendMailRequest/tns:MailAddressInfo/tns:BCC" mode="address"/> </ns0:Bcc> <!—Subject and Body --> <ns0:Subject> <xsl:value-of select="/tns:SendMailRequest/tns:MailContent/tns:mailSubject"/> </ns0:Subject> <xsl:choose> <xsl:when test="/tns:SendMailRequest/tns:MailContent/tns:MailAttachments/*/tns:content/text()"> <xsl:call-template name="ProcessMultiPartContent"/> </xsl:when> <xsl:otherwise> <xsl:call-template name="ProcessSimpleContent"/> </xsl:otherwise> </xsl:choose> </ns0:EmailPayload> </xsl:template> <!-- email body and 1 or more attachments --> <xsl:template name="ProcessMultiPartContent"> <ns0:Content> <ns0:MimeType>multipart/mixed</ns0:MimeType> <ns0:ContentBody> <ns0:MultiPart> <!—- email body --> <ns0:BodyPart> <ns0:MimeType>text/html; charset=UTF-8</ns0:MimeType> <ns0:ContentBody> <xsl:value-of select="/tns:SendMailRequest/tns:MailContent/tns:mailBody"/> </ns0:ContentBody> <ns0:BodyPartName/> </ns0:BodyPart> <!—- attachments --> <xsl:for-each select="/tns:SendMailRequest/tns:MailContent/tns:MailAttachments/*[tns:content/text()]"> <ns0:BodyPart> <ns0:MimeType> <xsl:value-of select="tns:mimeType/text()"/> </ns0:MimeType> <ns0:ContentBody> <xsl:value-of select="tns:content/text()"/> </ns0:ContentBody> <ns0:BodyPartName> <xsl:value-of select="tns:attachmentName/text()"/> </ns0:BodyPartName> </ns0:BodyPart> </xsl:for-each> </ns0:MultiPart> </ns0:ContentBody> </ns0:Content> </xsl:template> <!-- email body only. No attachments --> <xsl:template name="ProcessSimpleContent"> <ns0:Content> <ns0:MimeType>text/html; charset=UTF-8</ns0:MimeType> <ns0:ContentBody> <xsl:value-of select="/tns:SendMailRequest/tns:MailContent/tns:mailBody"/> </ns0:ContentBody> </ns0:Content> </xsl:template> <!-- concat addresses --> <xsl:template match="node()" mode="address"> <xsl:value-of select="*[1]/text()"/> <xsl:for-each select="*[position()>1][text()]"> <xsl:value-of select="concat(',',text())"/> </xsl:for-each> </xsl:template>
Finally the outcome of this transformation is send to the email task. The email task is invoked using this outcome as input Payload.
construct a Email component request in BPEL
In the remaining part of this post I will give an example of how to construct a request like the one shown at the beginning of this post.
The calling BPEL process has the following three step construction.
First Assign the variables/parameters to a complex type variable that contains all required dynamic email content. For example:
<xsd:complexType> <xsd:sequence> <xsd:element name="parameter" maxOccurs="unbounded" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element name="LOCATION" minOccurs="0" type="xsd:string"/> <xsd:element name="EVENTDATE" minOccurs="0" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType>
Second, transform data to the payload format of the Mail Component.
And finally, invoke the Email Service with the transformed payload. e.g:
<InvokeEmailService_createAndSendMail_OutputVariable> <part name="payload"> <CreateAndSendMailResponse> <mailBody> Could you please construct the bill for a public event license?<br> Key numbers:<br> <br> - Location: DownTown <br> - Event date: 20 Mar 2012 </mailBody> <mailSubject> public event license DownTown on 20 Mar 2012</mailSubject> <sendMailResult>done</sendMailResult> </CreateAndSendMailResponse> </part> </InvokeEmailService_createAndSendMail_OutputVariable>
After execution. The following flow is shown in the Weblogic Enterprise Manager Console: