You are hereAria User Guide / Section III: In Depth / Evaluated Attributes and Helpers

Evaluated Attributes and Helpers


By luano - Posted on 14 January 2009

Evaluated attributes provide a powerful way of extending the scope and range of what Aria can do. Take for example a simple data binding where a single source node is mapped to say an edit field. On its own this binding is limited, but if we use an evaluated attribute then we can control what is displayed each time the binding is updated, and earlier (Callbacks.) we saw an example of this dynamic data binding.

Evaluated attributes offer a great deal of power and reinforce the idea of the Model-View-Controller architecture by providing a means to insert links between the various components without hard wiring of these links.

Evaluated attributes

First of all, to recap what an evaluated attribute is and how it works lets look at a very simple example.

Basic attribute evaluation

  1. <Button name="DecBtn" x="178" y="43" w="42" h="20" content="${getContent()}"/>

The code ${getContent()} is an expression that is evaluated at runtime each time the expression is encountered. For a page component declaration the expression is evaluated when the page is loaded.

Expressions can be used in other locations such as within the data model, the data bindings, the validations or the event bindings.

Arguments allowed in XML attribute method calls

The XML description of pages has been able to support method calls for the evaluation of attributes since version 1.0.3. These method calls now support method arguments. Arguments of int and String types can be included. For example:

An Evaluated Attribute

  1. <Bind target="connSizeSt" source="${getNodeValue(3)}" unique="true"/>

This example dynamically binds a value to the connSizeSt component. The implementing page should then contain the method

A Handler for an Evaluated Attribute

  1. public String getNodeValue( int NodeID )
  2. {
  3. ...
  4. }

The implementation of this method should return a String that can be used as the source attribute of the original XML Bind element.

The advantage of this method call is that the same page definition can now be reused and bound to different parts of the data model. A simple example of this might be where a popup dialog is used to show details of say a person in some business model. Such a person entity could be a manager, an employee or a visitor/guest and as such the data for each of these entities would exist in different parts of an organizational hierarchy.

Library expressions

In Aria 2.0 The attributes can also be defined in classes other than the current page or classes derived from Page . The syntax for such expressions is as follows:

Extended attribute declarations

Syntax

Behavior

${mypackage.MyClass.myMethod(args...)}

to invoke a static method

${mypackage.MyClass[].myMethod(args...)}

to create a new instance of the class on each evaluation

${mypackage.MyClass[referenceName].myMethod(args...)}

for a named object instance

${myMethod[referenceName](args...)}

for a method contained within the invoking page

${[referenceName].myMethod(args...)}

for a method contained within the class instance referred to by the reference name.

${this[referenceName].componentMethod(args...)}

for a method contained within the component referred to by the reference name. Since 2.0.7

${project.projectMethod(args...)}

for a method contained within the current project. Since 2.0.7

${this.myMethod(args...)}

for a method contained within the enclosing page class. This is provided for compatibility with the basic method invocation mechansim. Since 2.0.7

${a/b/c.myMethod(args...)}

for a method contained within a POJO attached to the Aria data model. The POJO at the model path a/b/c containing the method myMethod will be invoked. since 4.0

where mypackage is the name of the Java package containing the class MyClass . The value of referenceName is a user defined value that identifies the instance of the class. The application instantiates an instance of the class when the expression is first encountered and thereafter maintains the instance with each subsequent call retrieving the same instance of the class. As in early versions, the method call can also contain zero or more arguments. For an example of this please see Evaluated attributes.. Library expressions can be used in the specification of component attributes, events and for data bindings.

Expression evaluators

The expressions are evaluated by an ExpressionEvaluator and each page has by default its own instance of the default expression evaluator. (The default evaluator delegates storage of the referenced classes to the project). However, the page allows this evaluator to be replaced and a different evaluator can be inserted with a call to the AriaBuilder.setAttributeEvaluator method. This replaceable evaluator allows a route to include other expression evaluators such as interpreters. Therefore if the capability of the built in evaluate is insufficient you can replace or extend the default evaluator. As an example a prototype evaluator for the Groovy language has been created.

Using evaluated attributes

OK, so we have seen how the attributes of an XML file can in fact be callbacks to methods in your page class or in some other class. What does this mean for the application?

Essentially this means that the model is dynamic, it can be adapted to meet the changing needs of your application as a session progresses. You are not restricted to the setup encoded in the XML at start-up.

The dynamic model also means the data structure specified in the XML (or in your code for that matter) can be mapped from one instance to another via the evaluated attributes and callbacks. We have already seen how this could be use with something as simple as an address form.

Evaluated attributes also make it possible to apply more advanced techniques like filtering data and providing access control. Once you get to grips with the basic functionality you should find the use of evaluated attributes a very powerful mechanism.

