Prerequisite knowledge

Previous experience with LiveCycle Enterprise Suite and Flash Builder will help in making the most of this article.

User level


Tetrapod is a lightweight demo application built with Adobe AIR and Adobe LiveCycle Enterprise Suite to assist users through complex, forms-intensive processes. It connects a library of Adobe forms managed by an Adobe AIR application to a process and content management back end. The goal of this project is to provide a demonstration and starting point for developers to quickly build their own Adobe AIR application connected to Adobe LiveCycle Process Management. Flex developers—even those who are just beginning—should be able to download, install, and customize this application in hours. To facilitate this and illustrate the potential of simplifying customer experiences in sophisticated forms-driven interactions, Tetrapod has intentionally been kept simple. This project relies on Adobe technologies, making it easier to explore, implement, and adapt to create a solution your organization would find valuable immediately. Tetrapod is freely available for you to incorporate into your own projectsthere is no enterprise support provided and no warranty on the code made available through this initiative.

Note: The sample file includes the source to the AIR application, the compiled and installable AIR application itself, and the LiveCycle archive file.

For more advanced projects that solve business specific problems, take a look at the Adobe Solution Accelerators program. Solution Accelerators are fully tested and supported frameworks that bundle together all of the underlying LiveCycle Enterprise Suite modules required to develop each solution, together with solution-specific components, called building blocks, ready for use in production applications.

Typical usage scenarios for Tetrapod

There are three broad categories of usage scenarios for the Tetrapod application:

  • Off-the-shelf demo. Tetrapod can be used as an off-the shelf demonstration application for presenting Adobe AIR and LiveCycle integration. You can use the default skin set along with existing forms examples or add your own forms inside Tetrapod, with no changes to the project source code.
  • Customized demo. You can customize Tetrapod for a specific customer by modifying the skin of the Adobe AIR client component and, if needed, developing new electronic forms. By tailoring the application’s look and feel and linking it with custom LiveCycle processes, you can deliver a unique experience that is aligned with your customer’s own business environment and context. The skin modification requires minor code modifications, and a customer-specific demo will require replacement of the example LiveCycle process.
  • Set of code samples in one bucket. Several partners and customers are already using Tetrapod as inspiration for highly customized forms-intensive applications. In developing these applications, Tetrapod served as a set of code samples that helped developers to solve common challenges, including embedding PDFs in an Adobe AIR application or linking an Adobe AIR application with Adobe LiveCycle components such as Process Management or Content Services.

Tetrapod functionality

Without any modification, the Tetrapod client AIR application enables the end user to:

  • Select an appropriate form
  • Fill in the form (in PDF or SWF format)
  • Submit form data to LiveCycle Process Management in a sample approval process
  • Retrieve a response
  • Review the content of the application’s documents library such as PDF files and video files

The Tetrapod back-end is responsible for:

  • Enabling back office users to approve form data from the Tetrapod AIR application (with LiveCycle Workspace, for example)
  • Enabling back office users to approve form data from the Tetrapod AIR application (with LiveCycle Workspace, for example)
  • Storing the documents exchanged with the Tetrapod AIR application using LiveCycle Content Services on the server side.

Tetrapod technical architecture

Tetrapod uses the Swiz framework for dependency injection and application event handling. For non-skinnable components, the presentation model pattern is applied. However, even if you’re unfamiliar with dependency injection and the presentation model pattern, it shouldn’t be hard to use and customize Tetrapod. The application is modular, and the design separates application layout, core functionality, and components that manage incoming and outgoing data (see Figure 1). Deployments for the desktop and mobile environment are also separated.

Tetrapod is designed for adaptability and agility. You can use its structure as an initial foundation and tailor it to fit specific project scenarios. In fact, the present structure has already undergone several improvements thanks to partner and customer feedback, and it’s very likely that it will continue to evolve in the future.

