Tuesday 22 May 2012

Apache Camel Tutorial on EIP, Routes and Testing

Interesting blog about Apache Camel. I'll be definitely playing around with this on the weekend and post my findings about it.

Please read it at the following link - http://www.kai-waehner.de/blog/2012/05/04/apache-camel-tutorial-introduction/

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

Tuesday 24 April 2012

Comparing Open Source ESBs

I've working heavily with webMethods (http://goo.gl/z69Nu) for the last 7 or so years, I'm always thinking about what open source alternatives are there and how mature they have become compared to more proprietary EBS's like webMethods, Tibco, Oracle Fusion, IBM WebSphere etc.

I've been playing around recently with Apache Camel (http:/camel.apache.org) and Mule ESB (http://www.mulesoft.org) to get a better idea of how easy it is to use these open source ESBs

I've found that Apache Camel has quite a lot of the standard endpoints used in most organisations, however, the GUI for quick mappings and orchestrations is lacking. The tutorials are good and very detailed, especially with providing sample code, but doesn't feel like it's complete. Due to it's open source nature and with many collaborators working on Apache projects, there is a big talent pool out there to help make this a solid alternative to a paid ESB.

Mule, on the other hand, was originally driven through a XML file that had all the endpoint configurations. When dealing with configuring XML for endpoints, it was quite painful. With Mule Studio GA releasing, it has made development and integration a whole lot easier with a GUI that allows for orchestrations and quick integration projects.
One of my good friends has done quite a bit of Mule integration and with the new GUI, he's been able to reduce the amount of time taken to do his projects.

I've been looking to use Mule for my home projects and eventual integration to websites, but with the very small nature of those projects, I might just stick with using some simpler Java based solution.

This was just my experience with some of the commonly used open source ESB's compared to paid alternatives. I'll be using them more in the future and will be keeping track of them as well as any newer ones that pop up.

Tuesday 17 April 2012

Communication between MWS & ESB with certificates

Introduction

The following article guides you through setting up your MWS and IS instances to encrypt data/decrypt data 

MWS

Installing the IS certificate into the MWS truststore

  1. On your MWS server download a copy of InstallCert.java
  2. Open the file and change the line 72 to reflect your install path of MWS
  3. Compile the code javac InstallCert.java
  4. Run the code as follows:
    • java -cp . InstallCert <ISHostName:httpsPortNum> <glueTrustStore.jksPassword>
  5. This will try to download the certificate from the IS server and install it in the MWS truststore

Setup environment variables in your CAF application

Configure your CAF application to have the following environment entries:

String store = "<MWS_HOME>/server/<server_Instance>/config/glue/glueTrustStore.jks";
String sPass = passphrase_for_file_above;
String alias = alias_of_IS_key;

Write a method that takes in your data to be encrypted with the Certificate, plus the above parameters:

private static byte[] encryptData(String store, String sPass, String alias, String data) throws Exception {
    KeyStore ks = KeyStore.getInstance("JKS");
    FileInputStream fis = new FileInputStream(store);
    ks.load(fis, sPass.toCharArray());
    fis.close();
    java.security.cert.Certificate cert = ks.getCertificate(alias);
    PublicKey key = cert.getPublicKey();
    Cipher cipher = Cipher.getInstance(key.getAlgorithm());  
    cipher.init(Cipher.ENCRYPT_MODE, key);
    return cipher.doFinal(data.getBytes());
}

Bind the byte[] to the input provided by the ESB WSD.

ESB

Create a service that takes in a byte[] input from above and retrieves the privateKey of the IS as well as decryption of the payload (using the following flow service to get the privateKey):
pub.security.keystore:getKeyAndChain

Here is the Java code for the decryption service:

public static final void decryptData(IData pipeline) throws ServiceException {
    // pipeline
    IDataCursor pipelineCursor = pipeline.getCursor();
    PrivateKey privateKey = (PrivateKey) IDataUtil.get(pipelineCursor, "privateKey");
    byte[] encryptedData = (byte[]) IDataUtil.get(pipelineCursor, "encryptedData");
    pipelineCursor.destroy();

    Cipher cipher = null;
    String decryptedData = null;
    try {
        cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        decryptedData = new String(cipher.doFinal(encryptedData));
    } catch (Exception e) {
        throw new ServiceException(e);
    }
    // pipeline
    IDataCursor pipelineCursor_1 = pipeline.getCursor();
    IDataUtil.put(pipelineCursor_1, "decryptedData",decryptedData);
    pipelineCursor_1.destroy();
}

For details on setting up the certificates on the IS, please refer to the Administration Guide.