Oracle Technologies Primer

July 22, 2011

Creating A PDF Document within a BPEL Process

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.

.

4 Comments »

  1. [...] my previous post I had described how we can create a custom Java Class to save custom business indicators in a [...]

    Pingback by Archiving Audit Diagrams as Images in Oracle SOA Suite BPM Processes « Oracle Technologies Premier — July 26, 2011 @ 4:10 pm

  2. the Java embedding approach is very interesting and I was not aware of that thanks.

    As an alternative I would like to show you the XSLFO approach, you can create a XSLFO template and call the Apache FOP servlet with HTTP there is a description here:

    http://www.java4less.com/fopdesigner/fodesigner.php?info=oraclebpel

    Comment by Jon — October 30, 2011 @ 8:09 pm

    • Hi Jon, I was not aware of the XSLFO approach and it looks very interesting. However the documentation available to use it to generate a PDF from a BPEL process is not exhaustive. Is there a way that PDF’s can be formatted?

      Comment by Arun Pareek — October 31, 2011 @ 2:27 am

  3. I used an alternative approach for achieving the same.
    I wrote the same java code using iText Pdf jars and exposed that java code as a web service which was deployed on the same weblogic server.
    Hence, now, all services can use the same external java as a Partner link in their BPEL.

    The same can be done using Apache XSL-FO too.

    HTH.

    Comment by punix — January 2, 2012 @ 6:56 pm


RSS feed for comments on this post. TrackBack URI

Post your comments and suggestions here

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme. Blog at WordPress.com.

Adam Deane

Business Process and Workflow

Oracle Technologies Primer

Technical posts on OSB/WLS/AIA, Oracle SOA Suite, BPM and Fusion Middleware

SOA Community Blog

by Jürgen Kress

Technical posts on OSB/WLS/AIA, Oracle SOA Suite, BPM and Fusion Middleware

Technical posts on OSB/WLS/AIA, Oracle SOA Suite, BPM and Fusion Middleware

J@n van Zoggel

mumblings of a middleware minion

Oracle .. Java .. OpenSource .. SOA

Just another WordPress.com weblog

Nitin's Oracle Fusion Middleware and SOA World

SOA FMW BPM BPEL OSB Governance J2EE and all the Geeky stuff

RedStack

Musings on Integration with Oracle Fusion Middleware

Follow

Get every new post delivered to your Inbox.

Join 921 other followers

%d bloggers like this: