Introduction
The following post outlines what is required to merge data from an IS document to an Adobe LiveCycle Static PDF form.
Prerequisites
- Adobe Livecycle Static PDF Form
- iText jars in package
- Names used in Static form are the same as in IS Document, otherwise data won't be merged
IS Code
Inputs/Outputs:
- Document - IS document containing data
- pdfFormTemplate - full file path of the Adobe Livecycle Static PDF form
- pdfBytes - byte[] containing merged data
import com.wm.data.*;
import com.wm.util.Values;
import com.wm.app.b2b.server.Service;
import com.wm.app.b2b.server.ServiceException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Set;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
import com.wm.data.IData;
import com.wm.data.IDataCursor;
import com.wm.data.IDataUtil;
import com.wm.util.coder.IDataCodable;
public final class documentToPdfBytes_SVC
{
/**
* The primary method for the Java service
*
* @param pipeline
* The IData pipeline
* @throws ServiceException
*/
public static final void documentToPdfBytes(IData pipeline)
throws ServiceException {
// pipeline
IDataCursor pipelineCursor = pipeline.getCursor();
IData document = IDataUtil.getIData(pipelineCursor, "document");
if (document == null) {
throw new ServiceException("No document provided");
}
HashMap<String,String> fieldMap = new HashMap<String, String>();
String pdfFormTemplate = IDataUtil.getString( pipelineCursor, "pdfFormTemplate" );
byte[] pdfBytes = null;
try {
populateHashMap(document, fieldMap);
pdfBytes = createPdfData(pdfFormTemplate, fieldMap);
} catch(Exception e) {
throw new ServiceException(e);
}
// pipeline
IDataUtil.put(pipelineCursor, "pdfBytes", pdfBytes);
pipelineCursor.destroy();
}
// --- <<IS-BEGIN-SHARED-SOURCE-AREA>> ---
/**
* Fill out a form the "traditional way".
* @param pdfTemplate the original PDF
* @param outputFile the final signed output PDF file
* @param fieldMap {@link HashMap} of IData key/value pairs in the input document
* @throws Exception
*/
private static byte[] createPdfData(String pdfTemplate, HashMap<String, String> fieldMap) throws Exception {
RandomAccessFileOrArray raf = new RandomAccessFileOrArray(pdfTemplate);
PdfReader reader = new PdfReader(raf,null);
File tmpFile = File.createTempFile("cpv", ".pdf");
tmpFile.deleteOnExit();
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(tmpFile));
AcroFields form = stamper.getAcroFields();
form.removeXfa();
Set<String> fields = form.getFields().keySet();
if(fields.size() == 0) {
throw new ServiceException("No AcroFields in this pdf template "+ pdfTemplate);
}
for(String s : fields) {
for(String key : fieldMap.keySet()) {
if(s.contains(key)) {
form.setField(s, fieldMap.get(key));
}
}
}
stamper.setFormFlattening(true);
stamper.close();
byte[] fileBytes = getBytesFromFile(tmpFile);
return fileBytes;
}
// Returns the contents of the file in a byte array.
private static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
// You cannot create an array using a long type.
// It needs to be an int type.
// Before converting to an int type, check
// to ensure that file is not larger than Integer.MAX_VALUE.
if (length > Integer.MAX_VALUE) {
// File is too large
}
// Create the byte array to hold the data
byte[] bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}
// Close the input stream and return bytes
is.close();
return bytes;
}
/**
* @param in {@link IData} pipeline document
* @param fieldMap {@link HashMap} map of document fields
* @param indent
* @throws ServiceException
*/
private static void populateHashMap(IData in, HashMap<String,String> fieldMap) throws ServiceException {
IDataCursor idc = in.getCursor();
for (int i = 0; idc.next(); i++) {
Object key = idc.getKey();
Object val = idc.getValue();
if (val instanceof IData[]) {
IData[] ida = (IData[]) val;
for (int l = 0; l < ida.length; l++) {
populateHashMap(ida[l], fieldMap);
}
} else if (val instanceof IData) {
populateHashMap((IData)val, fieldMap);
} else if (val instanceof IDataCodable[]) {
IDataCodable[] ida = (IDataCodable[]) val;
for (int l = 0; l < ida.length; l++) {
populateHashMap(ida[l].getIData(), fieldMap);
}
} else {
if(val != null) {
fieldMap.put(key.toString(), val.toString());
}
}
}
idc.destroy();
}
private static void logMessage(Object msg) {
IData input = IDataFactory.create();
IDataCursor inputCursor = input.getCursor();
IDataUtil.put(inputCursor, "message", "field: "+msg.toString());
try {
Service.doInvoke("pub.flow","debugLog", input);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
inputCursor.destroy();
}
// --- <<IS-END-SHARED-SOURCE-AREA>> ---
}