In Figure 1, Core represents the application behavior and central part of the project. DataSource is responsible for data handling. Connectors link the application with external systems. Skin represents the application’s look and feel. These components are combined in a desktop application, but Tetrapod can be adapted to work in a mobile environment if needed.

Controllers make up the largest component of the project core; they include:

  • navigation controller for managing the screen flow logic in the application
  • update controller for managing the application update process
  • startup controller for managing the application startup process
  • skin controller for loading the appropriate skin
  • notification controller for managing pop up messages
  • sound controller for managing sounds in the application

The Controllers package is the right place to modify application behavior. For example, you would make changes to this package if you want the application to start up only when an Internet connection is available or if you want to add a completely new screen to the application.

The small but important Event package is also within the Core component. It manages events related to documents, the startup process, and navigation. By default Tetrapod manages only document open, save, submit, close, select, and delete events. If you need to trace something else —for example, if you would like to trace the mouse position–then you will need to change the code in the Event package.

The Model package defines many basic application objects, including documents and document conversations. To add a new type of document in the application, you would likely modify the document class or add a new type of supported asset. Additionally, the model and state of MainView, which manages the screen display, is in the Model package (see Figure 2).

The View package in the Core component includes screens and screen components. Screen components represent view elements of the screen such as the top bar, bottom bar, and document display window. Screen components are assembled into screens by the skin, which defines the layout and design.

The small Data package maintains the interfaces implemented in the DataSource component. DataSource provides data from the connectors. It also manages the application’s offline behavior using a built-in persistence mechanism. It can be used as it is or it may be replaced by a custom data source, for example by integrating Adobe LiveCycle Data Service 3.1 capabilities. The DataSource defines how document repositories are accessed, how information (including forms and documents) are retrieved, and what happens when a form is submitted. By default, the application in online mode downloads content from the repository if it is not cached. In offline mode, only previously downloaded content is available. Likewise, in online mode, documents and forms are submitted immediately. In offline mode, however, submitted documents and forms are stored until a connection is restored.

Connector components are responsible for the communication between Tetrapod and external data providers such as a business process management system. By default Tetrapod is delivered with the Adobe LiveCycle Process Management connector. However, you can create new ones and connect Tetrapod to any process platform. In fact, at a recent SAP user conference, Tetrapod was presented working with the SAP NetWeaver platform.

Skinning Tetrapod

A principal design requirement for Tetrapod was support for easily customizing the look and feel of the entire application via the new skinning mechanism introduced in Adobe Flex 4. The skin is a separate, interchangeable module, which defines the visual aspects of the application.

While there are many great tutorials on skinning Spark components, skinning your application can tricky when there are many interrelated components. Most non-trivial applications have multiple custom components, which may contain other custom components. When you need to support multiple skins, which look completely different and must be interchangeable, it can be a challenge.

As an example, consider one of the principal components used in Tetrapod, called HomeScreen. This is a central screen of the application that is displayed after the Tetrapod starts (see Figure 3).

HomeScreen is just an MXML component containing a set of buttons that lead to other screens of the application. One of the most intuitive approaches to implementing this would be to place all the state, logic, and children structures in component MXML files and the visual part in a corresponding skin file (see Figure 4).

While this approach is elegant and component nesting is well-defined in a single project (you can easily Ctrl+Click to open a nested component in Flash Builder), there is another approach, described below, which can be taken when skins not only differ in color and layout but also some structural elements.

For example the HomeScreen color, layout, and structure can be changed using Tetrapod skins. The standard skin has an animated circle menu built with Adobe Flash CS5. In contrast, the healthcare skin has custom buttons built with bitmap icons and FXG (see Figure 5).

The gaming skin doesn’t have any buttons at all; instead it has a "Forms Pod" logo and a navigation menu at the top (see Figure 6).

Though the screens are visually very different, they all share the same functionality–enabling the user to navigate to other application screens by clicking on a UI component. Because a requirement of Tetrapod is to support the addition of new skins without modifying the main application or even having its source code, it uses Flex skinning a little differently.

The main component file contains only the logic of the home screen.


<?xml version="1.0" encoding="utf-8"?> <!--- Home screen displayed after application startup --> <s:SkinnableContainer xmlns:fx="" xmlns:s="library://" xmlns:mx="library://" xmlns:screens="com.Adobe.demo.Tetrapod.view.screens.*"> <fx:Script> <![CDATA[ import com.Adobe.demo.Tetrapod.controller.NavigationController; [Inject] public var navigationController:NavigationController; public function showFormsDirectory(event:Event = null):void { navigationController.showFormsDirectory(); } public function showMyForms(event:Event = null):void { navigationController.showMyForms(); } public function showDocumentsLibrary(event:Event = null):void { navigationController.showDocumentsLibrary(); } public function showSettings(event:Event = null):void { navigationController.showSettings(); } ]]> </fx:Script> </s:SkinnableContainer>

As you can see, the logic is straightforward. This particular screen could be implemented in ActionScript, but we decided to use MXML for all screens as it makes declaring states and bindings much easier and more readable. Notice that the code doesn’t contain a skinClass attribute. This is defined in the CSS file of the skin project.

All visual components and graphics are placed inside the skin file.

HomeScreenSkin.mxml in standard skin

<?xml version="1.0" encoding="utf-8"?> <s:Skin xmlns:fx="" xmlns:s="library://" xmlns:components="com.Adobe.demo.Tetrapod.view.components.*" xmlns:ns1="*" width="100%" height="100%" creationComplete="init();"> <fx:Metadata> [HostComponent("com.Adobe.demo.Tetrapod.view.screens.HomeScreen")] </fx:Metadata> <fx:Script> <![CDATA[ import com.Adobe.demo.Tetrapod.skins.standard.util.Icons; private function init():void { mainMenu.circleMenu.formsDirectoryButton.addEventListener(MouseEvent.CLICK, hostComponent.showFormsDirectory); mainMenu.circleMenu.myFormsButton.addEventListener(MouseEvent.CLICK, hostComponent.showMyForms); mainMenu.circleMenu.documentsLibraryButton.addEventListener(MouseEvent.CLICK, hostComponent.showDocumentsLibrary); mainMenu.circleMenu.settingsButton.addEventListener(MouseEvent.CLICK, hostComponent.showSettings); } ]]> </fx:Script> <s:states> <s:State name="normal" /> <s:State name="disabled" /> </s:states> <s:Rect width="100%" height="100%"> <s:fill> <s:RadialGradient spreadMethod="pad"> <s:GradientEntry color="#484848"/> <s:GradientEntry color="#1E1E1E"/> </s:RadialGradient> </s:fill> </s:Rect> <s:Group width="100%" height="100%"> <ns1:MainMenu id="mainMenu" verticalCenter="70" horizontalCenter="80"/> <s:BitmapImage source="{Icons.AdobeLogoTag}" bottom="0" right="10"/> </s:Group> </s:Skin>

HomeScreenSkin.mxml in healthcare skin

<?xml version="1.0" encoding="utf-8"?> <s:Skin xmlns:fx="" xmlns:s="library://" xmlns:components="com.Adobe.demo.Tetrapod.view.components.*" width="100%" height="100%"> <fx:Metadata> [HostComponent("com.Adobe.demo.Tetrapod.view.screens.HomeScreen")] </fx:Metadata> <fx:Script> <![CDATA[ import; ]]> </fx:Script> <s:states> <s:State name="normal" /> <s:State name="disabled" /> </s:states> <s:Group verticalCenter="-30" horizontalCenter="40"> <s:layout> <s:VerticalLayout gap="15"/> </s:layout> <components:HomeScreenButton label="PLANS &amp; FORMS" description="Browse and fill forms" icon="{Icons.formsDirectoryIcon}" click="hostComponent.showFormsDirectory()"/> <components:HomeScreenButton label="MY FORMS" description="Manage drafts and conversations" icon="{Icons.myFormsIcon}" click="hostComponent.showMyForms()"/> <components:HomeScreenButton label="HEALTH CONNECT" description="Browse training and marketing materials" icon="{Icons.documentsLibraryIcon}" click="hostComponent.showDocumentsLibrary()"/> <components:HomeScreenButton label="SETTINGS" description="Manage your individual preferences" icon="{Icons.settingsIcon}" click="hostComponent.showSettings()"/> </s:Group> </s:Skin>

Notice that both skins above contain references to other custom components: MainMenu (the external Flash component) in the standard skin and four HomeScreenButton components in the healthcare skin.

This approach (see Figure 7) gives more flexibility in creating the UI components’ structure because child custom components are referenced from the skin class, which allows minor structural changes by simply swapping the skin. Flex 4 skinning plays an important role in this approach. Terapod is a great example of using LiveCycle and PDF forms in the context of AIR based applications and Flex skinning. Using easily adaptable custom skins, you can develop client-oriented applications based on Tetrapod and enhance the end user experience. The skins presented here provide insight into how a different look and feel (based on different topics or the corporate identity of the client, for example) can be applied to Tetrapod based applications. When designing and adapting custom skins for Tetrapod, keep in mind that the AIR windows that will present the PDF forms using the Acrobat Reader plug-in cannot be transparent. Also strive to keep all user interface elements coherent in the context of the overall look and feel and make user interface elements of the same type recognizable to the user.

Forms in Tetrapod

A key feature of Tetrapod is the ability to work with different types of content. For data input you can use PDF, SWF, or HTML.

This section focuses on PDF forms created with Adobe LiveCycle Designer. The Form Bridge object, a standard LiveCycle Designer component, is used to enable any given PDF form for use with Tetrapod. This means that just by dragging a Form Bridge object on your existing form, you can use all the forms-related features of Tetrapod, including managing drafts and submissions. The Form Bridge object is available in the Custom category of the Object Library palette in LiveCycle Designer (see Figure 8).

It is also automatically placed in new forms created using Adobe LiveCycle Workbench when you select the From LiveCycle Workspace form submission option in the New Form dialog box (see Figure 9).

The Form Bridge object provides a set of JavaScript functions required to set up a message listening mechanism. Messages sent from the Flex application to the PDF form are translated to JavaScript function calls, which ultimately cause a response message to be sent. For Tetrapod, this is an ideal solution to provide such communication between the PDF form and the AIR application. When you drop this component on a newly created form, Adobe LiveCycle Designer creates a subform with a script object named ContainerFoundation_JS that contains all the required JavaScript (see Figure 10).

Now you are ready to load the prepared PDF form in your application. First, you must load it into an mx:HTML component from the HTML file, for example:

<html> <head> <title></title> <script language="javascript"> function loadDoc(path) { PDFArea.innerHTML = '<object id="PDF" height="100%" width="100%" type="application/pdf" data="PDFForm.pdf#toolbar=0"></object>'; var PDFObject = document.getElementById("PDF"); PDFObject.messageHandler = { onMessage: function(message) { receiveFromJS(message[0]); return true; }, onError: function(error, message) { alert("Error: communication with PDF failed!"); } }; } function sendMessage(message) { var PDFObject = document.getElementById("PDF"); PDFObject.postMessage(message); } </script> </head> <body> <div id="PDFArea" style="width: 100%; height: 100%;"> </div> </body>

Then you can load the PDF form by calling the JavaScript function loadDoc from Flex, for example:

pdfBridge = new PDFBridge(htmlLoader.window,pdfLoadedHandler); htmlLoader.window.loadDoc(pdfUrl); htmlLoader.addEventListener(,htmlRenderHandler);

Now you can access the wide set of operations that the Form Bridge object supports. For example, you can get and set form data for the entire form, get and set the value of a particular field, get a list of fields in the form, or submit form data by email. For a full list of Form Bridge operations look inside the FormBridge header in Adobe LiveCycle Designer (see Figure 11).

Messages that are sent to a Form Bridge script must be in the following format:


  • id is a number supplied by the requestor
  • requestName is the name of the command to perform
  • params are parameters for the command

The response for the command is returned in the following format:


  • id is the number that was supplied by the requestor
  • requestName is the name of the command performed
  • returnId is a string indicating success or failure
  • returnValue is the return value of the command if applicable

The most common use of the Form Bridge object in Tetrapod is retrieving XML data from a PDF form:

public function getData():void { if(pdfLoaded) { pdfBridge.getData(getDataHandler); } } private function getDataHandler(message:String):void { if(message != null) { var data:XML = new XML(message); var pdfEvent:PDFEvent = new PDFEvent(PDFEvent.PDF_FORM_DATA_RECEIVED); pdfEvent.xmlData = data; dispatchEvent(pdfEvent); } }

Here is the ActionScript function that calls Form Bridge commands directly:

override flash_proxy function callProperty(requestName: * ,... args):* { requestId++; if (args && args[args.length - 1] is Function) { requestsMap[requestId + "-" + requestName] = args[args.length - 1]; } var params:Array = [requestId.toString(),requestName.toString()]; for each (var arg:Object in args) { if (! arg is Function) { params.push(arg.toString()); } } pdfObj.pdfSendMessage(params); }

When creating Flex and HTML forms, a form creator has to include only two simple functions in the form files: setFormData and getFormData. In HTML, these functions are written in JavaScript and in Flex they are written in ActionScript. The function setFormData requires an XML string as an input parameter. After loading, the XML content is displayed in the form. The function getFormData returns XML data from a form to Tetrapod. The structure of the retrieved data is not defined; it depends on the form type.

Here is an example XML file:

data : XML = <data> <firstName>John</firstName> <lastName>Doe</lastName> </data>

And here are example get and set functions:

private function setFormData(xmlStr:String):void{ var xml ; XML = new XML(xmlStr); firstNameTextInput.text=xml.firstName; lastNameTextInput.text=xml.lastName; } private function getFormData():String{ var xml : XML = <data/> xml.firstName=firstNameTextInput.text; xml.lastName=lastNameTextInput.text; return xml.toXMLString(); }

Tetrapod connectivity with LiveCycle Content Services

Tetrapod uses Adobe LiveCycle Content Services as its storage mechanism. The server-side processes responsible for data management are built as short lived processes using LiveCycle Workbench. When the application requests data, it invokes a RemoteObject component, the request is processed, and data is returned to the application. There are also internal processes that manage the data synchronization between the Tetrapod AIR application and LiveCycle Content Services.

In the process shown in Figure 12, LiveCycle Content Services receives a request to list all available categories. In the first step, the list of available content spaces is retrieved using the foundation ContentService component. Then there is a check to see if any category is available. If yes, then a loop is used to convert every content space descriptor into a simple category object. After processing, this simple list of categories is passed back to the application.

Note that this process (like other processes used with Tetrapod) is created entirely in LiveCycle Workbench. No external components are used–only foundation elements. Submission of forms is also handled by LiveCycle Process Management. Any process can be attached to handle the submission. Processes can be system-centric or human-centric. For the Tetrapod AIR application, the user can see the results of the server-side processes as new elements in the conversation box. From a portability perspective, moving Tetrapod’s server components from one LiveCycle server to another requires administrative rights for LiveCycle Process Management and LiveCycle Content Services and the ability to import the LiveCycle archive file (.LCA) in the sample file.

Where to go from here

Tetrapod demonstrates a technology stack of front-end components and back-end services used to build a sample AIR application integrated with Adobe LiveCycle technology. You can use it as an out-of-the box demo, or customize it to fit customer specific requirements by changing the skin and behavior of the application.


A big thank you goes to Loni Kao, Bartlomiej Soin, Jakub Kaniewski, Tomasz Lichota, and Pawel Cichon for their contributions to the application.