Monday, September 1, 2008

Calling executables/batch files/scripts from BPEL

No direct way..
While working with a client, I was confronted with this problem - calling an executable from BPEL. The client was using PGP(Pretty Good Privacy) to encrypt/decrypt/sign files and my task was to write a BPEL prcoess that would perform these functions by calling the PGP program. Unfortunately, BPEL does not have an out of box functionality to address this. Thus I had to write a JAVA snippet that would do the task for me. The subject matter of this post is how to write the code. Though the code is specific to calling the PGP, it could be used for calling any executable with few changes. The essentials are the same.

Calling the code
There are three ways to incorporate the JAVA code into the BPEL.


  1. Wrap the code in a web service
  2. Use JAVA embedding and call the code directly
  3. Use WSIF to call the codeYou can use any of these.

In my case the client wanted it as a web service, so that it could be resued as and when needed.


The JAVA code
My code has just one public class EncryptDecrypt and the following methods


  • public String pgpEncryptFile (String pgpEncryptCommand): This method takes the command for encrypting a file and returns 'Success' if the encryption was successful or 'Error' otherwise
  • public String pgpDecryptFile (String pgpDecryptCommand): This mehtod takes the command for decrypting a file and returns 'Success' if the decryption was successful or 'Error' otherwise
  • private void getCommandOutput(): This method fetches the output produced subsequent to the execution of the command
  • private void writeCommandOutputToLog(): This method is responsible for writing the command output to a log file. Everytime the command is run the log file is updated

Declare and initialize the variables
//location of the executable
private static final String pathToPGPExecutable = "C:\\Program Files\\Network Associates\\PGPcmdln\\PGP.exe";
private static final String pgpInstallationDirectory = "C:\\Program Files\\Network Associates\\PGPcmdln";
//name for the log file to be created

private static final String logFileName = "CommandOutput.log";
private String executionStatus = null;
private String commandOutput = null;
private String logContent = "";
private BufferedReader stdInput = null;
private BufferedReader stdError = null;
private Process processInstance = null;


Method implementations
Below are the implementations of the menthods with explanations


pgpEncryptFile
Every Java application has a single instance of class Runtime that allows the application to interface with the environment in which the application is running. We can obtain the current runtime by using the static getRuntime method of this class. Then we will call the exec method to create a new process and execute the command in the process thus created. This is done as

processInstance = Runtime.getRuntime().exec(pgpEncryptCommand);
The pgpDecrypt is exactly same as this one. The only difference is in the command.Here is the implementation of this method

public String pgpEncryptFile(String pgpEncryptCommand ) {
try {
System.out.println(pgpEncryptCommand);
//create a process and execute the command
processInstance = Runtime.getRuntime().exec(pgpEncryptCommand);
//wait for the process to complete
processInstance.waitFor();
getCommandOutput();
System.out.print("LOG Content : " + logContent);
System.out.println("LOG finished");
}
catch (IOException e) {
executionStatus = "Error";
e.printStackTrace();
}
catch (InterruptedException e) {
executionStatus = "Error";
e.printStackTrace(); }
executionStatus = "Success";
return executionStatus;
}

getCommandOutput
The next step is to get is to get our hands on the ouput of the command. For this, we will create two streams - one connected to the normal output of the process and the other connected to error stream of the process(to make provision for in the case of an error). Then we will route the contents of the stream into a local variable logContent. The implementation of this method is as follows.

private void getCommandOutput() throws IOException {
String newline = System.getProperty("line.separator");
stdInput = new BufferedReader(new InputStreamReader(processInstance.getInputStream)));
while ((commandOutput = stdInput.readLine()) != null) {
logContent = logContent + commandOutput + newline;
stdError =new BufferedReader(new InputStreamReader(processInstance.getErrorStream)));
while ((commandOutput = stdError.readLine()) != null) {
logContent = logContent + commandOutput + newline;
}
}
}

writeCommandOutputToLog
This method will write the output of the command to a log file. First, a new directory will be created under the directory where PGP is installed, and then a log file will be created under the new directory thus created. This file will contain the output of the command

private void writeCommandOutputToLog() throws IOException {
File createDir = new File(pgpInstallationDirectory, "Log");
createDir.mkdir();
String logPathLocation = pgpInstallationDirectory + "\\Log";
PrintWriter fileWrite = new PrintWriter(new BufferedWriter(new FileWriter(new File (logPathLocation, logFileName))));
fileWrite.println(logContent);
fileWrite.flush();
fileWrite.close();
}



Finally

Readers may please note that this is a more specific example, but the concept is the same. Calling any other executable would need appropriate changes in the code provided here.




No comments: