Friday, June 12, 2009

Adding Digital Signatures to a PDF Document with Java

For this exercise, you will need to make a call to a server running Adobe LiveCycle ES 8.2.1. You will have to have it set up with appropriate user names and permissions. To learn how to set up Eclipse with this project and your development environment, please see the previous article here in this video: http://www.adobe.com/devnet/livecycle/articles/invoke_services.html

Set your domain name:port and the username and password in the code below. To programmatically add a Signature Field to a PDF document, the LC ES SDK offers a service client method called addSignatureField(). Here is the method signature (click to expand):


During this exercise you will also learn how to invoke an Adobe LiveCycle ES service using the Java SDK to add a visible signature field to a PDF document. The expected duration is approximately 15 minutes.

Step 1: Set up a new Java class call AddSignatureField in Eclipse. Import the same jars as per the previous lesson and also add the jar that contains the packages com.adobe.livecycle.signatures.client and com.adobe.livecycle.signatures.client.types. Copy the following code into your class:


package org.duanesworldtv.livecycle.samples;



import java.util.*;

import java.io.File;

import java.io.FileInputStream;

import com.adobe.livecycle.signatures.client.*;

import com.adobe.livecycle.signatures.client.types.*;

import com.adobe.idp.Document;

import com.adobe.idp.dsc.clientsdk.ServiceClientFactory;

import com.adobe.idp.dsc.clientsdk.ServiceClientFactoryProperties;



public class AddSignatureField {



public static void main(String[] args) {



try

{

//Set connection properties required to invoke LiveCycle ES

Properties ConnectionProps = new Properties();

ConnectionProps.setProperty(ServiceClientFactoryProperties.DSC_DEFAULT_SOAP_ENDPOINT, "http://<your_server>:<port>");

ConnectionProps.setProperty(ServiceClientFactoryProperties.DSC_TRANSPORT_PROTOCOL,ServiceClientFactoryProperties.DSC_SOAP_PROTOCOL);

ConnectionProps.setProperty(ServiceClientFactoryProperties.DSC_SERVER_TYPE, "JBoss");

ConnectionProps.setProperty(ServiceClientFactoryProperties.DSC_CREDENTIAL_USERNAME, "administrator");

ConnectionProps.setProperty(ServiceClientFactoryProperties.DSC_CREDENTIAL_PASSWORD, "p@ssw0rd");



//Create a ServiceClientFactory instance

ServiceClientFactory myFactory = ServiceClientFactory.createInstance(ConnectionProps);



//Create a SignatureServiceClient object

SignatureServiceClient signClient = new SignatureServiceClient(myFactory);



//Specify a PDF document to which a signature field is added

FileInputStream fileInputStream = new FileInputStream("/Users/duane/Desktop/eclipse/workspace/JavaOne2009-docs/test.pdf");

Document inDoc = new Document (fileInputStream);



//TODO: Specify the name of the signature field




//TODO: Create a PositionRectangle object that specifies

//the signature fields location





//TODO: Specify the page number that will contain the signature field





//Add a signature field to the PDF document

Document sigFieldPDF = signClient.addSignatureField(

inDoc,

fieldName,

pageNum,

post,

null,

null);



//Save the PDF document that contains the signature field

File outFile = new File("/Users/duane/Desktop/eclipse/workspace/JavaOne2009-docs/test-signed.pdf");

System.out.println("Signature added, file saved!");

sigFieldPDF.copyToFile(outFile);

} catch (Exception ee) {

ee.printStackTrace();

}

}

}



Step 2: Make sure your code looks similar to the following. There should five TODOs, two of which are merely paths.

We need to add code to complete the parameters required to write the code where the "TODO" markers are. Study the method signature to understand what each required parameter is.

Parameters

inPDFDoc — A com.adobe.idp.Document object that represents the PDF document to which the signature field is added. This is a required parameter and cannot be null.

signatureFieldName — The name of the signature field. This is a required parameter and cannot be null.

pageNumber — The page number on which the signature field is added. Valid values are 1 to the number of pages contained within the document. This is a required parameter and cannot be null.

positionRectangle — A PositionRectangle object that specifies the position for the signature field. This is a required parameter and cannot be null. If the specified rectangle does not lie at least partially on the crop box of the specified page, an InvalidArgumentException is thrown. Also, neither the height nor width value of the specified rectangle can be 0 or negative. Lower left X or lower left Y coordinates can be 0 or greater but not negative, and are relative to the crop box of the page.

fieldMDPOptionsSpec — A FieldMDPOptionSpec object that specifies the PDF document fields that are locked after the signature field is signed. This is an optional parameter and can be null.

seedValueOptionsSpec — A PDFSeedValueOptionSpec object that specifies the various seed values for the field. This is an optional parameter and can be null.

TODO:

The first line of code you have to add will be the name of the signature field itself. This can be whatever you want. Signature fields in PDF documents are named uniquely so you can further manipulate them programmatically to do things like validate signatures, get signature values and more.


//TODO: Specify the name of the signature field

String fieldName = "SignatureField1";



Step 4: You now need to create a "PositionRectangle" object that specifies the signature fields location. This is done via 4 integers which correspond to the (int lowerLeftX, int lowerLeftY, int width, int height). These represent the position of a signature field located within a PDF document. A signature field's rectangle defines the location of the signature field on the PDF document page in default user space units. An object of this type can be programmatically added to a PDF document.

//TODO: Create a PositionRectangle object that specifies

//the signature fields location