From an achitectural point of view the use of evaluated expressions means that you can create a user interface with XML with very little dependancy upon the Java code. The page does not need to be derived from a custom class as you logic can be embedded in some other hierarchy.

The use of library functions also promotes reuse as the code can be freed of some of the page specific constraints. Late binding also opens up further possibilities for dynamically matching code to the user interface and providing different levels of functionality or strategies for different situations or even for different users.

The on-line mortgage tutorial uses library methods to implement its page navigation. In the pre 2.0 versions the navigation required a special page to implement this behavior and therefore the navigation page became tied to the navigation class which was undesirable if you wanted to use features of another page class (assuming that the navigation is only a small part of the page's functionality). With the new library functions the navigation features can be added as mix-ins with very few special requrements.

The added flexibility of this arrangement should make it possible to build reusable functionality that can be dropped in to various points of your application.

Escape sequence for path attribute values

When searching for a model node it is possible to specify an attribute value to distinguish between nodes with the same parents. For example:

A Model Path and Attribute

  1. model.get( "products/software/vendor@name=Formaria" );

This searches for a node where the vendor has a name attribute of Formaria . Sometimes, for instance when handling code numbers or article numbers, the attribute may include forward slashes. These slashes can cause problems when trying to identify various parts of the path and therefore an escape sequence has been added to allow attributes with slashes to be used in searches. Such a search would appear as:

A Model Path and a Specified Attribute

  1. model.get( "products/tyres/vendor@name=michelin/size@value=[R14/500]" );

In the above example the search is for a tyre from the michelin vendor and with a size of R14/500 .

Handling evaluation exceptions

An exception handler has been added to the attribute evaluator. The handler gets called in case of an exception and can override the result returned by the attribute evaluator. The evaluator may be of use in case, for example, an evaluation depends on a list selection and where that list may not have a selected values - the list would otherwise return a value such as null or -1 to indicate the error and this is probably not a valid value for the evaluated attribute. Say a path of a/b/${c}/d/e is enetered and ${c} depends on say a list selection and that list is not fully initialized.

TODO add example code

An example

To illustrate the use of evaluated attributes a dialog with dynamically loaded text will be displayed. The text to be loaded comes from an extrenal HTML file as it is too large to be embedded in the page XML or the language resource bundles.

First of all lets look at the XML:

Setting the text via a callback function

  1. <Page class="org.formaria.demo.About" padding="10">
  2. <Components>
  3. <Image x="526" y="0" w="74" h="30" imageName="danfoss.gif" />
  4. <ScrollPane x="10" y="50" w="600" h="250" style="base/info" border="0"
  5. vertical_scrollbar="as needed" horizontal_scrollbar="never">
  6. <Label x="10" y="50" w="600" h="400" content="${getExtraText(terms)}"
  7. style="base/info"/>
  8. </ScrollPane>
  9. <ImageButton name="closeBtn" x="510" y="310" w="100" h="28"
  10. style="GraphicButton" text="OK"
  11. imageName="button.png" rollover="button_over.png"
  12. pressed="button_pressed.png"/>
  13. </Components>
  14. <Events>
  15. <Event method="closeDlg" target="closeBtn" type="ActionHandler"/>
  16. </Events>
  17. </Page>

Then in the about class the referenced method is implemented:

Implementingthe evaluated method

  1. public class About extends Dialog
  2. {
  3. public About()
  4. {
  5. }
  6.  
  7. /**
  8.   * Get the text for a popup from an extra file
  9.   * @param fileName the argument from the XML file
  10.   */
  11. public String getExtraText( String fileName )
  12. {
  13. // Get the default language from the preferences
  14. Preferences rsPrefs = Preferences.userNodeForPackage( Welcome.class );
  15. String defLangCode = rsPrefs.get( "defaultLanguage", "en" );
  16.  
  17. // Build the path to the file - use a separate sub folder for each language
  18. String filePath = defLangCode + File.separator + fileName + ".html";
  19. try {
  20. // Open and read the file
  21. Reader r = project.getBufferedReader( filePath );
  22.  
  23. StringBuffer text = new StringBuffer();
  24. int BUF_LEN = 1024;
  25. int len = -1;
  26. char buffer[] = new char[ BUF_LEN ];
  27. while (( len = r.read( buffer, 0, BUF_LEN )) >= 0 )
  28. text.append( buffer, 0, BUF_LEN );
  29.  
  30. // Now return the text
  31. return text.toString();
  32. }
  33. catch ( Exception e )
  34. {
  35. e.printStackTrace();
  36. }
  37.  
  38. // The resource was not loaded for some reason
  39. return translate( "Missing resource" );
  40. }
  41. }

With just a few lines of reusable code it is now possible to load content from a variety of sources much in the manner of templates. In fact, the above method has little need to reside in a page class and could just as easily reside in a library class further extending the resuability of the evaluated attribute.

The results of this coding can be seen below: