Home  >  Development  >  features

Anatomy of an Enterprise Flex RIA Part 15: Commands and Controllers

AddThis Social Bookmark Button
riaseries_part15.jpg

Last time we looked at Cairngorm's business delegates and services, and now we're going to see where Cairngorm commands fit in.

Commands and Controllers

Cairngorm commands implement the ICommand interface, which specifies an execute method. The command may also implement IResponder, which specifies a result and a fault method, to be called on result or fault from the service, as the case may be. Each command is registered with a controller, with the FrontController delegating the work to the controller (the Service-to-Worker pattern). Figure 19 shows the location of all the commands and controllers.

series15_fig19.jpg
Figure 19. The locations of the commands and controllers

Table 11 and Table 12 list each command, how it does what it does, and what type of service is involved.

Table 11. User section commands
User section
command
Discussion
FindAuthorsByName
Command
On execute:
Calls BookieDelegate.findAuthorsByName, which uses a DataService to fill the BookieModel’s author collection based on the event’s data, which is the search text for the author’s name.
FindBooks
Command
On execute:
Uses the event data, which should be a SearchEvent specifying the type of search and the search data, along with the string to search with from the user.
On result:
Sets the BookieModel’s books collection to the returned books.
FindSubjectsBy
NameCommand
On execute:
Calls BookieDelegate.findSubjectsByName, which uses a DataService to fill the BookieModel’s subject collection based on the event’s data, which is the search text for the subject.
GetAllAuthors
Command
On execute:
Calls BookieDelegate.getAllAuthors, which uses a DataService to fill the BookieModel’s author collection.
GetAllSubjects
Command
On execute:
Calls BookieDelegate.getAllSubjects, which uses a DataService to fill the BookieModel’s subject collection.
ReserveBooks
Command
On execute:
Creates a collection of reservations based on the event data, specifying books and a user, and calls BookieDelegate.reserveBooks, which uses a DataService to create and persist the reservations.
These reservations should automatically be pushed to the admin clients viewing reservations.
After the call, a notice is displayed, and then the user is logged out, making the assumption that there’s no longer a reason to use the application after reserving the books.
SignInCommandOn execute:
Calls BookieDelegate.findPersonByCardNumber, which uses a RemoteObject service to look up the user based on the card number. On result:
If the call returned a user, the user is stored on the model, the login screen is cleared, and a ViewLocator is used to change the view state of the screen to the main browsing view. If no user was found, an error message is displayed on the login screen.
SignOutCommandOn execute:
The model is cleared of data by calling initialize, all the screens are looked up through ViewLocators and are cleared, and the main ViewLocator is used to return the view state to the login screen.

 

Table 12. Admin section commands
xxyy
Admin section
command
Discussion
ClearReservations
ReceivedCommand
On execute:
Sets the AdminModel’s outstandingReservations to 0. This is the number of new reservations for display in the control bar in the Admin view as a notice to an administrator that may have been away from the computer when a new reservation came in.
DeleteBook
Command
On execute:
Calls the AdminDelegate.deleteBook method which deletes the book from the data service.
DeletePerson
Command
On execute:
Calls the AdminDelegate.deletePerson method which deletes the book from the data service.
DeleteReservations
Command
On execute:
Calls the AdminDelegate.deleteReservations method which deletes the set of reservations from the data service.
DeleteSubject
Command
On execute:
Calls the AdminDelegate.deleteSubject method which deletes the subject from the data service.
GetAllAuthors
Command
On execute:
Calls the AdminDelegate.getAllAuthors method which uses the PersonAssembler to fill a collection of people, limited to people with the author flag equaling true.
GetAllBooks
Command
On execute:
Calls the AdminDelegate.getAllBooks method which fills the model’s collection of books.
GetAllReservations
AwaitingCheckOut
Command
On execute:
Calls the AdminDelegate.getAllReservationsAwaiting
CheckOut method which uses the data service to fill a collection of reservations where the reservedOn is null, meaning that these reservations are awaiting checkout.
GetAllReservations
CheckedOut
Command
On execute:
Calls the AdminDelegate.getAllReservations
CheckedOut method which uses the data service to fill a collection of reservations where the reservedOn is a date, meaning that these reservations are already checked out.
GetAllSubjects
Command
On execute:
Calls the AdminDelegate.getAllSubjects method which fills the model’s collection of subjects.
GetAllUsers
Command
On execute:
Calls the AdminDelegate.getAllUsers method which uses the PersonAssembler to fill a collection of people with any of the people found.
ReservationNotification
SubscribeCommand
On execute:
Gets a reference from the ServiceLocator to the consumer that will receive messages from the JMS when new reservations are persisted. Sets the reservationConsumer property on the NotificationListener, which adds it as a listener for these types of messages.
I will describe the NotificationListener in more detail later, but it’s responsible for popping up the notification window when a new reservation is persisted.
Reservation
ReceivedCommand
On execute:
Tells the NotificationListener to pop up the reservation notification message using a ViewLocator, and to increment the number of new reservations on the model, which should be shown on the control bar in the Admin view.

Let’s look at the commands that call the methods we already looked at on the bookie delegate. First is the command to sign a user into the system, SignInCommand:

package lcds.examples.bookie.command {
 ...
     public class SignInCommand implements ICommand, IResponder {
  
           private var model:BookieModel = BookieModel.getInstance();
  
           public function execute(event:CairngormEvent):void {
                 var evt:SignInEvent = event as SignInEvent;
                 var delegate:BookieDelegate = new BookieDelegate(this);
                 delegate.findPersonByCardNumber(evt.cardNumber);
            }
  ...

Note that SignInCommand implements both ICommand and IResponder, which means that we expect this command to call a service asynchronously and get a call back to result or fault when the service is done. Asynchronously simply means that there’s no way for the Flash Player to call out to Java and wait until it’s done before going on with execution. You don’t even really want it to. Because Flash isn’t multithreaded, all execution in the Flash Player would be on hold until Java came back with an answer. When we call a method on a remote service we always specify a “callback,” or a method to call when it’s done. The Flash Player keeps track of that for you, but once you call out to the service layer, execution continues from the point you make the call and the method that’s making the call ends. In this case, the callbacks are those result and fault methods specified by the IResponder interface.

Here are the implementations in the SignInCommand:

public function result(result:Object):void {
     if (result.result != null) {
           var p:Person = Person(result.result);
           model.user = p;
           model.loginFailedMessage = "";
  
           model.currentState = BookieModel.SIGNED_IN;
      } else {
           model.loginFailedMessage = "That card number was not found";
      }
     
}

public function fault(fault:Object):void {
     Alert.show("Unable to sign in", "Error while signing in");
}

The result method gets called back with a result object. On the result object is a property called result which contains the data from the callback. If you look all the way back through the delegate to the BookSearchService in Java, and further to the DAO, you’ll see that this call will return a Person object, which should be the user matched by the card number. If that person isn’t null, we know we matched a user with the card number, so we’ll let the user sign in (pretty secure, huh?). We’ll see how the login process works in more detail in a bit; this is just to let you see that the command gets a call back to result when a service call originating in execute returns. The fault method just pops up a simple alert to say there was a problem, but of course, that could be more complex as needed.

Let’s look at a command that calls a data service, GetAllSubjectsCommand:

package lcds.examples.bookie.command {
 ...
     public class GetAllSubjectsCommand implements ICommand {
  
           private var model:BookieModel = BookieModel.getInstance();
  
           public function execute(event:CairngormEvent):void {
                 var delegate:BookieDelegate = new BookieDelegate();
                 delegate.getAllSubjects(model.subjects);
            }
  
      }
}

The GetAllSubjectsCommand only implements ICommand, so it doesn’t expect to be called back by the service after its execution is complete. And look at how simple the execution is too; all it needs to do is get the reference to the subject collection from the model and pass it to the delegate, which you’ll remember calls a fill on that collection.

The Command pattern is a smart way to keep execution of a discrete set of functionality modular and reusable. Anyplace in the code that needs to get all the subjects doesn’t need to know anything but to call the right command, and that command can be called anywhere in the application. If the process to get all the subjects into a collection changes none of the code that kicks off the command needs to know, so they’re insulated from change.

Next week we'll look at the Cairngorm model locator and how we'll use the power of Flex's binding to easily configure the view based on the state of the model. You can always find the entire series here.

Comments

Leave a comment


Type the characters you see in the picture above.

Tag Cloud

Related Books

Development Series

Get an overview of the tools and technologies that work together to allow developers to build Rich Internet Applications (RIAs) quickly and easily.

Anatomy of an Enterprise Flex RIA

Recent Comments

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.

About Us
Meet the Experts
Meet Our Contributors
Send Us Feedback