Home  >  

Anatomy of an Enterprise Flex RIA Part 14: Services and Delegates

Author photo
AddThis Social Bookmark Button
riaseries_part14.jpg

Last time we looked at Cairngorm and its role in our application. This installment of Anatomy of an Enterprise Flex RIA, we're going to look at Cairngorm’s business delegates and how to set up a service oriented architecture in Flex.

Services and Delegates

The ServiceLocator and delegates for Bookie are the last stop on the Flex side for calls to the services. Figure 18 shows where they’re located.

anatomy14_fig18.jpg
Figure 18. Location of the ServiceLocator and delegates for Bookie

The ServiceLocator definition for Bookie is fairly simple and declarative:

<?xml version="1.0" encoding="utf-8"?>
<cairngorm:ServiceLocator...>
    <mx:RemoteObject  id="bookSearchService"
                    destination="bookSearchService"
                    showBusyCursor="true">
     </mx:RemoteObject>    
     <mx:DataService id="bookDataService" destination="bookService" />
     <mx:DataService id="subjectDataService" destination="subjectService" />
     <mx:DataService id="personDataService" destination="personService" />
     <mx:DataService id="reservationDataService" destination="reservationService" />
     <mx:Consumer id="reservationConsumer" destination="outstandingReservationTopic" />
</cairngorm:ServiceLocator>

Each tag points to a destination defined in an LCDS configuration file: data-management-config.xml for the DataServices, which map to our assemblers; and remoting-config.xml for the RemoteObject, which points to lcds.examples.bookie.service.BookSearchExample. We’ll see how to get a reference to these services from the delegates next.

There are two delegates in Bookie, the BookieDelegate and the AdminDelegate, corresponding to the service calls needed for each part of the application. The delegates are simple, and again, they act mostly as a buffer to change in the service layer.

Let’s look at the BookieDelegate, which uses both data services and a remote object:

package lcds.examples.bookie.business {
 ...
     public class BookieDelegate {
  ...
           private var responder:IResponder;
           private var bookSearchService:RemoteObject;
           private var subjectService:DataService;
           private var personService:DataService;
           private var reservationService:DataService;
           private var services:ServiceLocator =
                      ServiceLocator.getInstance();
  
           public function BookieDelegate(responder:IResponder=null) {bookSearchService =
                     services.getRemoteObject("bookSearchService");
                 subjectService =
                     services.getDataService("subjectDataService");
                 personService =
                     services.getDataService("personDataService");
                 reservationService =
                     services.getDataService("reservationDataService");
                 this.responder = responder;
            }
  ...

First, in the constructor, we take an argument of a responder, which is a simple interface that looks like this:

public interface IResponder {
     function result(data:Object):void;
     function fault(info:Object):void;
}

Each command that calls a delegate implements this interface, which gets the callback from any service calls to the result method if the call went well, and to fault if the call went south.

Each command is responsible for instantiating its own delegate, and the delegate keeps a reference to the responder that called it. In the constructor, the delegate also sets up a reference to all the services:

...
public function findPersonByCardNumber(cardNumber:String):void {
     var call:AsyncToken = bookSearchService.findPersonByCardNumber(cardNumber);
     call.addResponder(responder);
}

Next, we see one example of a delegate call, findPersonByCardNumber. It simply takes a card number as a string, calls the method of the same name on the bookSearchService RemoteObject, and gets a reference to the AsyncToken returned by that call, which acts as a handler to the call and knows how to call back to a registered responder. Calling addResponder registers the responder with the token. Once the call returns, one of the result or fault methods of the responder will be called.

How does Flex know there’s a method called findPersonByCardNumber on the RemoteObject? Well, strictly speaking, it doesn’t, so you could get an exception at runtime if there were a spelling mistake. What really happens when you call any method on a RemoteObject is that a method of the same name is invoked on the object the RemoteObject points at through a destination. This works because RemoteObject is a subclass of flash.utils.Proxy, which is a class that knows how to deal with calls to methods that don’t exist on the object. It seems like magic, but it works great, and it’s a lot better than trying to deal with web services and all that packing and unpacking of XML. Now let’s look at a call to a DataService:

...
public function getAllSubjects(collection:ListCollectionView):void {subjectService.fill(collection);
}
...

This method on the delegate is pretty darn simple, right? That’s LCDS. All we do is to pass in a reference to a collection we want to fill with a set of data, and then call the fill method on a data service with that collection. The rest happens automatically. Now that collection is managed, and because we’ve left on the default auto-sync behavior of the DataServices, any changes to managed items in the collection or changes to the collection itself, such as additions or removals, will be sent to the assembler, on through the session bean the assembler wraps, and into the database.

Remember that the code samples have RemoteObject services mixed with DataServices to provide an example of each. It’s easy to see that for most “save this object” use cases, a DataService is the way to go. For other use cases that rely on communication with a POJO, RemoteObject is the way to go.

Make note of the delegate methods in BookieDelegate that call methods on the BookSearchService RemoteObject:

  • findPersonByCardNumber
  • findBooksByAuthor
  • findBooksByTitle
  • findBooksBySubject

The remaining methods in BookieDelegate and AdminDelegate all use various DataServices. I’ve left some methods in the BookSearchService to do some of the same things that are done with the DataServices. Feel free to experiment with changing between the RemoteObject and the DataService services.

Next time we'll see how Cairngorm commands, the workhorse of the micro-architecture, fit into our application. You can always find the entire series here.

Read more from Tony Hillerson. Tony Hillerson's Atom feed thillerson on Twitter

Comments

3 Comments

Andre Dekker said:

Hello Tony,

You have done a great job with these series about Flex.
Especially Cairngorm in combination with LCDS is very interesting for me.

However there is one problem i've got reproducing your code in my own project.

These lines of code in the delegate won't work:

private var services:ServiceLocator =
ServiceLocator.getInstance();
subjectService = services.getDataService("subjectDataService");


the method "getDataService" does not exist in my ServiceLocator :((

I am using the latest version of Cairngorm (2.2.1)

Do i miss something ?

Please help me out.


@andre - If you updated to the latest version of Cairngorm, make sure you got the Enterprise version, since that has the data service methods.

Try here: http://labs.adobe.com/wiki/index.php/Cairngorm:Cairngorm2.2.1:Download

Joel Hooks said:

Specifically you want to use EnterpriseServiceLocator to make use of LCDS DataService.

Leave a comment


Tag Cloud

Question of the Week: Dream App

If you had an unlimited budget and unlimited resources what application would you build and why would you build it?

Answer

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.