Wednesday, 14 September 2016

Creating A PDF Document within a BPEL Process Using Java Program

Quite recently I had this requirement in one of my project to create a PDF snapshot from a BPEL Process. The PDF document was required to be archived and contain a brief detail of key business indicators for the order and also whether the was processed manually or automatically.
The business requirement thus set it was now evident that we needed to define a schema to extract the key order indicators and use it in an Embedded Java activity inside a BPEL process to call a custom piece of Java code that create a PDF document.
Defining the schema
Here is snapshot of the schema I choose to create to describe the Order Indicators for a Sales Order Instance.
image
The Order message is intercepted in the bpel process to determine whether it is to be processed manually or automatically.
A first Look at the PDF
Creating an instance and letting the Order process manually I was able to derive a PDF capturing the order summary at an archived location. The below screenshot shows how the document looked like.
image
Creating the Process
The first step in the process would be to instantiate a salesOrderIndicator variable based on the above schema and extract information from the Sales Order payload inside the BPEL process.
I created a custom Java class to print a PDF document using the iText api for Java.
The library can be obtained from sourceforge here
Create a Java project in JDeveloper and name it OrderApprovalDocument. Add the Itextpdf-5.1.1.jar to the project classpath.
image
The OrderApprovalDocument class will create an instance of PdfWriter, take in value from the BPEL JAVA Embedded activity and create the pdf document in a tabular format.

package com.beatech.salesapp;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.Barcode;
import com.itextpdf.text.pdf.BarcodeEAN;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import java.awt.Color;
import java.io.FileOutputStream;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
public class OrderApprovalDocument {
public OrderApprovalDocument() {
super();
}
private static Font catFont =new Font(Font.FontFamily.HELVETICA, 11, Font.BOLD);
private static Font redFont =new Font(Font.FontFamily.TIMES_ROMAN, 9, Font.NORMAL, BaseColor.RED);
private static Font subFont =new Font(Font.FontFamily.HELVETICA, 6, Font.BOLD);
private static Font smallBold =new Font(Font.FontFamily.HELVETICA, 8, Font.BOLD);
public void createPDFSummary( Map varMap, String approvalStatus)
{
String fileName = "c:/Arrun/OrderApprovalSnapshot_"+(String)varMap.get("PURCHASE ID")+".pdf";
try {
Document document = new Document();
PdfWriter writer =PdfWriter.getInstance(document, new FileOutputStream(fileName));
document.open();
addDocumentMetaData(document);
addDocumentTitle(document,varMap);
addContent(document,writer,varMap, approvalStatus);
document.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// iText allows to add metadata to the PDF which can be viewed in your Adobe Reader under File -> Properties
private static void addDocumentMetaData(Document document) {
document.addTitle("Order Approval Summary");
document.addSubject("Sales Order Summary Document");
document.addKeywords("Sales Orchestraction Project,Order Approval Summary");
document.addAuthor("Sales Orchestraction Project");
document.addCreator("Sales Orchestraction Project");
}
private static void addDocumentTitle(Document document, Map contentMap) throws DocumentException {
Paragraph preface = new Paragraph();
// Adding one empty line
addEmptyLine(preface, 1);
// Adding a Document header
preface.add(new Paragraph("APPROVAL FLOW FOR ORDER : " + (String)contentMap.get("PURCHASE ID"), catFont));
addEmptyLine(preface, 1);
// A Small body: Report generated by  _Name, _Date
preface.add(new Paragraph("Report Generated by Order Approval Flow,  " +new Date(), redFont));
addEmptyLine(preface, 2);
document.add(preface);
}
private static void addContent(Document document, PdfWriter writer, Map contentMap, String approvalStatus) throws DocumentException {
// Add a table
createTable(document, writer,contentMap, approvalStatus);
}
private static void createTable(Document document, PdfWriter writer, Map varMap, String approvalStatus) throws BadElementException, DocumentException {
PdfPTable table = new PdfPTable(3);
table.setTotalWidth(500);
table.setLockedWidth(true);
PdfPCell c1 = new PdfPCell(new Phrase("ORDER APPROVAL SUMMARY", new Font(smallBold)));
c1.setColspan(3);
c1.setFixedHeight(40);
c1.setBorderColor(new BaseColor(Color.RED));
c1.setBorder( Rectangle.BOX);
c1.setBorderWidth(1);
c1.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(c1);
PdfContentByte cb = writer.getDirectContent();
BarcodeEAN codeEAN = new BarcodeEAN();
codeEAN.setCodeType(Barcode.EAN13);
String s= "000000000000"+(String)varMap.get("PURCHASE ID"); // twelve zeros prepended
codeEAN.setCode(s.substring(s.length()-13));
Image imageEAN = codeEAN.createImageWithBarcode(cb, null, null);
c1 = new PdfPCell(imageEAN,false);
c1.setHorizontalAlignment(Element.ALIGN_RIGHT);
c1.setColspan(3);
c1.setBorder(1);
c1.setFixedHeight(5);
table.addCell(c1);
c1 = new PdfPCell(new Phrase("ORDER ID",new Font(smallBold)));
c1.setBorderColor(new BaseColor(Color.RED));
c1.setBorder( Rectangle.BOX);
c1.setBorderWidth(1);
c1.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(c1);
c1 = new PdfPCell(new Phrase((String)varMap.get("PURCHASE ID"),new Font(smallBold)));
c1.setBorderColor(new BaseColor(Color.RED));
c1.setBorder( Rectangle.BOX);
c1.setBorderWidth(1);
c1.setColspan(2);
c1.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(c1);
c1 = new PdfPCell(new Phrase("KEY INDICATORS",new Font(smallBold)));
c1.setRowspan(8);
c1.setBorderColor(new BaseColor(Color.RED));
c1.setBorder( Rectangle.BOX);
c1.setBorderWidth(1);
c1.setVerticalAlignment(Element.ALIGN_CENTER);
c1.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(c1);
Iterator entries = varMap.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry) entries.next();
c1 = new PdfPCell(new Phrase( (String)entry.getKey(),new Font(subFont)));
c1.setBorderColor(new BaseColor(Color.RED));
c1.setBorder( Rectangle.BOX);
c1.setBorderWidth(1);
table.addCell(c1);
c1 = new PdfPCell(new Phrase((String)entry.getValue(),new Font(subFont)));
c1.setBorderColor(new BaseColor(Color.RED));
c1.setBorder( Rectangle.BOX);
c1.setBorderWidth(1);
c1.setBackgroundColor(new BaseColor(255,181,188));
c1.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(c1);
}
c1 = new PdfPCell(new Phrase("APPROVAL STATUS",new Font(subFont)));
c1.setHorizontalAlignment(Element.ALIGN_CENTER);
c1.setBorderColor(new BaseColor(Color.RED));
c1.setBorder( Rectangle.BOX);
c1.setBorderWidth(1);
table.addCell(c1);
c1 = new PdfPCell(new Phrase(approvalStatus,new Font(subFont)));
c1.setHorizontalAlignment(Element.ALIGN_CENTER);
c1.setBorderColor(new BaseColor(Color.RED));
c1.setBorder( Rectangle.BOX);
c1.setBorderWidth(1);
c1.setBackgroundColor(new BaseColor(227,7,7));
c1.setColspan(2);
table.addCell(c1);
document.add(table);
}
private static void addEmptyLine(Paragraph paragraph, int number) {
for (int i = 0; i < number; i++) {
paragraph.add(new Paragraph(" "));
}
}
}
Feel free to add your own custom style to the pdf. You can even add your corporate logo into the snapshot.🙂
Secondly use the Embedded Java Activity from the BPEL process to call this custom class and pass a Map containing the key indicators for the sales order instance.
You can even pass the entire XML from the embedded java activity and unmarshall the XML in the custom class. Its a matter of choice.
image
Here is the java code for the embedded activity
 System.out.println("<<<================Entering JAVA Embedding=====================>>>");
