Created

20 July 2009

Requirements

Prerequisite knowledge

A basic knowledge of Flex, Flex Builder, and LiveCycle ES is needed.

User level

Beginning

Flex is used to develop engaging interfaces, and Adobe LiveCycle ES is used to automate complex processes. Together they can be used to create applications that are both useful and enjoyable. Getting the two products to work together isn't difficult, but it does require some knowledge of how both technologies work.

The Document object is one of the fundamental building blocks of the LiveCycle ES product; it is used to hold PDFs, XML data, and binary information. Unfortunately there is no similar object on the Flex side. Flex has a FileReference object that allows developers to point to binary data, but it does not permit direct access to that data. Using the DocumentReference object (from the adobe-remoting-provider.swc file which is included in the LiveCycle API) and the LiveCycle Remoting upload servlet (lcfileupload) developers can easily pass documents between applications built in these two very different development environments.

In this article, I'll cover the steps needed to implement a simple process that uploads, processes, and returns a Document object using Flex and LiveCycle ES.

Uploading files from Flex to LiveCycle ES

Since processes quite often begin with user requests, I'll start with the Flex end of the system. I'll build a simple interface that an operator can use to upload a file (any file) to a LiveCycle process.

Here are the basic steps:

  1. Add a button that will bring up a file browse dialog box
  2. Use a FileReference object to point to the document's location
  3. Use the LiveCycle Remoting upload servlet (which is part of the LiveCycle ES system) to upload the file to the server side.
  4. Use a DocumentReference object to pass the uploaded file's URL to a LiveCycle process.

Start by creating a new Flex project using Flex Builder or the Flex Builder 3 Eclipse Plug-in. Add a button to the project and add a click event that will call a local function:

<mx:Button id="selectBtn" label="Select Files" width="105" click="uploadFile()"/>

Next you'll need to write some script to make things work. Add a script tag to your Flex application and add FileReference and FileReferenceList object instances. While you are at it, you can create the function that the button calls.

<mx:Script> <![CDATA[ private var fileRef:FileReference = new FileReference(); private var fileRefList:FileReferenceList = new FileReferenceList(); private function uploadFile():void { } ]]> </mx:Script>

I can use the FileReferenceList object's browse function to bring up a file browse dialog box. I'll also need to handle the resulting event, which is dispatched when Flex determines that the user is done with the browse window.

private function uploadFile():void { fileRefList.addEventListener(Event.SELECT, selectHandler); var docFilter:FileFilter = new FileFilter("PDF Documents","*.pdf"); fileRefList.browse([docFilter]); } private function selectHandler(event:Event):void {}

Next is the fun part. I pull out each file from the FileReferenceList object and upload it to the LiveCycle ES servlet. The servlet will return a URL to that uploaded file, which I will use when I make the call to the LiveCycle ES process.

I will need to add a few new global variables to the application:

private var fileName:String; private var pendingFiles:Array; private var urlRequest:URLRequest = new URLRequest("http://myserver:8080/remoting/lcfileupload"); private var uploadedDocURL:String;

Then add the functions to perform the file uploads:

private function selectHandler(event:Event):void { pendingFiles = new Array(); for (var i:uint = 0; i < fileRefList.fileList.length; i++) { fileRef = FileReference(fileRefList.fileList[i]); addPendingFile(fileRef); } selectBtn.enabled = false; createBtn.enabled = true; } private function addPendingFile(fileRef:FileReference):void { pendingFiles.push(fileRef); fileRef.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,completeHandler); fileRef.upload(urlRequest); } private function completeHandler(event:DataEvent):void { //in this case I am only storing one value //if I wanted multiple files then I could use an array to //store the returned URLs. In this case only the LAST one will be kept. uploadedDocURL = event.data; }

Calling a LiveCycle ES process using a remote object

Now I will make the call to LiveCycle ES and pass the Document object using the Flex DocumentReference object. I'll need to create a remote object that references the LiveCycle ES service that I will call later. The "GenericProcess" that is specified in the destination attribute is the name of the LiveCycle ES service that is being called. In this case GenericProcess just echo's the input Document object.

<mx:RemoteObject id="ro" destination="GenericProcess" result="resultHandler(event)" fault="faultHandler(event)"/>

Since the remote object needs to communicate with the server, I need to use a ChannelSet object. This will also allow me to set the user name and password that LiveCycle ES requires. In this case I set the channel set information when the application initializes. Remember to replace myserver with the actual name of your LiveCycle ES server.

private function initApp():void{ var cs:ChannelSet= new ChannelSet(); cs.addChannel(new AMFChannel("my-amf", "http://myserver:8080/remoting/messagebroker/amf")); ro.setCredentials("administrator", "password"); ro.channelSet = cs; }

To pass the uploaded document(s) to the LiveCycle service I create a DocumentReference object. I then use the URL returned by the servlet to populate that object. The InputDocument string is the name of the input parameter in the LiveCycle process. In this case the GenericProcess that is being called only takes in one (and only one) Document object. If your process took more Document parameters, or a List of Documents then this is where you would populate those variables.

private function callLC():void{ CursorManager.setBusyCursor(); createBtn.enabled = false; var inDoc:DocumentReference = new DocumentReference(); inDoc.url = uploadedDocURL; inDoc.referenceType = DocumentReference.REF_TYPE_URL; var params:Object = new Object(); params["InputDocument"] = inDoc; ro.invoke(params); }

Handling the response

This LiveCycle ES process will also return a Document object. The Flex application will need to be able to do something with the returned object, which contains a URL to the resulting document. In this case I display the returned URL on the screen using a label object that the user can click.

From the returned event object, I use the LiveCycle output process variable name to access the document object. For this example, that variable is pdfOutput:

private function resultHandler(event:ResultEvent):void { var docRef:DocumentReference = event.result.pdfOutput; //last part of this must be the same as the LC output variable pdfUrl.htmlText = "<u><a href='" + docRef.url + "'target='_blank'>Generated PDF</a></u>"; pdfUrl.selectable = true; CursorManager.removeBusyCursor(); }

Where to go from here

That's it! You've now uploaded, processed, and received a returned Document object using a Flex front end.

I recommend that you have a look at the following documents: