Remember your imports!

One of the most common configuration errors people make is to forget to import the necessary interfaces for a bundle:

<manifest xmlns="http://ns.adobe.com/gravity/manifest/1.0"> 
 
  <interface location="foo_interface.swf"> 
    <exports> 
      <export name="com.example.IFoo"/> 
    </exports> 
  </interface> 
 
  <bundle location="some_bundle.swf"> 
    <imports>
      <import name="com.example.IFoo"/>
    </imports>
  </bundle> 
  
  <bundle location="other_bundle.swf"> 
    <!-- forgot to import IFoo -->
  </bundle> 
  
</manifest>

Such errors may not be immediately apparent as some other bundle that happens to be loaded earlier may happen to import the same interfaces: so long as the interface SWF happens to be loaded before any bundles that require it are loaded, everything will work, since interface SWFs are loaded into the root ApplicationDomain. However, since bundles are loaded in parallel when possible, this can lead to race conditions where the failure is very intermittent since so many different factors come into play: operating system, browser and browser version, network topology, contents of the browser cache, and more. You can experiment with the effects of load ordering with this multiple ApplicationDomain demo.

If you have this issue, it will typically manifest as a failure to find the service that wasn’t imported. If you find yourself thinking, “I can see that the service is registered, why is my lookup failing?” then this is probably the problem.

If you optimize your bundles by excluding the service interfaces, it will show up as a VerifyError, which makes it a little easier to diagnose.

Note that the same issue can occur between interface SWFs if one interface SWF depends on another. Interface SWFs also need to declare imports if they depend on interfaces defined in other interface SWFs:

<manifest xmlns="http://ns.adobe.com/gravity/manifest/1.0"> 
 
  <interface location="foo_interface.swf"> 
    <exports> 
      <export name="com.example.IFoo"/> 
    </exports> 
  </interface> 
 
  <interface location="bar_interface.swf"> 
    <exports> 
      <export name="com.example.IBar"/> 
    </exports> 
    <imports>
      <!-- IBar has methods or properties that reference IFoo,
           or IBar extends IFoo, so we need to import IFoo -->
      <import name="com.example.IFoo"/>
    </imports>
  </interface> 
</manifest>

CRX and WebDAV

