Workaround for receiving a PDF form as PDF without Reader Extensions

24 06 2009

This post assumes one has the Adobe LiveCycle Forms ES component installed on the server.

In one of my previous posts I’ve mentioned that the Reader Extensions are necessary for a PDF form to be able to submit itself as a PDF. In this post I’m going to explain a workaround for this problem, which consists of the following steps:

  1. Create a small XML Schema Definition for the PDF form that we will create.
  2. Create a PDF form, which submits itself as an XML file attachment of an e-mail.
  3. Create an Adobe LiveCycle ES process, which will handle the e-mail and the attachment to generate a new PDF out of it and submit it back to the same e-mailaddress.

Create a small XML Schema Definition

In this example we want our PDF form to contain information about the PDF form, the person (who submits the PDF form) and an indication if the person wants an acknowledgement that the PDF form has been received in good order. We want our XML to have the following format:

<?xml version=”1.0″ encoding=”UTF-8″?>
<form>
<formdetails>
<formLocation><location of the form in the Adobe LiveCycle repository></formLocation>
</formdetails>
<persondetails>
<firstName>Geert</firstName>
<lastName>Zijlmans</lastName>
<emailAddress><my e-mailaddress></emailAddress>
</persondetails>
<questions>
<acknowledge>1</acknowledge>
</questions>
</form>

Code 1: XML content

One can use a standard text editor to create the XML Schema Definition (XSD) , but one can also use XML editors like Altova XML Spy or oXygen. The XSD should have the following format:

<?xml version=”1.0″ encoding=”UTF-8″?>
<xs:schema xmlns:xs=”http://www.w3.org/2001/XMLSchema” elementFormDefault=”qualified” attributeFormDefault=”unqualified”>
<xs:element name=”form”>
<xs:annotation>
<xs:documentation>Form</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name=”formdetails” type=”FormDetails”/>
<xs:element name=”persondetails” type=”PersonDetails”/>
<xs:element name=”questions”>
<xs:complexType>
<xs:sequence>
<xs:element name=”acknowledge” type=”xs:int”/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name=”FormDetails”>
<xs:sequence>
<xs:element name=”formLocation” type=”xs:string”/>
</xs:sequence>
</xs:complexType>
<xs:complexType name=”PersonDetails”>
<xs:sequence>
<xs:element name=”firstName” type=”xs:string”/>
<xs:element name=”lastName” type=”xs:string”/>
<xs:element name=”emailAddress” type=”xs:string”/>
</xs:sequence>
</xs:complexType>
</xs:schema>

Code 2: XML Schema Definition

Create a PDF form

Now that we have the XSD we can develop our PDF form in the Adobe LiveCycle Designer ES from within the Adobe LiveCycle Workbench ES. In the Adobe LiveCycle Workbench ES we need to have the Form design perspective active. In this perspective we want to create a new subdirectory for our little project, so we open the resources view and add a new folder to the hierarchy, named TEST. In this folder we add a new PDF file, named workaround.pdf,  and open it inside the Workbench.

Inside the PDF form we add a new data connection to our XSD. Once the XSD has been connected to the PDF form, one can drag-and-drop the contents of the XSD onto the PDF form. The next thing we need is an Email Submit Button from our Object Library and configure it to send an e-mail to an e-mailaddress our Adobe LiveCycle ES process will poll for incoming mails having a certain subject (in our case: “[test workaround]“). Our PDF form design should look like the figure below.

PDF form in Adobe LiveCycle Workbench ES

PDF form in Adobe LiveCycle Workbench ES

For our Adobe LiveCycle ES process it is essential that the process knows which PDF should be generated from the repository. To solve this little problem, we set the default value of the field form to the location of the form in our Adobe LiveCycle repository: CIBER/TEST/workaround.pdf.

Create an Adobe LiveCycle ES process

In the Adobe LiveCycle Workbench ES we need to switch to the Process design perspective. In this perspective one can add a new process in the processes pane. We create a process named renderFormMail and add it to the category CIBER TEST. In the orchestration we add the following services:

  • RenderPDFForm: This service belongs to the Adobe LiveCycle Forms ES component and can be used to generate and prefill a PDF form that is handed to the service. The prefill data needs to correspond with the dataset defined in the PDF form.
  • SendWithDocument: This service belongs to the Foundation of the Adobe LiveCycle ES platform and can be used to send an e-mail with zero or one com.adobe.idp.Document attached to it.

Before we can configure our services, we need to define several variables, which will be used by the services:

  • emailaddressInbox: This is the String value which will hold the e-mailaddress of the INBOX.
  • emailaddressFrom: This is the String value which will hold the e-mailaddress the e-mail came from.
  • form: This is the com.adobe.idp.Document which will hold the generated PDF Form.
  • formData: This is the XML data which was send together with the e-mail.

The configuration for the RenderPDFForm service will be:

  • Input
    • Name: Render PDF form from XML
    • Form to Render (XPath): /process_data/formData/form/formdetails/formLocation (will contain “TEST/workaround.pdf”)
    • Form Data (variable): formData
    • Character Set: UTF-8
    • Render At Client: Yes
    • Content root URI: repository:///CIBER/
  • Output
    • Rendered Form: form

The configuration for the SendWithDocument service will be:

  • To Addresses
    • To (variable): emailaddressInbox
  • From Addresses
    • From (variable): emailaddressFrom
  • Attachments
    • Attachment Name (literal): form.pdf
    • Attachment (variable): form

The figure below displays the designed process.

Process for workaround

Process for workaround

Once the process has been designed you need to activate it. By activating it, it can be used to create an e-mail endpoint for it.

Creating an e-mail endpoint for the process

Log in to the Administration Console of the Adobe LiveCycle ES platform and navigate to the Service Management of the process (home > services > Applications and Services > Service Management). Open the process renderFormMail and add an e-mail endpoint according to Adobe’s instructions. To invoke the process one needs to configure its input parameters:

  • emailaddressInbox (literal): <the e-maildress that needs to be polled>
  • emailaddressFrom (variable): %SENDER%
  • formData (variable): *

Once the endpoint is activated. The e-mail Inbox will be polled for incoming messages. Each incoming message will invoke the process and will be deleted afterwards. In my next post I will explain the ReceiveEmail service which will give you more control over the e-mails that start a certain process.





Connecting to the MySQL database of the Adobe LiveCycle ES Turnkey installation

4 06 2009

This post is about gaining access to the MySQL database that comes installed with the Adobe LiveCycle ES Turnkey solution.

When installing the Turnkey solution of Adobe LiveCycle ES, one automatically installs a MySQL 5.0 database which will be used by the Adobe LiveCycle ES platform. During the installation of the Turnkey solution one will be asked to provide a username and password for the account that Adobe LiveCycle ES will use to gain access to the MySQL 5.0 database (write these down somewhere because we need them later on!!).

When the Adobe LiveCycle ES platform is installed, configured and started one needs to perform the following actions to gain access to the Adobe LiveCycle ES database:

  1. Install the MySQL GUI Tools according to the installation guide provided by MySQL.
  2. Open a command window (start -> run -> cmd) and navigate to the bin directory of the mysql database that comes installed with Adobe LiveCycle ES (normally this would be: C:\Adobe\LiveCycle8.2\mysql\bin).
  3. Open the MySQL console under the root account and execute the command: msql -u root -p<the password you entered during the installation>
  4. To grant the Adobe LiveCycle ES user all privileges to the MySQL database one needs to execute the following command within the MySQL console: grant all privileges on *.* to ‘<the username you entered during the installation>’@’%’ identified by ‘<the password you entered during the installation>’;
  5. After this one needs to flush the privileges by executing the command: flush privileges;
  6. One can quit the MySQL console by executing the command: quit;

