Identificações

At a first glance, reading data files in Flex is easy. But sometimes things which seem simple (and should be simple!) actually prove to be tricky... I would like to share my experience in this area, hoping it may be of some help to others.

Additional requirement: cope with cases when translations are not available for all supported locales.

Also, allow adding a translation without modifying the source code of the app.

And (of course!), maximize performance and minimize bandwidth consumption for running over the web.

A solutionThe above requirements look quite analogous to those of the Flex mechanism for dealing with resource bundles for the localization of Strings in ActionScript or MXML, for which Flex provides already everything you need (see Using resources in Flex documentation). Furthermore, we do want a similar policy for loading localized data files as the one Flex uses for loading resource bundles for a given locale chain:

The Flex application uses the list of locales in the localeChain
property (of ResourceManager) to determine precedence when getting values from resource
bundles. If a value does not exist in the first locale in the list, the
Flex application looks for that value in the next locale in the list,
and so on. (citation from Flex documentation)

But this resource bundle mechanism does not apply (at least not directly) to the loading of data files. So let's try to implement it by our own. At a first glance, it should be a piece of cake:

Package the data files in locale-dependent subdirectories of the application (as for property files), say "data/fr_FR/mydata.xml", "data/en_US/mydata.xml". Each directory contains the localized variant for the corresponding locale.

At runtime, gather the localeChain (app.resourceManager.localeChain) and iterate over the locales to obey the precedence rule.

For each locale, check whether the data file is present.

If present, read it and use it, and we're done. If not present, go to the next locale, till the end of the locale chain. If not found for any locale in the locale chain, fall back to some predefined default locale (typically but not necessarily English).

Algorithmically quite trivial... but step #3 proved to be much trickier to implement than I initially thought. That is, checking whether a data file is present in a given directory isn't that simple: you discover it once you try it... Let's see the available Flex APIs for loading data files in webapps. The package "flash.net" provides URLStream, which, according to its doc, "provides low-level access to downloading URLs. Data is made available to application code immediately as it is downloaded, instead of waiting until the entire file is complete as with URLLoader. The URLStream class also lets you close a stream before it finishes downloading. The contents of the downloaded file are made available as raw binary data from an URL".

Fine. But for our purpose we need to iterate over URLs with relative parts such "data/fr_FR/mydata.xml" and, "data/en_US/mydata.xml" and, for each, to determine as quickly as possible if the given file is available. No API is dedicated for this precise task: checking for file availability. Instead, we have to actually start a loading of the file using URLStream.load(URLRequest). Then we try to figure out whether the file exists. But how do we figure it out? The Flex API offers several types of notifications:

URLStream.load throws IOError or SecurityException exceptions "if the loading fails immediately" (more exactly, both exception classes are mentioned in the asdoc, however only the SecurityException is listed in the throws clauses of the asdoc).

Events are sent to the registered listeners of IOErrorEvent.IO_ERROR and SecurityErrorEvent.SECURITY_ERROR events. Obviously, this holds for errors that occur asynchronously.

Events are also sent to registered listeners of HTTPStatusEvent.HTTP_STATUS events. This event contains an event.status field.

Finally, events are also sent to registered listeners of Event.OPEN, ProgressEvent.PROGRESS, and Event.COMPLETE events.

So, these APIs offer several means to detect either a loading failure, or a loading success. Can we just rely on just one of them in all cases? Testing in various cases brought a negative answer... The behavior of these APIs varies from one testing platform to another, for reasons such as design or implementation choices or bugs in Flex/Flash, variety of behaviors of browsers and webservers. All in one, I had to use a combination of the means mentioned above to be able to put in place an utility function which works in all the use cases that we tested.

Examples of behaviors which are browser-dependent:

The status field of HTTPStatusEvent.HTTP_STATUS events: depending on browsers, FlashPlayer may not be able to provide the
correct status and provides instead the value 0. See Adobe bug FP-721
"URLLoader - HttpStatusEvent should return a valid http status code and
not 0".

ProgressEvent.PROGRESS : for instance with Internet Explorer 8 (and FlashPlayer10.3), we get
a "progress" event even for an URL corresponding with a non-existing
file! Furthermore, this "progress" event has event.bytesAvailable >
0! Indeed, the stream can contain in case of error an HTML page with an
error message... (and its precise content depends on the webserver)

We called this utility function AsyncFileLoader.asyncLoadLocalized.

Sample applicationThe sample application uses the utility function AsyncFileLoader.asyncLoadLocalized and provides a GUI which allows to try it in various cases. The GUI is mostly self-explanatory. It has three parts:

Top part: There are two buttons: one for loading a data file which is available for fr_FR and en_US locales (French and English translations), but not for ru_RU locale. The second button is for launching the loading of a data file which is available for none of the locales. The combo box allows to switch among all possible combinations of order among the three locales (ru_RU, fr_FR, and en_US).

Middle part: shows the content of the loaded file (when the loaded succeeds).

Bottom part: shows the log (the output of debugging statements in the utility function).

Here is how the sample application looks like:

Screenshot of the sample application (click to enlarge).

In this example, the log shows the execution traces corresponding to the loading in Internet Explorer 9 of a data file which is available for the second locale in the locale chain, but not for the first locale. The important point is that, as you can see, the execution sequence includes, for Internet Explorer (at least 8 and 9), an event of type "open" even for a file which does not exist! This does not hold for Chrome or Firefox, but it means we can't blindly consider that a file exists just because we received an "open" event! As a matter of fact, the loading goes differently depending on web browsers, and potentially Flex and Flash versions (see the Adobe bug mentioned above), and web servers (which may react differently to requests for unavailable resources). The utility aims to cope with a variety of behaviors while detecting as soon as possible whether a file exists or not for a given locale. There is no theoretic guarantee that it works optimally in all possible cases, but it has been successfully tested on all the combinations of OS and
browser supported by Flash Player 10.3 (recent versions of Chrome,
Firefox, Internet Explorer, Opera, Safari, on Windows, Linux, and Mac
OSX systems).

You can run the sample application by clicking here. To view the source code, right-click anywhere in the application and press "View Source".

Sparkline components, also known as “Sparklines” or “micro charts”, were first described by Edward Tufte in “Beautiful Evidence” as "data-intense, design-simple, word-like graphics". Sparklines are characterized by their small size and high data density, and are useful for presenting variations associated with measurement, for example, in the domain of monitoring applications, such as stock market applications, network equipment monitoring, or in any systems that produce numerical real-time data.

Using MicroLineChart and MicroColumnChart out-of-the-box, they look like this:

Since microcharts are based on the Spark architecture, let's see how to modify the skin of the component to:

add a label displaying the last value,

add a color indicator that will be red if the last value is negative, green otherwise,

change the main color of the skin to black.

To display the last value, we use hostComponent.lastPushedObject in the skin definition:

Here is an overview of the new features and improvements of the Diagram module in the recently
released IBM ILOG Elixir Enterprise 3.5:

New graph layout algorithm: Circular layout

Circular Layout is designed for graphs representing interconnected ring and/or star
network topologies, as in the following example:

Network of star clusters laid out using the new Circular Layout algorithm

The algorithm is able to partition the graph into clusters according to specified business data, or
to compute a partitioning automatically. See CircularLayout's property clusteringMode.

Improved layout of nested graphs thanks to a new mode of Hierarchical Layout

In the previous release, it was necessary to use a combination of "node layout" and "link layout" in
order to lay out a nested graph including intergraph links (links that connect nodes from different subgraphs).
In Elixir 3.5, Hierarchical layout has been improved with a recursive mode such that it can handle by itself an
entire nested graph. This simplifies user's task for configuring the layout: no link layout is needed anymore.
Moreover, it improves the quality of the layout, because instead of optimizing the layout locally for each
individual subgraph the algorithm now performs a global optimization taking into account the entire nested
hierarchy. The quality improvement consists in a reduced number of link crossings and a more regular layout
of the links. The following screenshots illustrate this benefit by comparing the result for the same nested
graph with, and without this new feature:

The new recursive mode is enabled by default. If necessary, it can be disabled by setting HierarchicalLayout's
property recursiveLayoutMode at false.

Improved self-link and multi-link layout

A new link layout algorithm has been added: BasicLinkStyleLayout. This algorithm handles multiple
links between the same pair of nodes, and self-links that start and end at the same node. While
Hierarchical, Tree, Short and Long Link layouts were already able to lay out multi-links and self-links,
this feature was missing on other node layout algorithms. Now Circular and Force-Directed Layout also have
such capabilities, because they are now subclasses of the new BasicLinkStyleLayout (which can also be used standalone).
The algorithm provides a large number of choices among various styles and distance parameters.
An example:

Multi-links and self-links laid out laid out by the new BasicLinkStyleLayout (also available in Force-Directed and Circular layout)

Other new features

Improved animation during graph layout

For a more pleasant effect, the fit and the layout animation can be executed in parallel,
instead of successively. New property on the class Diagram: animateGraphLayoutFitContent.

Easing and duration options have been added. New properties on the class Diagram:
graphLayoutAnimationDuration, graphLayoutAnimationEaser.

Diagram links

Curved links: a Bezier curve can now be used as path for the links. New style properties on
the class Link: curved and curveSmoothRatio.