If your Flash Builder project is setup in CRX and using a WebDAV client such as NetDrive (http://netdrive.net/) to manage the Gravity source and content, Flash Builder may throw the following error to the Problems view:

   unable to load SWC gravity_di_loader_lib.swc   

To fix this simply modify the encoding used by the WebDAV client.  In NetDrive:

1. Click the Advanced button.
2. Select ‘UTF-8′ from the encoding drop list and choose Ok.
3. Re-build or clean the Flash Builder project.

 

Quick pointer to the documentation

The not necessarily obvious path to the Client Component Framework documentation is to go here http://help.adobe.com/en_US/enterpriseplatform/10.0/AEPDeveloperGuide/index.html and then click on the ADEP Client Component Framework link at the bottom of the left-hand list.

Propagation of manifest properties

I recently received a question about manifest properties… I thought it would be useful to share the question and answer here.  The question:

I guess this is more of a philosophical question and probably a lack of personal OSGi knowledge but here goes.  Why is the ManifestParseContext the same from manifest to manifest, or at least the properties available the same? If my application loads a manifest at some point later, why is that manifest load subject to all the prior manifest properties?  It would seem like very <manifest></manifest> would be “isolated” from others but, that doesn’t appear to be the case.

Here is the explanation I gave:

OSGi does not have a concept of properties like Gravity. This is a Gravity feature.

The properties are actually isolated, just not in the manner that you’re thinking… if I have this in the initial manifest

    <manifest xmlns="http://ns.adobe.com/gravity/manifest/1.0">
      <bundle location="alice.swf"/>
      <property name="alpha" value="apple"/>
      <include location="other-manifest.gxml"/>
      <property name="delta" value="date"/>
      <bundle location="carol.swf"/>
    </manifest>

and other-manifest.gxml contains

    <manifest xmlns="http://ns.adobe.com/gravity/manifest/1.0">
      <property name="bravo" value="banana"/>
      <bundle location="bob.swf"/>
      <property name="bravo" value="blackberry"/>
      <property name="charlie" value="cranberry"/>
    </manifest>

then the alpha, bravo (with a value of “blackberry”), charlie, and delta properties are visible for the definition of the carol.swf bundle and for any manifests loaded from the carol.swf bundle. Only the alpha and bravo (with the value of “banana”) properties are visible to the bob.swf bundle, and only those properties will be propagated to any calls to installBundlesFrom* from bob.swf (the bob.swf bundle is isolated from later changes). If installBundlesFrom* is called from alice.swf, none of these properties will be defined for that manifest.

In other words, each bundle captures the properties that were valid at the point of definition of that bundle, and the captured values of those properties are propagated in subsequent calls to installBundlesFrom* from within each bundle. This avoids the need to define properties like debug in every single manifest while providing predictability and traceability. If the properties were simply global it’d be difficult to figure out how a property ended up getting set: it could have happened anywhere, and the ordering of independent loads would be significant.

HelloGravity Sample Application

The sample application “HelloGravity” included with this post is a small master-detail application that highlights some of the key features of the ADEP Client Component Framework, also known as Gravity.

Installing and Building the HelloGravity Application

Download the project source: HelloGravity.zip

Note: This sample requires FlashBuilder 4.5 and the Flex 4.5.0 SDK.

  • Download “HelloGravity.zip” and unzip it into a directory of your choice.
  • Open FlashBuilder, and create a workspace that is located at the root of the application above.
    • File -> Switch Workspace -> Other…
    • Click “Browse” and select the root directory for the HelloGravity application
    • Ensure the default Flex SDK is version 4.5.0
  • Import the 5 HelloGravity projects into the workspace
    • Select “File -> Import…” then “General->Existing Projects into Workspace” – click “Next”
    • Browse to the root directory of the sample – click “Choose”
    • Select the 5 HelloGravity projects – click “Finish”
  • Run the “HelloGravity_main” application
    • All applications should compile cleanly. By having the FlashBuilder workspace at the root of the projects, the inter-project dependencies should be satisfied.
    • The application should launch in the browser showing a simple list that can be used to select an image and display information about it.
    • Note that modifying the “Title” field in the editor will also cause the corresponding label in the list to change.

Structure of the application

The application is made up of three visual components (UiServices), the “Header”, “List”, “Editor”. They are backed by non-visual bundles to manage the application domain model and data services.

The following is a simplified diagram of the application structure:

HelloGravity Application Structure

HelloGravity Application Structure

Each of the application UIServices and bundles are implemented independently, and are in the projects as follows:

HelloGravity_main Project

This project holds the UIService modules that make up the visual portions of the application. Each of the following modules generate their own SWF when compiled, and each has a configuration (gxml) file in the manifest directory. These modules could also be compiled with independent projects, and in a large system with independent groups working on them it would be normal to separate them.

HelloGravity_main_module:  the top level contain that pulls together the header, list and editor UiServices

HelloGravity_header_module: the header for the application containing the title and logo

HelloGravity_list_module: the list control. Note that the list has no linkage or knowledge of the editor

HelloGravity_editor_module: the editor control. Note that the editor has no linkage or knowledge of the list control

HelloGravity_domain_bundle and HelloGravity_domain_interface Projects

These projects hold the domain classes and their corresponding interfaces. The domain classes represent the list of image data that is backing the application.

HelloGravity_dataService_bundle and HelloGravity_dataService_interface Projects

These projects implement the data persistence tier for this application. The interface API is independent of the implementation, and could be used with a server. However, as this is a standalone sample, this implementation simply creates the data list locally and returns the data. However, it is simulating the asynchronous nature and serialization of data that would be present in a real system that is connected to a server.

Video Tutorials

A series of videos is available on the ADEP developers channel on YouTube that describe the development of this application and the concepts behind it.

YouTube Channel: Client Component Framework (Gravity) Development on ADEP

Video 1Setting up the Gravity Development Environment
Learn how to set up a FlashBuilder development environment for use with Gravity. It explains where to find Gravity, how to configure the initial bootstrapping of the application, and how many of the other libraries are used.

Video Part 1: Setup the Gravity Environment –  Part 1
Video Part 2: Setup the Gravity Environment – Part 2

Video 2Develop a Simple UiService
Learn how to create a Module Bundle and a simple UI Service component to add a header component to the application.

Video 3Building a Master-Detail Application with UiServices
Create a simple master-detail application that consists of two UIServices, one containing a summary list and the other the detail information. These two UIServices are wired to an existing domain service.

Video 4Create a domain model and domain service
This session covers the concept of a domain model service, and interface bundles. It also explains how Gravity creates and uses application domains and how this enables applications to be build using different Flex SDK’s.

Video 5Create a data service and link to the application
This session covers a data service that backs a domain model. It discusses the asynchronous nature of this service and how the binding mechanisms of Gravity and Flex simplify application development. It also covers how to link the FlexBuilder library projects as RSL’s such that the needed SWF is available at runtime.