Map variableMap = new HashMap();
try{
String approvalStatus ="ORDER AUTOMATICALLY APPROVED";
// Setting the Map
variableMap.put("FULFILMENT ID",((XMLElement)getVariableData("salesOrderIndicator","/ns12:SALOrderIndicator/ns12:fulfillmentID")).getFirstChild().getNodeValue());
variableMap.put("ORDER GUID",((XMLElement)getVariableData("salesOrderIndicator","/ns12:SALOrderIndicator/ns12:orderGUID")).getFirstChild().getNodeValue());
variableMap.put("PURCHASE ID",((XMLElement)getVariableData("salesOrderIndicator","/ns12:SALOrderIndicator/ns12:purchaseID")).getFirstChild().getNodeValue());
variableMap.put("ORDER AMOUNT",((XMLElement)getVariableData("salesOrderIndicator","/ns12:SALOrderIndicator/ns12:orderAmount")).getFirstChild().getNodeValue());
variableMap.put("DISCOUNT AMOUNT",((XMLElement)getVariableData("salesOrderIndicator","/ns12:SALOrderIndicator/ns12:discountAmount")).getFirstChild().getNodeValue());
variableMap.put("TAX AMOUNT",((XMLElement)getVariableData("salesOrderIndicator","/ns12:SALOrderIndicator/ns12:taxAmount")).getFirstChild().getNodeValue());
variableMap.put("PROMISED SHIP TIME",((XMLElement)getVariableData("salesOrderIndicator","/ns12:SALOrderIndicator/ns12:promisedShipDateTime")).getFirstChild().getNodeValue());
variableMap.put("BOOKING TIME",((XMLElement)getVariableData("salesOrderIndicator","/ns12:SALOrderIndicator/ns12:bookingDateTime")).getFirstChild().getNodeValue());
if(((XMLElement)getVariableData("ruleProcessingResponse","payload","/ns20:callFunctionStatefulDecision/ns20:resultList/ns21:OrderClass/ns21:isManualOrder")).getFirstChild().getNodeValue()  == "true")
{
approvalStatus= "MANUAL APPROVAL NEEDED";
}
// Calling the Custom Class with the Map and approval status
OrderApprovalDocument createDoc = new OrderApprovalDocument();
createDoc.createPDFSummary(variableMap,approvalStatus);
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("<<<==============Leaving JAVA Embedding=========================>>>");

Open the .bpel file inside the composite and import the required classes for the Java Embedding activity using the <bpelx:exec/> extension.
image
Create a JAR from the custom java class project as OrderApprovalDocument.jar and add it to the classpath of the composite project.
image
Also copy the OrderApprovalDocument.jar into the SCA-INF\lib directory of the project inside the composite application.
Deploy the onto the soa server of the SOA Suite 11g runtime domain and test the process with a simple order message.
You can see the generated PDF in the directory mentioned in the custom java class. The pdf file is appended with the instance order number.