PositionRectangle post = new PositionRectangle(193,47,133,12);



Step 5: The last thing you have to do is to specify the page number. This may be confusing but values start at 1 (not zero) and go up. This is a mandatory requirement and will throw an error if left null. HINT: The document we are using is only one page long.

//TODO: Specify the page number that will contain the signature field


java.lang.Integer pageNum = new java.lang.Integer(1);

Step 6: Your code should now be ready to compile and run. It should look like the code below:

package org.duanesworldtv.livecycle.samples;


/*

* This Java Quick Start uses the following JAR files

* 1. adobe-signatures-client.jar

* 2. adobe-livecycle-client.jar

* 3. adobe-usermanager-client.jar

* 4. adobe-utilities.jar

* 5. jbossall-client.jar (use a different JAR file if LiveCycle ES is not deployed

* on JBoss)

*

* These JAR files are located in the following path:

* /Adobe/LiveCycle9.0/LiveCycle_ES_SDK/client-libs/common

*

* For complete details about the location of these JAR files,

* see "Including LiveCycle ES library files" in Programming

* with LiveCycle ES

*/

import java.util.*;

import java.io.File;

import java.io.FileInputStream;

import com.adobe.livecycle.signatures.client.*;

import com.adobe.livecycle.signatures.client.types.*;

import com.adobe.idp.Document;

import com.adobe.idp.dsc.clientsdk.ServiceClientFactory;

import com.adobe.idp.dsc.clientsdk.ServiceClientFactoryProperties;



public class AddSignatureField {



public static void main(String[] args) {



try

{

//Set connection properties required to invoke LiveCycle ES

Properties ConnectionProps = new Properties();

ConnectionProps.setProperty(ServiceClientFactoryProperties.DSC_DEFAULT_SOAP_ENDPOINT, "http://<your_server>:<port>");

ConnectionProps.setProperty(ServiceClientFactoryProperties.DSC_TRANSPORT_PROTOCOL,ServiceClientFactoryProperties.DSC_SOAP_PROTOCOL);

ConnectionProps.setProperty(ServiceClientFactoryProperties.DSC_SERVER_TYPE, "JBoss");

ConnectionProps.setProperty(ServiceClientFactoryProperties.DSC_CREDENTIAL_USERNAME, "administrator");

ConnectionProps.setProperty(ServiceClientFactoryProperties.DSC_CREDENTIAL_PASSWORD, "p@ssw0rd");



//Create a ServiceClientFactory instance

ServiceClientFactory myFactory = ServiceClientFactory.createInstance(ConnectionProps);



//Create a SignatureServiceClient object

SignatureServiceClient signClient = new SignatureServiceClient(myFactory);



//Specify a PDF document to which a signature field is added

FileInputStream fileInputStream = new FileInputStream("/Users/duane/Desktop/eclipse/workspace/JavaOne2009-docs/test.pdf");

Document inDoc = new Document (fileInputStream);



//Specify the name of the signature field

String fieldName = "SignatureField1";



//Create a PositionRectangle object that specifies

//the signature fields location (int lowerLeftX, int lowerLeftY, int width, int height)

PositionRectangle post = new PositionRectangle(193,47,133,35);



//Specify the page number that will contain the signature field

java.lang.Integer pageNum = new java.lang.Integer(1);



//Add a signature field to the PDF document

Document sigFieldPDF = signClient.addSignatureField(

inDoc,

fieldName,

pageNum,

post,

null,

null);



//Save the PDF document that contains the signature field

File outFile = new File("/Users/duane/Desktop/eclipse/workspace/JavaOne2009-docs/test-signed.pdf");

System.out.println("Signature added, file saved!");

sigFieldPDF.copyToFile(outFile);

} catch (Exception ee) {

ee.printStackTrace();

}

}

}

Now run the code. Note that this lab will take about 15 seconds to completely run--probably longer if there are many people all logging in at the same time.

Navigate to the path you specified for the output file and see your document. You should see a PDF document with a signature!

5 comments:

  1. For developers who don't have access to LiveCycle (not everybody can afford it), you may look into a very affordable java library which can apply digital signatures to PDF documents called jPDFSecure.

    ReplyDelete
  2. How do I make it so a signature field can be signed using java?

    I have a signature field already in my document and I want to prompt the user to sign it. For instance, there are 100 pdfs with signature fields... I want to have a script run through VBA that opens all 100 PDDocs and prompts the user for 100 signatures so they dont have to go and open each one.

    Thanks!!

    ReplyDelete
  3. How do I make it so a signature field can be signed using java?

    I have a signature field already in my document and I want to prompt the user to sign it. For instance, there are 100 pdfs with signature fields... I want to have a script run through VBA that opens all 100 PDDocs and prompts the user for 100 signatures so they dont have to go and open each one.

    Thanks!!

    ReplyDelete
  4. John:

    My company (Technoracle) is working on a server for this. It is quite a complex process since each signature has to be validated after signing but we are close to a beta product. We would be very interested in working with you to understand your requirements. If you contact me at duane at technoracle-systems dot com I will help you.

    ReplyDelete
  5. John:

    We have recently got this up and running now with the Technoracle Server. Please let us know if you would like to have a look at what we are doing?

    Duane

    ReplyDelete

Do not spam this blog! Google and Yahoo DO NOT follow comment links for SEO. If you post an unrelated link advertising a company or service, you will be reported immediately for spam and your link deleted within 30 minutes. If you want to sponsor a post, please let us know by reaching out to duane dot nickull at gmail dot com.