Home  >  

Anatomy of an Enterprise Flex RIA Part 20: Administration Section: Layout and Navigation

Author photo
AddThis Social Bookmark Button

Last installment we looked at searching for data with our application. Now we'll conclude our look at Flex, LiveCycle Data Services, and EJB 3.0 by exploring the administrative section of the application.

Administration Section: Layout and Navigation

The administration section is only a little more complex (see Figure 25).

series20_figure25.jpg
Figure 25. The administration section

There is an ApplicationControlBar along the top which is the main navigation for the admin section. The control bar has a ToggleButtonBar which is bound to the ViewStack, which makes the button bar have as many buttons as the stack has views, using the labels of the views as the labels of the buttons.

The ApplicationControlBar also has a label on the right side which is bound to the AdminModel’s outstandingReservations property, with a little extra text. The outstandingReservations property tells how many new reservations have come in and not yet been checked out, meaning that someone has reserved some books but has not picked them up yet. The administrator should get those books ready for checkout. We’ll see how this property is set later.

The three views of the view stack are the book management section, the outstanding reservations section, and the checked out reservation section. The management section is where People (Authors and Users), Subjects, and Books are created, updated, and deleted. The outstanding reservations section shows a list of reservations that haven’t yet been checked out, and the checked out reservations section shows a list of books that are checked out, allowing the administrator to check them in.

Administration Section: Data Management in Action

Let’s look at how the CRUD views work. EditBooksPanel includes three edit panels: BookEdit, SubjectEdit, and AuthorEdit. There is some interaction between the three and the EditBooksPanel when a Subject or Author is selected. An event is emitted from the SubjectEdit and AuthorEdit components when one of these is selected, caught by the EditBooksPanel, and set as the current Author or Subject for editing or creating a new Book.

What’s more interesting, though, is editing one of these three. First, instead of a separate form to edit, I’ve used a DataGrid in editable mode. For this simple use case, that works nicely. For a more complex use case, we would probably need a form. Here’s a look at SubjectEdit:

<mx:Panel ... creationComplete="init()">
...
    <mx:Script>
    [Bindable]
    private var model:AdminModel = AdminModel.getInstance();

    public function get selectedSubject():Subject {
          return subjectGrid.selectedItem as Subject;
     }

    private function init():void {
          new GetAllSubjectsEvent().dispatch();
     }

    private function subjectSelected():void {
          dispatchEvent(new Event("subjectSelected"));
     }

    private function removeSubject():void {
          new DeleteSubjectEvent(subjectGrid.selectedItem as Subject).dispatch();
     }

    private function createNewSubject():void {
          var subject:Subject = new Subject();
          subject.name = "New Subject";
          model.subjects.addItem(subject);
     }
    </mx:Script>

The DataGrid is populated with the right data on creationComplete, which is when the view is ready for display, by firing the GetAllSubjects event, this time in the admin package.

<mx:DataGrid
    id="subjectGrid"
    dataProvider="{model.subjects}"
    click="subjectSelected()"
    editable="true"
    width="100%"
    height="100%"
>
    <mx:columns>
        <mx:DataGridColumn
              dataField="id"
              headerText="Id"
              editable="false"
          />
          <mx:DataGridColumn
              dataField="name"
              headerText="Subject Name"
          />
          <mx:DataGridColumn
              dataField="createdOn"
              headerText="Created"
              editable="false"
         />
         <mx:DataGridColumn
              dataField="updatedOn"
              headerText="Updated"
              editable="false"
         />
    </mx:columns>
</mx:DataGrid>
<mx:HBox>
    <mx:Button label="New" click="createNewSubject()" />
    <mx:Button label="Remove" click="removeSubject()"
              enabled="{subjectGrid.selectedItem != null}" />
</mx:HBox>

But look at the code to edit subjects—if you can find it, that is. You’d think you’d need to capture when a row was edited or added, get the information, and send it to the service for persistence, right? We’ll, you’d be right in that it needs to be done, but what’s actually doing all of that work are the data management features of LCDS. All we need to do is make the changes to the data already in the managed collection, or add or delete a row from that collection.

When the init method loaded the data, it got a collection from the data service and put that on the model, and the grid is bound to that model’s collection. Because the DTOs in the collection are all marked as managed:

...
    [Managed]
    [RemoteClass(alias="lcds.examples.bookie.entity.Subject")]
    public class Subject extends BaseEntity {
 ... 

and the DataService is auto-syncing (the default state), the LCDS code on the client knows to automatically save any changes to those DTOs.

This should strike you as an incredible aid to the development effort. That glue code to hook up the edits to any particular object all the way through to the service layer is written for you already—you don’t even have to think about it.

Explore the sample code more if you want, but the important “take home” is how the data management features work hard so that you don’t have to.

Administration Section: The Reservation Alert Notification

One last item of note in Bookie is the notification when a new reservation is received. We’ve seen how the topic is set up in JBoss, and we’ve seen how the ReservationsDAOBean publishes a message to that topic. Now let’s look at how Flex signs up to get those messages.

First, in the Cairngorm services definition, lcds.examples.bookie.business.Services, there’s a definition for a Consumer called reservationConsumer:

<mx:Consumer
    id="reservationConsumer"
    destination="outstandingReservationTopic" />

A Consumer is LCDS’s class for subscribing to and receiving messages. Our reservationConsumer is set to a destination called outstandingReservationTopic, defined in messaging-config.xml:

<destination id="outstandingReservationTopic">
    <properties>
         <network>
              <session-timeout>0</session-timeout>
         </network>
         <jms>
              <destination-type>Topic</destination-type>
              <message-type>javax.jms.ObjectMessage</message-type>
              <connection-factory>
                   TopicConnectionFactory
              </connection-factory>
              <destination-jndi-name>
                   topic/outstandingReservationTopic
              </destination-jndi-name>
              <destination-name>
                   outstandingReservationTopic
              </destination-name>
              <delivery-mode>NON_PERSISTENT</delivery-mode>
              <message-priority>DEFAULT_PRIORITY</message-priority>
              <acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode>
              <transacted-sessions>false</transacted-sessions>
         </jms>
    </properties>
</destination>

This destination points to the topic and connection factory and sets the properties of the topic that LCDS needs to know. All we need to do to start listening for messages is to tell the consumer to subscribe. What I’ve done is create something similar to a wrapper to the Consumer in lcds.examples.bookie.business.NotificationManager. It takes a Consumer in the reservationConsumer setter, subscribes that Consumer (if it wasn’t already), and starts listening for messages.

package lcds.examples.bookie.business {
 ... 
     public class NotificationManager {
  ... 
           private var _reservationNotificationView:NewReservationNotification;
           public function set reservationNotificationView(view:NewReservationNotification):void {
                 _reservationNotificationView = view;
            }
  
           private var _consumer:Consumer;
           public function set reservationConsumer(consumer:Consumer):void {
                 if (!consumer.subscribed) consumer.subscribe();
                 consumer.addEventListener(MessageEvent.MESSAGE, onNewReservation);
                 _consumer = consumer;
            }
  
  ...  
           public function onNewReservation(me:MessageEvent):void {
                 var reservation:Reservation = Reservation(me.message.body);
                 new ReservationRecievedEvent(reservation).dispatch();
                 notifyOfReservation(reservation);
            }
  
           public function notifyOfReservation(reservation:Reservation):void {
                 _reservationNotificationView.show(reservation);
            }
 }

NotificationManager is a singleton because we should have only one. To bootstrap this NotificationManager, admin.mxml fires a command when it’s initialized, called lcds.examples.bookie.command.admin.ReservationNotificationSubscribeCommand, which simply sets the consumer on the NotificationManager. It also gets an instance of the NewReservationNotification component, which displays a notification when a new reservation is received.

package lcds.examples.bookie.command.admin {
     public class ReservationNotificationSubscribeCommand
                                   implements ICommand {
  
           public function execute(event:CairngormEvent):void {
                 var evt:ReservationNotificationSubscribeEvent = 
                      event as ReservationNotificationSubscribeEvent;
                 var consumer:Consumer = 
                 EnterpriseServiceLocator.
                      getInstance().
                      getConsumer("reservationConsumer");
   
                 var manager:NotificationManager =
                      NotificationManager.getInstance();
                 manager.reservationConsumer = consumer;
                 manager.reservationNotificationView =
                      evt.reservationNotificiation;
           }
      }
}

Once a message is received, NotificationManager.onNewReservation is called, and that fires an event which corresponds to the lcds.examples.bookie.command.admin.ReservationReceivedCommand. The NotificationManager then tells the NewReservationNotification to show itself. That view is a simple HBox that shows a collection of books in a reservation, and then animates itself away similar to how the Thunderbird email client shows that you have new email (see Figure 26).

series20_figure26.jpg
Figure 26. An automatic reservation update

Here’s the code for that little widget:

...
         private var hideTimer:Timer;

         public function show(reservation:Reservation):void {
               reservationTitles.text =
                    reservationTitles.text +
                    reservation.book.title + "\n";
               reservationTitles.maxWidth = this.width;
               if (hideTimer == null || !hideTimer.running) {
                     hideTimer = new Timer(3000, 1);
                     hideTimer.addEventListener(
                          TimerEvent.TIMER_COMPLETE, hide);
                } else {
                     hideTimer.reset();
                }
               visible = true;
          }

         public function showEffectComplete():void {
               if (hideTimer != null) hideTimer.start();
          }

         public function hide(event:TimerEvent):void {
               visible = false;
          }

         public function hideEffectComplete():void {
               reservationTitles.text = "";
               hideTimer = null;
          }
    </mx:Script>
    <mx:hideEffect>{hideDissolve}</mx:hideEffect>
    <mx:showEffect>{showWipeDown}</mx:showEffect>
    <mx:WipeDown id="showWipeDown" effectEnd="showEffectComplete()"
target="{this}" />
    <mx:Dissolve id="hideDissolve" effectEnd="hideEffectComplete()" target="{this}" />
    <mx:Label id="titleLabel" text="New Book Reservations" fontWeight="bold" />
    <mx:Text id="reservationTitles" />
...

To test this, deploy the application and open both the user application and the admin application side by side (see Figure 27).

series20_figure27.jpg
Figure 27. The user and admin applications

Browse for a few books and reserve them from the user side, and watch the notification come up on the admin side. Slick. And easy!

You can always find the entire series here.

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

Comments

10 Comments

Flexi said:

Hi Tony,
Just wanted to say that these articles, as good as they are, should all be upgraded to Flex 3.0. just have a look on all the comments people left on the 2nd entry... I think most of them stopped there. If the example code doesn't work... well, you know...

@Flexi - I totally agree, it's just an issue of timing. This "article", which is actually a serialization of an O'Reilly Shortcut, was written almost a year ago and serialized on this site. I haven't actually been writing these fresh each week.

I'd love to upgrade it, but it's an issue of time. I'll bring up your concerns, and thanks for reading until the end :)

Flexi said:

No no... thank you, mate!
I figured that that was the issue - time :)... well, no pain no gain, hmm?

Flexer said:

Tony,

These articles are good but have basically nothing to do with enterprise flex, the title is very misleading.

Enterprise is not the same as somewhat large app and most of these patterns wouldn't apply to real enterprise systems. I am not sure where these ideas were confused along the way (in many developers heads) but the word enterprise means something and its casual use is making it harder for those of us trying to find real information on enterprise flex to actually find anything at all.

Pete

@Pete

What I meant by Enterprise was connecting to and loading data from a Java Enterprise Application Server, such as JBoss, and the development tasks that work with that environment.

As a dissenter, can you give us an idea of what you would have liked to have seen in this shortcut instead of or in addition to what's there?

Tony

TJ said:

@Pete

Please do share with is what you mean by your "Enterprise" complaint. These articles show you the in and outs of building a real application that connects with and uses real backend services. Moreover, it provides tons of great insight on how/which frameworks to be using in each of the various application layers. What more could you possibly want.

Great articles!

Jasper said:

Tony,
Why didn't you ever make any attempt to clear up the mass confusion at the 2nd in the series. There was so many mistakes and things left out. Yet here you have time to discuss. It's a big time-waster.
you know what they say: if it's worth doing...
sorry

Vineet said:

Tony,

Great series of articles! Extremely helpful for me as I am starting work on a new enterprise application using LCDS. The java service layer you described is very slim. In enterprise apps (specifically for data capture) there is a lot more which happen before anything gets to the DAO layer. For example server side validations, calculations and other business logic. These java service class would then delegate to assemblers and DAO. How would the data management be configured in case where we want things to go to java Service class first?

@Vineet - that's a good question. It always makes sense to put business validation on the server side in an SOA because you're not planning for any particular client and for any number of clients.

With a Flex application you have more facility for a good user experience with regards to validations and things like that, so in some cases it's pragmatic to catch some validations on the front end as well. It's up to you how you plan to cut down on any duplication in that regard. If it's simple email validation or something like that, duplication probably isn't a big deal. Complex business logic will require a robust error handling and message system to pass user friendly messages back to the front end.

Hope that answers your question. Of course this is a pretty simplistic application to show simply how to wire things up, but it's a start.

sara said:

alter anchor text each time please

administration work
admin job
admin jobs
uk admin jobs
administration career
Sara
administration job

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.