The Journey of the Lunch Launcher: Part 7 - The Lunch Manager

Part 1 - The origins of the 'lunch launcher'
Part 2 - MEDC 2007
Part 3 - Managing the Transport
Part 4 - Sending messages
Part 4b - The output channel
Part 5 - Receiving messages
Part 6 - Processing messages

The journey is almost at an end.  Today, I am going to talk about the last major piece of the Lunch Launcher puzzle -- the lunch manager.

As with all entries in this series, please note that the following disclaimer covers all examples contained herein.
//----------------------------------------------------------------------- //THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY //KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE //IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A //PARTICULAR PURPOSE. //-----------------------------------------------------------------------
What is the lunch manager?
The lunch manager is a class (conveniently called "LunchManager") which controls the transports, serializers and other objects which come together to allow users to coordinate lunch with their friends.  In fact, other than purely data objects (Buddy, LunchInvitation, etc), the LunchManager is the only object known to the application.

MEDC 2007
From the beginning of the Lunch Launcher project, I separated the user interface from the application logic.  As any who have attended my sessions (or watched on the conference DVDs) in the past several years can attest, I am a huge proponent of GUI-Logic separation.  The result of this design is the LunchManager.  As mentioned above, the LunchManager is the central object of the Lunch Launcher's logic.

It is the responsibility of the LunchManager to load the buddy and restaurant lists as well as control the lifetime of the listeners and the sending of messages.

For MEDC 2007, the LunchManager's Start method was very simple.
private void Start() {     // start the listeners     ThreadPool.QueueUserWorkItem(InvitationListener);     ThreadPool.QueueUserWorkItem(ReplyListener);     ThreadPool.QueueUserWorkItem(LunchDetailsListener); }

The remainder of the LunchManager (not counting buddy and restaurant list loading methods) has been previously discussed as part of the sending and receiving installments.

Current Version
In the current (November 2007) version, the LunchManager contains many of the details of the optimizations seen in the sending and receiving discussions.  Specifically, the management of serializers and transports.
private Dictionary<Type, LunchObjectSerializer> m_Serializers =     new Dictionary<Type, LunchObjectSerializer>(); private LunchObjectSerializer GetSerializer<T>() {     // get the serializer     LunchObjectSerializer serializer = this.m_Serializers[typeof(T)];     Debug.Assert(null != serializer,                 "Requested serializer has not been created");     return serializer; } private Dictionary<Type, TransportObjects> m_Transports =     new Dictionary<Type, TransportObjects>(); private TransportObjects GetTransport<T>() {     // get the transport     TransportObjects transport = this.m_Transports[typeof(T)];     Debug.Assert(null != transport,                 "Requested transport has not been created");     return transport; }

Serializers and transports are now created at startup and kept for the duration of the application.  This improves performance by reducing the amount reflection (serializer creation time) and garbage (recreating transports and serializers).

As a result, Start has been refined.
public void Start() {     // add the event handlers to the lookup table     this.m_Events.Clear();     this.m_Events.Add(typeof(LunchInvitation), LunchInvitationReceived);     this.m_Events.Add(typeof(LunchInvitationReply), LunchReplyReceived);     this.m_Events.Add(typeof(LunchDetails), LunchDetailsReceived);     // add serializers to the dictionary     this.m_Serializers.Clear();     this.m_Serializers.Add(typeof(LunchInvitation),                            new LunchObjectSerializer(typeof(LunchInvitation)));     this.m_Serializers.Add(typeof(LunchInvitationReply),                            new LunchObjectSerializer(typeof(LunchInvitationReply)));     this.m_Serializers.Add(typeof(LunchDetails),                            new LunchObjectSerializer(typeof(LunchDetails)));                      // add transport objects to the dictionary     this.m_Transports.Clear();     this.m_Transports.Add(typeof(LunchInvitation),                           new TransportObjects(InviteChannelName));     this.m_Transports.Add(typeof(LunchInvitationReply),                           new TransportObjects(ReplyChannelName));     this.m_Transports.Add(typeof(LunchDetails),                           new TransportObjects(DetailsChannelName));                     // start the listeners     ThreadPool.QueueUserWorkItem(InvitationListener);     ThreadPool.QueueUserWorkItem(ReplyListener);     ThreadPool.QueueUserWorkItem(LunchDetailsListener); }

As you can see, Start now performs a bit more work.  The event, serializer and transport collections (Dictionary<TKey, TValue>) are populated prior to the listeners being started.

Stop gets the following implementation. 
public void Stop() {     // channels are stopped by closing them     foreach(TransportObjects trans in this.m_Transports.Values)     {         trans.InputChannel.Close();     }                  // NOTE: The listener threads will uninitialize the transports when they     //  exit (shutdown or fatal condition) }

As I described when talking about the listeners, calls to Receive return immediately with a value of null when the input channel is closed.  Stop takes advantage of this and simply closes the input channel for each transport in the collection.

What's next?
That wraps up the details of the Lunch Launcher.  After a long and winding road, I have brought the idea to life and had the privilege to demonstrate it in front of a packed session at MEDC.  Thanks to the entire .NET Compact Framework team for helping to keep the idea alive and to keep pushing the platform to make it possible.

In the next (final?) installment, I will take a higher level view of what I have learned and what is next on my journey.  As I have mentioned previously, as I get time to work on the Lunch Launcher, I plan to update the relevant posts with any significant changes.

Take care!
-- DK

[Edit: add snippet disclaimer && fix snippet formtting]

Disclaimer(s):
This posting is provided "AS IS" with no warranties, and confers no rights.
The information contained within this post is in relation to beta software.  Any and all details are subject to change.