After these actions one should be able to connect to the MySQL 5.0 database of Adobe LiveCycle ES via the MySQL Query Browser of the MySQL GUI Tools.

To setup a connection to the database with the MySQL Query Browser, one will need to perform the following steps:

  1. Start the MySQL Query Browser
  2. In the connection window one presses the ellipsis (…) button to open de connection configuration window.

    Connection Window

    Connection Window

  3. In the connection configuration window, one can enter the parameters needed for the connection. To connect to the Adobe LiveCycle database use the schema: adobe. When one is finished one can apply those settings and close the configuration window.

    Configuration Window

    Configuration Window

  4. Make a connection to the Adobe LiveCycle database by selecting the profile one just has created and entering the password.

Now one is able to query the Adobe LiveCycle ES database, but be careful not to change anything unless you’re an expert!!!!!





Hiding the toolbar and navpanes of Adobe Acrobat Reader in a browser

4 06 2009

This post is about influencing the display of a PDF file in a browser window.

Normally when one opens a PDF within a browser, the PDF is shown within the Adobe Browser plug-in. This plug-in automatically shows the PDF with the plug-in toolbar above it and navigational panes (information, bookmarks, annotations and attachment panes) on the left of it.

Rob Huismans, a CIBER colleague, found a way to automatically hide the toolbar and navpanes of the Adobe Browser plug-in when showing the PDF. This way involves passing certain parameters in the URL request of the PDF.

To hide the toolbar one needs to add the parameter toolbar and set its value to 0 to hide it or to 1 to show it. The same can be done for the navigational panes, which are identified by the parameter navpanes.

An URL requesting a PDF without displaying the toolbar and navpanes should look like this:
http://partners.adobe.com/public/developer/en/acrobat/PDFOpenParameters.pdf#toolbar=0&navpanes=0

Thanks Rob :)





Changing the “favicon” of JBoss

20 05 2009

This post is about changing the favicon of  the JBoss application server that comes with the Adobe LiveCycle ES Turnkey installation.

Changing the “favicon” for all servlets in JBoss

To change the “favicon” for all servlets in JBoss one must follow the following steps:

  1. Create an icon of 16 x 16 pixels and name it “favicon.ico” (MSPaint can be used for this);
  2. Navigate to the folder “<root of your JBoss installation*>\server\all\deploy\jbossweb-tomcat55.sar\ROOT.war” and replace the “favicon” with the one you created in step 1;
  3. Restart your JBoss application server;
  4. (Optional) You might need to clear the cache of your browser

(Note: MSIE6 has some difficulties in retrieving and caching a changed “favicon”

* Normally this would be: “C:\Adobe\LiveCycle8.2\jboss

Changing the “favicon” for an HTML page

In this case one has an HTML page, that one wants to display with a different “favicon”. To achieve this one needs to perform the following:

  1. Create an icon of 16 x 16 pixels and name it “favicon.ico” (MSPaint can be used for this);
  2. Navigate to the root of your site and place the “favicon” in there;
  3. Between the <HEAD>-tags of your HTML page, one can add the following code:

<link rel="shortcut icon" href="<relative path to the root of the website>/favicon.ico" type="image/x-icon" />

Code 1: Adding a “favicon” to an HTML page

Hope this works for you, like it has for me ;)





Uploading a file with Adobe Flex to a Java Servlet

8 05 2009

This post is about uploading a file using an Adobe Flex application to a Java Servlet using Apache Commons’ FileUpload.

Adobe Flex application