For defining the links, the previous release provides two ways: using a link data provider
or an implicit definition by the hierarchy of nodes. Additionally, Elixir Enterprise 3.5 allows
the define the links thanks to successors or predecessors elements of the nodes.

New APIs on the class Diagram: successorsField, successorsFunction, predecessorsField,
predecessorsFunction.

New sample: samples/diagram/linkCreationPolicy.

New events

The Diagram class now dispatches new events for its nodes and links:
itemClick, itemDoubleClick, itemRollOver, itemRollOut.

The Elixir team hopes you will enjoy these new features! As usually, feel free to ask any questions.

Multiple calendar display in column view

In the previous versions, the color of the item renderers was used to differentiate two items that are belonging two different calendar.

In addition to colors, in order to easily compare items from two different calendars, the new component can, for each column representing a day, display a sub column per calendar.

Five calendars displayed in a single day.

Without separating calendars

Separating calendars

When time is selected in sub columns, you can easily determine the associated calendar, for example to create a task on the selected calendar.

View flexibility

Type of view and time range are not correlated

The calendar's core job is to display events in time through different views. In MX calendar, the kind of view is determined by the duration of the queried time range. This is not the case anymore, now you specifies the time range to display and the display mode: columns or grid.

For example this kind of view were not possible in previous versions:

Two work weeks using columns display mode

A work week using grid display mode.

Time range definition

To set the time range, you can:

specify the start and end dates of the time range,

or specify a date, an interval (day, work week, week or month) and a number of intervals.

This last way allows to easily define custom views like four days, two work weeks or two months without having to compute dates.

Item / renderer association

Before the kind of renderer (vertical, bar, horizontal or label) was hard-coded according to event duration.

Now you can specify the kind of renderer to use for each item using a simple custom function. It is very easy and very powerful.

Here are some examples where the default behavior is overridden:

In columns display mode, show only all day events on secondary group and not all long events.

Show bars instead of vertical if column width is too small

In grid display mode, show only horizontal renderers

Filter out some events by using no renderer for these particular events.

Here are some screen shots of usage of the renderer kind custom function:

Use only bar renderers as the columns are not wide enough.

Use horizontal renderers for short events instead of labels.

Day filtering

The Calendar components now has the ability to filter out some days of week.
In order to ease work week definition, two properties are exposed on the component:

One to define the day to hide in work week date interval,

Another to define the day to hide in other date intervals

Here are some example of usage of day filtering:

A work week where Sunday, Wednesday and Saturday are hidden.

A month view with week ends hidden.

Time of day filtering

Another feature often asked is the ability to choose the first and last hour displayed in the view.

Only the 8am to 6pm part of the day is displayed.

In grid display mode, it only applies on horizontal renderers and not labels.

Only the 8am to 6pm part of the day is displayed: the left side of a cell is 8am and the right side is 6pm.

Minimal sizes supported

If an event is very short is may not be readable. If readability is more important for you than exact time projection on the screen, the layout is now supporting a minimal height or width.

Without a minimal height, the first event that ends at 9:15am is very small.

With a minimal height, the event is visible but its end is not correctly projected so the label must include end time.

New grid display mode layout properties

In grid display mode, it is now possible to configure the layout to make the horizontal renderer to fill cells.

Instead of projecting event according to start and time, fill cells.

The horizontal renderer can now overlap each other like in columns display mode.

Overlap of horizontal renderers.

Work Calendar

The definition of working and non working periods is now delegated to dedicated object.

This work calendar allows to:

inherit from a base calendar,

define default working and non working periods,

define some exceptions for a specified period of time,

use the work calendar easily, for example during the editing of an event.

As this work calendar is also used in the Gantt chart components (resource chart and task chart), it allows a seamless integration of the calendar component in an application using these two components.

New animation engine

The new architecture allows to create new animations:

scrolling from one time range to a close one (ex: from current week to next week),

zooming in or out from a time range to another time range (ex: from current week to current day),

show or hide days using filtering feature (ex: from current week to current work week),

a combination of two previous use cases (ex: from current month to current work week).

The sole transition that is not animated is from one display mode to another.

In this newly recorded presentation Exploring choices for desktop and mobile RIA applications, learn the pros and cons of these three technologies: HTML 5 and Dojo, Adobe Flex, and Microsoft Silverlight. This recorded presentation has several demonstrations and provides insight about which technology is best for your RIA or project.

The next time you visit the Elixir Enterprise pages on ibm.com you may see a survey window appear. If you are interested in providing us some feedback, please click Yes. We are looking for your feedback to help improve the pages.

The survey should not take more than 5 minutes to complete. Head on over to the Elixir Enterprise page if you're interested in completing the survey.

[If you previously said No but are now interested, clear your cookies and the survey should appear.]