Monday 7 May 2012

Merging IS document to LiveCycle PDF

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>> ---
}

No comments:

Post a Comment