Let’s start with the Adobe Flex application. This application is quite simple and can be found in any tutorial about Adobe Flex’s capability of uploading files. The code below is all one needs.

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”vertical”><mx:Script>
<![CDATA[
import flash.net.FileReference;

private var fileRef:FileReference = new FileReference();
private var servletTarget:URLRequest = new URLRequest("<your servlet's location comes here>");

private function fileBrowse():void {
fileRef.addEventListener(Event.SELECT, onSelect);
fileRef.addEventListener(ProgressEvent.PROGRESS, progressHandler);
uploadStatus.text = "Browsing the File System";
fileTitle.text = "";
description.text = "";
fileLocation.text = "";
fileRef.browse();
}

private function onSelect(event:Event):void {
uploadStatus.text = "File selected";
fileLocation.text = fileRef.name;
}

private function progressHandler(event:ProgressEvent):void {
var percentLoaded:Number = Number((event.bytesLoaded / event.bytesTotal) * 100);
uploadStatus.text = "The file is " + percentLoaded + "% loaded";
}

private function fileUpload():void {
uploadStatus.text = "Uploading....";
var menuURLVars:URLVariables = new URLVariables();
menuURLVars.fileTitle = fileTitle.text;
menuURLVars.description = description.text;
servletTarget.method = URLRequestMethod.POST;
fileRef.upload(servletTarget);
}
]]>
</mx:Script>

<mx:Panel title=”Uploader”>
<mx:Text text=”Manual:&#xd;Step 1. Enter a title for the file&#xd;Step 2. Enter a description for the file&#xd;Step 3. Click the ‘Browse’ button to search the file that one wants to upload&#xd;Step 4. Click the ‘Upload’ button to upload the file to the server” width=”100%”/>
<mx:Form>
<mx:FormItem label=”File title” required=”true”>
<mx:TextInput id=”fileTitle” width=”300″/>
</mx:FormItem>
<mx:FormItem label=”Description” required=”true”>
<mx:TextArea id=”description” width=”300″/>
</mx:FormItem>
<mx:FormItem label=”File to upload” direction=”horizontal” required=”true”>
<mx:TextInput id=”fileLocation” width=”300″ editable=”false” color=”#001234″/>
<mx:Button id=”browseButton” label=”Browse” click=”fileBrowse()”/>
</mx:FormItem>
<mx:FormItem label=”">
<mx:Button id=”uploadButton” label=”Upload” click=”fileUpload()”/>
</mx:FormItem>
<mx:FormItem label=”Upload status”>
<mx:Label id=”uploadStatus” text=”Select a file to upload”/>
</mx:FormItem>
</mx:Form>
</mx:Panel>

</mx:Application>

Code 1: uploader.mxml

As one can see in the code above, all one needs is an instance of the flash.net.FileReference class. In this example we use its method browse to open a file browse dialog at the client side and its method upload to upload the selected file to the servlet, which location is specified by an instance of the flash.net.URLRequest class. Because we want to upload a file, we need to set the URLRequest’s attribute method to URLRequestMethod.POST and pass the URLRequest instance to the FileReference’s method upload, when starting to upload the file.

Java Servlet

In this example we use the Eclipse IDE.

On the server side we need to implement a Java servlet, which will handle the uploaded file by the Adobe Flex application. We start by creating a new Dynamic Web Project in Eclipse. In the source folder we add a new class ProcessFileUpload, which extends HttpServlet and belongs to the package flex.samples.servlets. The source code for the class ProcessFileUpload is shown below.

package flex.samples.servlets;

import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.util.List;
import java.util.Iterator;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;

import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;

/**
* This class provides functionality to handle an uploaded file.
* This class uses code provided by Apache
*
* @author geert.zijlmans
*
*/
public class ProcessFileUpload extends HttpServlet {

private static final long serialVersionUID = 1L;

/**
* Default constructor.
*/
public ProcessFileUpload() {
// TODO Auto-generated constructor stub
}

/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(request, response);
}

/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// Check that we have a file upload request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);

if (isMultipart) {
// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory();

// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);

// Parse the request
List /* FileItem */ items = upload.parseRequest(request);

// Process the uploaded items
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();

if (item.isFormField()) {
processFormField(item);
} else {
processUploadedFile(item);
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}

private void processFormField(FileItem item) {
String name = item.getFieldName();
String value = item.getString();
System.out.println(“Item name: ” + name + ” ; value: ” + value);
}

private void processUploadedFile(FileItem item) throws Exception {
String fieldName = item.getFieldName();
String fileName = item.getName();
String contentType = item.getContentType();
boolean isInMemory = item.isInMemory();
long sizeInBytes = item.getSize();

boolean writeToFile = true;
if (sizeInBytes > (5 * 1024 * 1024)) {
writeToFile = false;
}
// Process a file upload
if (writeToFile) {
File uploadedFile = new File(“<directory on the server’s file system>“+ fileName);
if (!uploadedFile.exists()) {
uploadedFile.createNewFile();
}
item.write(uploadedFile);
}
else {
System.out.println(“Trying to write a large file.”);
}

}
}

Code 2: ProcessFileUpload.java

After creating the class ProcessFileUpload we need to make it visible as a servlet. To make this servlet visible we need to change the contents of the web.xml file. The change is shown in bold in the example below.

<?xml version=”1.0″ encoding=”UTF-8″?>
<web-app id=”WebApp_ID” version=”2.4″ xmlns=”http://java.sun.com/xml/ns/j2ee” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd”>
<display-name>
my-servlet</display-name>

<servlet>
<description>
</description>
<display-name>ProcessFileUpload</display-name>
<servlet-name>ProcessFileUpload</servlet-name>
<servlet-class>flex.samples.servlets.ProcessFileUpload</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ProcessFileUpload</servlet-name>
<url-pattern>/ProcessFileUpload</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>

Code 3: web.xml

If one wants to compile this Dynamic Web Project, one will need to add the following API’s to the classpath of the project:

After exporting the project as a .war file one can deploy this .war file on one’s Web Application Server (e.g. JBoss).

Testing the solution

The servlet should be active now, so let us test our Adobe Flex application by running it in Adobe Flex Builder 3 Pro. The output in de browser should look like the picture below.

Uploader Flex Application

Uploader Flex Application

One now can enter a file title, enter a file description, point to a file to be uploaded and finally upload the file to the servlet.

This was all :)





Adobe Acrobat Reader and Adobe LiveCycle Reader Extensions

4 05 2009

This post is for the people that don’t understand the use of Adobe LiveCycle Reader Extensions.

Adobe LiveCycle Reader Extensions is a component of the Adobe LiveCycle platform. This component is necessary when one wants their PDF forms to use hidden features in Adobe Acrobat Reader, that normally are only available in the Adobe Acrobat product. The following hidden features can be activated using the Adobe LiveCycle Reader Extensions Web application, which can be found under (http://<name and port of your Adobe LiveCycle server>/ReaderExtensions/):

  • Basic form fill-in (including the capability of saving the form’s data)
    • Import and export form data
    • Submit outside Web browser
    • Database and Web Service connectivity
    • Add, delete and change form fields
    • Create pages from templates
  • 2D barcode decoding
  • Digital signatures
  • Commenting
    • Online commenting
  • Embedded file attachments

The component Adobe LiveCycle Reader Extensions is activated within the Adobe LiveCycle Platform by a license. The price of this license is quite high. Because of this price some clients don’t want to invest in this wonderful component, which makes a PDF form even more rich than it already is. In most cases clients want the basic functionality that the data of the PDF form can be saved with the form offline and submitting the form’s data from within the Adobe Acrobat Reader. A workaround for this problem involves making a personalized portal from which a person can use his/her PDF forms, which of course all is done online. Or one just looks for another technology to accomplish the same that you wanted to do with the PDF form.

Submitting a PDF form is another topic which is important for the use of Adobe LiveCycle Reader Extensions. One is able to submit a PDF form without Reader Extensions from within a browser, but only in the following formats:

  • XML
  • XDP (XML + all nodes in the form that have their binding set to “normal”)

If one wants to use PDF as a format  and the possibility of submitting from within an Adobe Acrobat Reader, one will need to “extend” the form with Reader Extensions.

This wraps it up for the use of Adobe LiveCycle Reader Extensions for PDF forms which are opened by Adobe Acrobat Reader.