Automated Coder

Exploring the Code of CruiseControl.Net

Archive for November, 2008

Building a User Interface, Part 2

Posted by Craig Sutherland on 27 November, 2008

A Quick Recap

In my last post I started talking about the implementation of the UI for the CCTray replacement. I covered the main window, plus the splash and about windows. In this post I’ll start to delve into the details of the main window – especially how the various parts interact and how they are populated with data.

Data From the Source

All the data to be displayed comes from the controller, which in turn receives them from the communications channel. The channel has a MessageReceived event, which passes a CommunicationsMessageEventArgs instance. This contains a string telling the type of message, the id of the source and a object instance containing any additional data. To facilitate the understanding of messages I’ve also added a class called ServerCommands which contains a number of string constants for the different types of messages:

Server Commands
Server Commands

This class contains commands that will be passed in both directions on the channel. Since the controller is interested in what has changed on the server, it waits for the following commands:

  • ProjectChanged
  • QueueChanged
  • ServerChanged

When any of these commands are received, it triggers the event of the same name on the controller class. It also converts the data object into an instance of the changed type (e.g. server/queue/project) and adds a status message so the user can know the item has changed.

Updating the Main Window

When the main window started up, it added listeners to the three change events on the controller. This handler class InvokeOnUIThread() to handle any cross-thread marshalling and then passes on the require to a method called UpdateItemDisplay(). This is where I need to side-track a bit.

When an item is first loaded, it generates an instance of an IItemDisplay. This interface has a method called UpdateDisplay(), which is responsible for actually updating what the user sees. This way the main window doesn’t need to know about all the various controls and components in itself. Additionally, each node in the server explorer is also associated with an IItemDisplay, which allows the same update mechanism to be used.

Each data object has a list of these IItemDisplay instance associated with it (these are held in a dictionary), and the main window provides access to these lists via the GetItemDisplayList(). When a new item is added, the class doing the add calls GetItemDisplayList() to retrieve the correct list and then adds the new item. The same process is also followed for removing an item. Then, when a update event is received and UpdateItemDisplay() is called, all it needs to do is iterate through this list and call UpdateDisplay() on each IItemDisplay.

To implement this, there are a number of different implementations of this interface. Some of these implementations are:

  • ItemDisplayBase: an abstract implementation that provides some base details
  • TreeNodeItemDisplay: a default implementation for a tree node, used mainly by server explorer implementations
  • ServerTreeNodeItemDisplay: an updater for servers in the server explorer
  • QueueTreeNodeItemDisplay: an updater for queues in the server explorer
  • ProjectTreeNodeItemDisplay: an updater for projects in the server explorer
  • ProjectListViewItemDisplay: an updater for for the projects display tab (more on this later)
  • PropertyGridItemDisplay: an updater for the property grid display tab (more on this later)
IItemDisplay Implementations
IItemDisplay Implementations

Each implementation know the details of the item it is updating, and it knows which details to display – thus simplifying the code in the main window.

Selecting an Item

Since the display has been abstracted away, there needs to be a way to detect which item is currently selected. To complicate matters, my design currently allows for multiple items to be selected – thus raising the possibility that items on different servers could be selected.

To work around these issues I’ve added another interface called ISelectionControl:

ISelectionControl
ISelectionControl

This interface has two methods – one for first determining which processes have been selected, and then a second one for determining which projects have been selected for a process.

When a control on the form is activated (receives focus) the ISelectionControl instance is stored in the main window. Then, when a command is activated that requires a process/project selection the implementation is used.

The server explorer has a implementation called TreeViewSelection, which returns the process id and project name of the currently selected node. If the node is a display-only node (e.g. the holder node for Projects or Queues) then it goes up the tree until it finds a node that is a non-display-only node. Some of the display tabs also have their own implementations.

That covers the displaying of data and the selection of projects, the final area I’ll cover in this post is the display tabs.

Customising the Details

In the main window I have added an area for display tabs. These will replace the projects view area in the current CCTray. While this will offer similar functionality, it also allows the replacement to display a lot more details. For example, as well as a projects list display I have implemented a details display (using the PropertyGrid control) and a queues list.

All display tabs must implement IDisplayTab:

IDisplayTab
IDisplayTab

The Initialise() method is called when the display tab is first added to the window. This will generate and return the actual control to be added (the main window then adds it to the tab control and associated any required event handlers). When the selected item in the server explorer changes, the DisplayItem() or ClearItem() methods are called – these are resposible for changed the display (and generating any IItemDisplays as required).

The Text property is the title of the tab – this is only used when the tab is first added. The MainImageList provides a way of hooking the ImageList on the main window into the display tab (an attempt to reduce memory usage and allow common images). Finally the Selector property an ISelectionControl - which can then be used to select processes and projects. If the display tab doesn’t allow selections, then this property should return null.

I’ve already produced three implementations:

  • DetailsDisplayTab: displays the details on the currently selected item using a PropertyGrid
  • ProjectListDisplayTab: displays a list of projects for the currently selected item
  • QueueListDisplayTab: displays a list of queues for the currently selected item

These have their own associated implementations of IItemDisplay and ISelectionControl.

What’s Next?

This post and the previous have covered most of the details on the main user interface. The next area I’ll cover is how to configure the application. This will also involve some UI windows, but also require examining classes in the other components of the applications.

Stay tuned…

Posted in CruiseControl.Net, Project Leo | Tagged: | 2 Comments »

Building a User Interface, Part 1

Posted by Craig Sutherland on 25 November, 2008

Flashback

A couple of weeks ago I started on my design for a replacement for CCTray. Since then I got sidetracked with merging security changes, but that’s now on hold again. So, it’s time to return to the replacement for CCTray.

In this post I’ll start to cover the user interface (UI). One of my goals for the interface is to make it extensible. I’m intending on supplying some initial implementations of components, but it will also allow other people to add their own components.

The Design

In a previous post I mocked up how I thought the interface would look. The mock-up looked like the following:

UI Components
UI Components

This provides the main window for the application. I’m also planning on adding a splash window, an about window, plus some windows for the configuration (the configuration windows will be covered in a future post). The splash and about windows will be very similar – but display slightly different data. The splash window will show the load progress, while the about information will display information on the application (and in the future the plug-ins).

First Cut

With the above design in mind, here are my first versions of the main window and the about window:

Main Window
Main Window
About Window
About Window

The splash window is very similar to the about window, except without the version, copyright and company labels, also the Ok button is omitted and the grey box displays the status history (you’ll have to take my word on this as I can’t screen shot it!).

The first attempt is very similar to my mock-up – I just changed the menus around a bit. The actions have been included in the monitor menu, but I’ll probably change this later.

Window Flow

When the application first starts, it displays the splash screen. This screen then moves through the following steps:

  • Initialising
  • Loading main window
  • Loading configuration
  • Initialising interprocess communications
  • Starting server monitors

At the end of these steps it then displays the main window (as above). Most of these steps are self-explanatory. Initialising doesn’t actually do anything yet, it’s just a place holder.

The start-up process uses the same bootstrap process as the monitors – but it uses a WinApplicationCommand. This does the normal Windows application start-up steps. During the start-up it generates a controller and a context. The context is a forms context – it just handles the switching of the windows and also adds a slight delay in starting the initialisation.

The controller is what does most of the work. It co-ordinates all actions within the application – including the initialisation. The splash and main windows both have message history hooks that the controller calls to add messages. It also holds references to the interprocess communications and the server monitors. As such it acts as the gateway between the actual UI components and the other parts of the system.

Part of this gateway actions involves listening for messages from the communications channel. When a message is received it fires a relevant event on itself.

Main Window

The main window contains the tool bar, menu bar, server explorer, tab holder, message history and status bar. However, most of these are just pass-through items.

The tool and menu bars just call through to the correct method on the controller. The code-behind will automatically detect which server/queue/project the action is for, but after this the controller is responsible. If the action fails then an error will be displayed.

The server explorer contains a tree of all the servers, plus their queues and projects. This is populated when a server/queue/project changed event is triggered on the controller. Most of the time this just involves making sure the display is correctly updated. Clicking on an item in the explorer will change the item in the tabs. Basically it just fires a change event on all of the display tabs.

The tab holder can hold any number of display tabs. These are set in the configuration. The main window doesn’t really care about these, it just expects them to implement IDisplayTab. This interface allows the window to interact with the tabs – but I’ll talk more on this in my next post.

The message history is a list view that is populated whenever the controller adds a status message. It displays the time and the status message.

Finally the status bar is not being used yet. Eventually I’m thinking of displaying the last status message, plus the currently selected server/queue/project in it.

The main window is also resposible for handling all thread invokes – this is to ensure the correct thread is being used for updating the window.

Finally, the different parts of the window can be hidden. Either the server explorer or the tab holder can be hidden (but not both at the same time) and the message history can also be hidden. At the moment these settings are not persisted, but I’ll add them in sometime.

Time for a Break

That concludes this post on the user interface – this post has mainly been about how it looks, with a little bit on how it works. In my next post I’ll cover the coupling mechanism between the explorer, the controller and the display tabs.

Stay tuned…

Posted in CruiseControl.Net, Project Leo | Tagged: | Leave a Comment »

An Oversight in the Queues

Posted by Craig Sutherland on 21 November, 2008

An Assumption

I while back I wrote a patch to CruiseControl.Net to allow queues to be configured. It all worked fine, and allowed other people to add additional queue functionality.

However, it was recently pointed out, I made an assumption in the development :( My assumption was people would configure it properly – including setting up the links to queues correctly. Instead, someone configured it so the queues weren’t being used by any projects and wondered why the new queue functionality wasn’t working.

When he found the documentation, he then understood why it was happening, but pointed out the application should have validated the configuration and not let it happen. And I agree, the application should stop people making mistakes like this.

Thanks to Alex Hutton for pointing this out.

How Configuration Works

Before I look at resolving the issue, first I’ll quickly cover how CruiseControl.Net handles the configuration, and why this issue can occur.

The configuration file contains a number of XML elements, which are loaded by Exortech.NetReflector. This converts the XML into .Net objects – it uses attributes on the classes and dynamic look-ups to achieve this. The end-result is an XML element goes in and an object comes out. NetReflector applies some validation rules (mainly from the attibutes) and raised any errors.

CruiseControl.Net then checks the type of the returned object. If it is a project, it gets added to the list of projects, likewise if it is a queue. Any other object types will cause an exception to be raised (since these are the only two types that can be handled at the top-level).

And that’s it for validation – no more checks are done after this!

Validating Configuration

Now that I’ve shown that we have two lists – one for projects and the other for queues – it’s time to do some validation. Currently I’m only going to add one validation rule: all queues must be referenced by a project. It is not an issue if a project references a non-defined queue as CruiseControl.Net will automatically create the required definitions (using the default settings).

The check itself is very simple:

  • Iterate through the list of queues
  • For each queue definition, check that at least one project uses it (the QueueName has been set to the name of the queue)
  • If the queue is not used, then raise an exception

It was a little bit harder deciding where to add this exception. In the end I decided to add it to NetReflectorConfigurationReader. This is the class that is responsible for doing the actual load from XML. I put it in here for two reasons:

  • It already handles the unknown item validation (plus since it wraps NetReflector it has its validation)
  • Sometimes people will do a validation call to the console – this calls to this class and no further

End of Assumption

And that finishes the fix for my assumption. Now CruiseControl.Net will validate the queues and make sure they are being used. I have added it to the trunk and it will be included in the next release.

Posted in CruiseControl.Net | Tagged: , | 1 Comment »

Merge Update

Posted by Craig Sutherland on 21 November, 2008

After talking with Dave Cameron, we’ve decided to put the merge on hold for a short while. This is because of a critical bug that has occurred in the 1.4.1 release. Since there is already a fix in place, Dave is going to do a 1.4.2 release sometime soon.

When this release is out, and looks stable (i.e. we don’t find any more critical bugs) – then Dave has volunteered to do the merge for me :)

As such, at the moment I am tidying things up for the security merge (making sure the unit tests work, increasing the test coverage, fixing some small bugs, etc.)

I’ll add updates as they happen.

Posted in CruiseControl.Net, Security | Leave a Comment »

The Merge is Happening

Posted by Craig Sutherland on 19 November, 2008

Release 1.4.1 is Out

David Cameron announced yesterday that the 1.4.1 release of CruiseControl.Net has been released. This is mainly a fix build (hence the setting of only a revision point in the version number), but I’m proud to say it now includes some of my patches (queue configuration and duplicate handling, plus a few minor fixes).

More importantly this is the release I have been waiting for – now we can start merging the security work into the trunk.

What’s Merging?

Over the past few months I’ve been writing about enhancements I’ve been working on for CruiseControl.Net. Since these changes are likely to have far-reaching effects, I’ve been submitting them to a separate branch within Subversion.

In order of significance, these changes are:

  • Security
  • Multi-language
  • Extension points

Between these three changes I’ve modified nearly every file in Core, a large number of files in Remote, plus a sizeable number of files in the other projects (e.g. the projects for CCTray and the dashboard).

As such, it’s been taking me a bit of time to get everyting merged (hence the lack of posts for the past few days). I am slowly working my way through all the files, and making sure I’ve built unit tests for every change I’ve made.

Future Work

I recently started writing about a proof-of-concept I’ve been working on for replacing CCTray. This will not be included in the next release (too much work remaining). Therefore I won’t be adding this into the trunk.

I’m also planning on expanding the multi-language work I’ve done to include first the dashboard and then CCTray. As I have time to do this I’ll add it directly into the trunk – so it should be ready for the next release. However this will still require some translators.

Finally, I had started looking at what would be required to add dynamic value setting to projects on the server. This is where there is a single project, but it allows the user to choose build values when they trigger a force build (some people have been requesting this for a while). The concept is fairly simple, it’s just a matter of building it in a way that is both flexible and robust.

Nearly There

Thank you to all of those who have been following my posts on security and the other changes I’ve been making for CruiseControl.Net. I’m nearly there for adding it to the trunk – and then we can really start testing it.

More details to come…

Posted in CruiseControl.Net, Security | Leave a Comment »

Monitoring a Server

Posted by Craig Sutherland on 15 November, 2008

Reaching Out

In my last post (here) I started work on a replacement for CCTray. My initial work involved building a bootstrap application that would start an application command. In this post I’ll build an application command that uses .Net remoting to monitor a remote server.

In my original design (see the figure below), the application consists of four main parts – the bootstrap, the UI, the comms channel and a series of monitor.

UI Design - Interactions
UI Design – Interactions

Since the bootstrap is working, it’s now time to implement a server monitor so I can view some remote servers.

Design Concept

The basic goal behind a monitor is that it is an independant process that monitors a server (remote or local) and tells the application when things have changed. To increase the robustness and stability of the application, these will run in their own process – hence the requirement for a comms channel.

The monitor will wait for status changes on the server and then generate events on the channel telling the application. This does make things more interesting considering the current .Net remoting (and HTTP) does not tell the clients when things have changed, instead it just has a snapshot of the current state.

So, to get around this the monitor will poll the server on a regular basis (similar to the current CCTray implementation). When it first polls it stores the snapshot it retrieves. Then every snapshot it compares against the original to see if anything has changed. If things have changed, then it fires the relevant events.

Monitor Host

Since most of the monitors will work in the same way, I wrote a component that will host the monitor. This handles things like initialising the actual monitor, starting communications, loading listeners and handling shut-downs.

Since this is a core part of the functionality, I added it to the Core project. The class is called ServerMonitorCommand:

ServerMonitorCommand
ServerMonitorCommand

This class implements IApplicationCommand hence has the public Run() method. In order for this approach to work, I added another interface called IServerMonitor, which is the actual server monitor – ServerMoniterCommand just provides the framework for it. This interface is below:

IServerMonitor
IServerMonitor

This has a lot more expected methods, properties and events. These allow ServerMonitorCommand to handle the communications.

Initialisation

The first thing the host needs to do is intialise the actual monitor. This is done via a command-line argument – the address of the server. When the server address has been found (using IArgsParser) it then loads the configuration (via IConfigurationService) and attempts to find the server configuration. If any of these steps fail, then the monitor will get an exception and fail to start.

The next step is to initialise the communications channel. The actual communications channel is initialised by the UI, but the server monitor still needs to register with the channel. The channel is a class that implements IInterProcessCommunictions. I’ll write more about this interface in a future post, but for now just know it is the interface for sending messages between processes. This interface has a property for the channel URI, a Start() and Stop for registering and un-registering a process, and finally a method for sending messages and an event for handling received messages.

As part of the initialisation, the type of IInterProcessCommunictions implementation is received from the configuration, the channel URI set (from the command-line args) and then the Start() method called. Since the implementation type is stored in the configuration this can be changed (especially if someone comes up with a better implementation than mine!)

Next step in the initialisation is instantiating the actual monitor (the implementation of IServerMonitor). This involves generating an instance of the implementation class, setting the remote address to monitor and loading any optional configuration settings. Again, the configuration is something I’ll handle in a future post, but for now, the configuration options are set by the implementation – so it can have any required settings. The configuration window will handle the settings (via a PropertyGrid - more to come).

The only remaing part to initialise are the listeners. The only requirement (currently) for a listener is that it implements IStatusListener. In future this may change as I haven’t tried implementing any listeners yet. Basically the implementation has a Register() method that takes in an instance of IServerMonitor. The idea is the listener will then subscribe to the events that it is interested in and will do any processing based on the events.

Monitoring

Once everything is initialised (which is the bulk of the work), all that remains is to call the Start() method and tidy up. I’ve included both of these together because it is up to the monitor to enter its poll loop (or other wait state). This is assumed to keep polling until something happens to break the wait state (either a stop message, an error or some other event).

As such when the Start() method call returns ServerMonitorCommand assumes everything has finished and tidies up. This involves closing down the listeners and the communications channel.

Handling Incoming Requests

The only other job of ServerMonitorCommand (currently) is to handle incoming requests from the communications channel. IInterProcessCommunictions has an event called MessageReceived which is fired whenever a message is received. Because I don’t know all the possible message types I’ve built a generic message class (this inherits from EventArgs):

CommunicationsMessageEventArgs
CommunicationsMessageEventArgs

This class has an identifier for the source process (the Identifier from the Process), the message type and a data holder. The message type is a string, which can be set to any value. I’ve added a static class called ServerCommands which has the currently recognised commands in it – this will probably expand over time. The data holder is just an object which can take any object that can be serialised. However it is expected that the sender and the receiver both know what type it is and handle any differences gracefully.

ServerMonitorCommand subscribes to the MessageReceived event and checks the message type against the commands it knows about (using a switch statement). The known commands then result in the appropriate call to the IServerMonitor instance.

Polling a .Net Remoting Server

That covers the host for a server monitor. Now it’s time to take a very quick look at an implementation of IServerMonitor. Any monitor will consists of two logical parts: a remote monitor and an gateway for passing on commands. For both parts the .Net remoting monitor uses an instance of ICruiseManager that has been created via remoting.

For the .Net remoting monitor, the remote monitor part conists of a poll loop that checks every five seconds. This check involves retrieving the latest snapshot from the remote server and comparing against the last snapshot. If any items (e.g. the server, a queue or a project) have changed, then the relevant event if fired. If nothing changes, then no events are fired. The ServerMonitorCommand handles these events and passes them onto the communications channel (it does this via a special listener called CommunicationsStatusListener).

The reason for using events is to allow for a passive listener in the future. A passive listener is one that registers itself with some sort of listening mechanism and then enters a wait state (no polling). When the remote server triggers the event, then the listener activates, handles the event and returns to the wait state. This involves a lot less work for the server as it is not required to constantly poll the remote server (I’m thinking of implementing this with WCF in the future).

The gateway part involves the implementation of the ForceBuild(), AbortBuild(), StartProject() and StopProject() methods. These method calls are passed onto the ICruiseManager instance.

And that’s all that is needed for a monitor.

Wrap Up

In this post I covered my design for listening to remote servers. This involved a generic implementation called ServerMonitorCommand that provides a framework for any type of monitor. This can be replaced with a custom implementation if desired, but it provides most of the glue required to communicate with the rest of the application.

I also talked about the interface for monitors to implement to use ServerMonitorCommand, how it is initialised and called, and quickly talked about how the .Net remoting implementation works.

That completes the second component for the new CCTray – the monitor for listening to remote servers. The application now has the ability to start-up and monitor servers, now it needs to display things to the user. In my next post I’ll start looking at the UI!

Posted in CruiseControl.Net, Project Leo | Tagged: | Leave a Comment »

Starting the Monitor

Posted by Craig Sutherland on 12 November, 2008

Introduction

This is the first in a series of posts of building a prototype replacement for CCTray (my basic design is here). This series will mainly be about what I have done and why. At the end of the series I’ll have a working prototype replacement for CCTray.

A Beginning Point

Every application needs a start point. This will have at least a Main routine, perhaps with input arguments and it will do something (at least for a working application).

My prototype is no different, but I do have one twist. The same application will be used both for starting the main UI interface and any worker processes. As such it needs a way to distinguish between the various calls. To do this the application will check the input parameters against the configuration. The basic process will be:

  1. Load the application configuration
  2. Check the args for a command name, otherwise use the default from the configuration
  3. Instantiate an instance of the command
  4. Load the user configuration
  5. Run the command

This sounds like a pretty simple process and in reality, it is!

However to make the application more testable, I moved most of this functionality into the Core project and exposed it via interfaces. The BootStrap project just goes through the above sequence, plus adds some logging information.

The Application Configuration

The configuration for the application comes from two locations. The first is the configuration stored in the app.config file, the second comes from an XML config file stored in the user settings (more on this later).

The app.config configuration stores settings on the commands to run, the default settings and the location of the XML configuration. This information is accessed via the IApplicationConfigurationReader interface:

IApplicationConfigurationReader
IApplicationConfigurationReader

To load the configuration there is a class (ConfigurationHandler) in the bootstrap project which implements IConfigurationSectionHandler. This is to allow the configuration to use the configuration framework within .Net. This creates an instance of the class that implements IApplicationConfiguratioReader (XmlApplicationConfigurationReader) and calls ReadConfiguration(). This method then loads all the configuration settings. If the settings are missing then the default settings are initialised instead.

The four properties are straight-forward, they merely expose different settings that can be used. ConfigurationLocation is where the user configuration is located – by default this is in the ApplicationData folder. DefaultCommand is the command that will be used if no command was passed in on the command-line. This is a required property and must be set in the configuration. Finally InterProcessType and InterProcessUri are used for configuring the communications channel – I will talk more about these when I get to the communications in a future post.

The final part of this interface is RetrieveCommand(). This attempts to match the requested command with a command that is stored in the list. If the command cannot be found, it returns null, otherwise it will return the type to use for the command.

Parsing the Args

To handle the parsing of the command-line I have added an interface called IArgsParser:

IArgsParser
IArgsParser

The property is to allow the application to set the command-line args – this could have been a method, but it was just as easy to use a property.

FindCommand() will then search the args for a command to run. This will be the first arg that is not prefixed with a dash or slash. It will then use an instance of IApplicationConfigurationReader to find the type of command to run and return this. If either step fails it will return null (and cause the application to crash!)

CheckForArgument() and RetrieveArgument() are helper functions for finding a specific argument. CheckForArgument() merely returns whether the argument exists or not, while RetrieveArgument() returns the actual value. These are used in various places within the application.

Instantiating the Command

The actual commands, or logic to be run, must implement IApplicationCommand:

IApplicationCommand
IApplicationCommand

This has one method – Run(). This takes in the args, application configuration and user configuration.

To instantiate this instance I have a helper class called ObjectHelper. The Create<TObject>() method takes in a string containing the type name and returns a typed instance (hence the generic parameter). At the moment it mainly performs validation, but in future I will extend it to also handle searching in an extensions folder.

I’ll be posting a lot more about this interface and some implementations in the future.

Loading the Monitor Configuration

The final interface used by the bootstrap is IConfigurationServer:

IConfigurationService
IConfigurationService

This interfaces merely saves or loads the user configuration to disk (or potentially another location). When I talk about the configuration in a future post I’ll talk about how this interface works. For now, just know that the bootstrap instantiates an instance of this interface from the configuration and passes it onto the command.

That’s It!

The final step is just to call the Run() method on the application command, which the bootstrap does. From here on it is up to the application command to do all the work.

In my next post I’ll start looking at some of the commands and how they tie into the configuration.

Posted in CruiseControl.Net, Project Leo | Tagged: | 1 Comment »

A Brave New CCTray

Posted by Craig Sutherland on 10 November, 2008

Moving on from CCTray

In my last post on CCTray (here) I mentioned a number of what I saw as limitations on CCTray in its current implementation. In this post, it is time to start look at an alternate design for CCTray. Over time I will work on this design and eventually produce a prototype of what I think would be a replacement for CCTray.

Design Goals

Before I begin on the design, the question is what should this application do, what are the constraints and expectations and what is the basic philosophy behind the design.

The basic goal of this application is to provide the ability to monitor, in real time, what is happening on one or more servers that hosts the CruiseControl.Net server. It should also be able interact with the servers to provide a rudimentary level of control. This includes:

  • Forcing builds
  • Aborting builds
  • Stopping and starting projects
  • Clearing queues
  • Sending messages to be viewed by other users (e.g. fix notifications)

Where possible the application should be extendible. This means that no assumptions should be made about what will implement any part of the application. It should also be robust (handle failures without crashing), informative (let the user know what is happening) and easily usable (be easy to setup and run). Some nice to have features include automatic updates and international.

With this requirements list, what are the limitations? First it will require .Net 2.0 or higher. It will (at least initially) require Windows to run on (since I don’t know enough about Mono/Linux). And finally it must not require any changes to the server side. This also means it should be able to monitor older versions of CruiseControl.Net (I’m thinking at least 1.3 or later).

Components

Since one of the objectives of the new design is modularity, the new application will consist of a number of different interacting components. The following diagram provides a logical view of these components:

Components
Components

These break down into three categories – infrastructure, UI and monitor. The infrastructure components are common to all parts of the application and include items like interfaces, configuration and the bootstrap (more on this to come). The UI components are display components – they provide the actual interface that a user will see. Finally the monitor components do the actual monitoring of the remote server.

They are deliberately separate from the UI components, allowing them to be instantiated and used without requiring any UI components at all. If these three categories are implemented in separate projects (my plan) then it will be possible to build a wide variety of applications with only changing some of the modules.

The core component provides functionality that can be used by all other components. As such I envisage that it will be referenced by all components.

The bootstrap is a process launcher. It can take in a variety of command-line arguments and launch different configurations as required. When I talk about the interactions below this should become clearer.

The UI will contain the shell for the user interface. It can either be a complete interface in itself, or it can rely on optional display components (I will provide some default components).

Finally the monitor is the actual heart of the new application. This will be a standard interface that allows people to implement any transport protocol they like (initially I’ll build protocols for .Net Remoting, HTTP and WCF). The actual transport is called a listener – this merely monitors the remote server and passes on events. Therefore the other half of a monitor is a set of listeners. These can do any type of processing they like – X10, speech, notification icons, etc.

Interactions

The above model showed the various components, now it’s time to look at how this components will interact. The following diagram shows a logical view of this:

Interactions
Interactions

These different components work together in the following way:

  1. The user starts up the application. This is call to the bootstrap component, which starts up the default UI component.
  2. The bootstrap initialises an instance of the UI component and starts it running.
  3. The UI component then iterates through the configuration and calls the bootstrap component to start up an instance of each monitor. The new instance will run in a separate process.
  4. The bootstrap component initialises an instance of the server monitor and starts it running.
  5. Finally all the separate processes communicates via a standard communications channel (also changeable).

This model means each monitor is running in its own process – if a problem happens with a monitor it won’t take down the entire application! It also simplifies development as it removes needing to worry about threading and locking issues (well, also removes). Plus it does open a possibility for hot-swapping in the future (if desired).

The downside is there will be a slightly larger memory hit (since each monitor is its own process), plus some more processing is required for passing messages to the communications channel and picking up messages.

While this may appear to be a more complex model, it is possible for implement a threaded version of the UI that doesn’t have separate processes, or even a version that doesn’t run monitors at all (e.g. for a command-line version). In a future post I’ll look into this some more.

UI Design

For the UI I thought it would be good to move the design closer to a typical windows application. The following mock-up shows the rough areas for the main UI:

UI Components
UI Components

Most of these are self-explanatory. The menu bar, toolbar and status bar are the same as in a typical windows application. It should be possible to add commands to the first two and additional statuses as required.

The bottom part of the mockup shows an area for message history. This allows the UI to display any relevant messages that the user might be interested in. These would be things like status updates, user commands and results, and any errors. The user will have the ability to turn this area off if not desired (or perhaps it should default to off and they can turn it on).

On the left is something I’m calling a server explorer (for the moment). This would list all the servers and their queues (similar to the current queues display), plus the projects for each server. Over time more information may be added to the explorer (e.g. extra views, wizards, editors, etc.)

The final components are the tab selector and display. The user would be able to configure what project/server/queue displays they want, and they would appear in this area. As the user clicks on different items in the server explorer, this area would be updated. The selected tab display would also have the ability to interact with the menu bar, toolbar and status bar.

I’m envisaging a UI interface that looks something similar to the management console that comes with Windows (or at least some versions of Windows). The various bars would be consistent, but the other areas would be configurable by the user.

Summary

I’ve covered a bit in this post about what I see as a future (re)design for the CCTray application. I’ve covered what the modules, the interactions between the components and (very quickly) the UI.

This gives me enough to start on for a quick prototype of how the application will work. During my holiday in China I used some of my spare time to do just this, and over my next few posts I’ll start to cover some of what I have implemented.

However, be warned, this is still very much in a proof of concept stage. I haven’t ironed out all the issues (or all the errors) and it still needs a lot of work. But it should be enough to see whether it is worthwhile continuing the project or not :)

Stay tuned…

Posted in CruiseControl.Net, Project Leo | Tagged: | 1 Comment »

Internationalisation – part 4

Posted by Craig Sutherland on 8 November, 2008

Previously

Up until now I’ve been working on converting hard-coded strings to resource-based strings. This has all been in preparation for allowing people to change their language (or at least have their current language displayed). These changes make use of the resource functionality in .Net, plus the resource-based code generation in Visual Studio.

Now that I have some translated strings (thanks Ruben), I’m ready to test the language changing. In this post I’ll go over what I’ve done and why.

Configuring the Language

When I initially wrote about allowing different languages, the first feedback I got was that people like the idea, but they also want to be able to stick with English for their own use. This means giving people the ability to change which language they use.

By default the current UI culture is set to the UI culture of the machine. This is normally a combination of the language and region (i.e. for me, my UI culture is en-NZ). This allows both different languages and different date/time/numeric settings depending on where in the world a person is (i.e. I live in New Zealand and speak English).

In CruiseControl.Net people want to be able to change this (at least I’m assuming that their culture settings are non-English). Since the CruiseControl.Net server has no user interface, the best place for doing this is in the configuration.

Back when I started contributing to CruiseControl.Net I added the ability to set extensions in CruiseControl.Net. Part of this work involved letting people set, in the configuration file, which extensions to use. To do this I added a class called ServerConfigurationHandler, which implements IConfigurationSectionHandler. This means that configuration will be handled by the .Net configuration framework.

Now it’s time to modify this class and how it works. For my initial implementation I just returned a List<ExtensionConfiguration>, now I need it to return more (but still the list). To handle this I have added a new class called ServerConfiguration, which includes the current list plus adds the ability for people to add other configuration settings. This required modify ServerConfigurationHandler to return the new class and then modifying CruiseServerFactory to use the new class instead of the list.

Now I’m ready to add some new configuration. The only setting I’m going to add is culture name – this will be the language code the application will use. The default setting is the current UI culture name. The handler checks the configuration to see if the value is set, if so it loads it in, otherwise it just uses the default.

So, the new configuration looks like this:

<cruiseServer>
  <culture name="nl"/>
</cruiseServer>

To change the language just change the name of the culture :) But default this is commented out so the machine’s settings are used.

Changing the Language

Changing the language is very simple – just need to set the culture on the current thread. There is one limitation – the CurrentCulture property cannot be a neutral culture. To get around this, I’ve used CurrentUICulture instead. This is the property used by the resource manager to work out which language resources to use, while CurrentCulture is used for additional settings like number and date/time formats.

There are two projects where this needs to be set – console and service. The console project uses ConsoleRunner in the core project, while service does all its own instantiation and initialisation. Therefore the language changing logic needs to be in both locations.

The actual logic is straight forward. First attempt to get the configuration using ConfigurationManager. Next check if the configuration was retrieved (it will return null if there is none) and see if the culture has been set. If these conditions have been met, then instantiate the culture and set the CurrentUICulture property on the current thread.

I also modified the locations where a new thread is started to set the CurrentUICulture based on the culture of the calling thread – this should propagate the culture to all child threads.

Some quick testing showed that the culture is successfully changed and the applicaton now uses the desired language :)

Note: culture codes in .Net have two parts – the language and the area. The language code is always used, while the area defines the additional formatting settings. The resource manager will first attempt to match the language/area combination. If this fails it will attempt the language. Finally if both of these checks fail it will use the default resources – in this case English. As such it is possible to set the culture in the configuration to either (e.g. I could set en-NZ) and it will still work. But unless the language has been added you’ll get English. The other format settings are ignored (for the moment).

The Service

As I stated earlier, the service project also uses the culture settings. Like console, it provides an access point to the functionality in the core project. Unlike console, it has its own hard-coded strings. Therefore my final change for this post was to go through this project and convert all hard-coded UI strings to resource strings.

Now both of the back-end interfaces support multi-lingual interfaces.

The next step in this process is to start looking at the user interfaces – CCTray and the dashboard. Over the next few days I’ll take a look at them and then start to plan how I’ll convert them to use resources.

Posted in CruiseControl.Net | Tagged: | Leave a Comment »

Moving on from CCTray

Posted by Craig Sutherland on 7 November, 2008

What’s Wrong with CCTray

Before I begin this post, I just want to say that I am a fan of CruiseControl.Net and have used it with great results. I still have CCTray installed on my machine and think it provides a good view onto what is happening to our build servers.

Now for the “however”. Having looked at the code, and having developed a few additions for it, I’ve discovered that the code for it has some limitations. Here are some of the limitations that I’m aware of:

  • No extension model for adding new functionality – new extensions have to be baked into the application (e.g. X10, speech, etc.)
  • The application is starting to become bloated – there is no way to remove unwanted features (e.g.  the UI code when writing a console app, X10 because there is no need for it, etc.)
  • It polls per project, with a separate network call per project
  • It also polls per server, but not at the same time – thus introducing a delay between updating the queues and the projects

Given the small size of the application, you could argue that the first two points aren’t really that applicable, but I think as the application grows they will become more of an issue. And as I discovered when I wrote my CCCmd tool (which is a command-line interface to CCTrayLib), there’s a huge amount of additional functionality that gets included no matter what. We could split CCTrayLib into UI and non-UI components, which would reduce the size of the libraries (plus reduce the required dependencies).

However, my main issue is a more fundamental issue with the way CCTray works, read on…

From Projects to Servers

From what I understand, CCTray started as a project monitor. Initially it only monitored one server – from which the user would choose the projects to monitor.

As time went on, the developers realised that people would want to monitor multiple servers. So they added the ability to connect to multiple servers. This had the side affect of introducing the bug where the incorrect server name was displayed for projects with the same name on different servers.

More time passed, and queues were added. Suddenly CCTray needed to monitor the entire server, so new code was added to poll the servers and update the queues. I don’t know whether they looked at the project polling code, but a second set of polling code was added which included all the same information.

So, over time CCTray has added a lot more functionality, become more complex and has (arguably) not optimised code like it could have.

An example of this is the project vs. server polling. Each project poll downloads the relevant project details – nice and small with only the relevant project details are included. But the server poll downloads everything for the server – including all the project details again! It would be nice to use just the one server poll, which then feeds the information to the project polls.

What Am I Saying

My main point is not that CCTray and its code are horrible, but that a good redesign and perhaps rebuild is necessary. I say rebuild, as the project polling is right at the heart of CCTray and it would be challenging to refactor it out!

As well as the performance improvements (i.e. removing project polling) I think there are a few other factors that need to be considered in the redesign:

  • Extensibility – the ability to add new functionality to the application without forcing everyone to include it. This would include both new transports (e.g. WCF, messaging, etc.) and notifiers (e.g. X10, speechlib, etc.)
  • Robustness – the application should continue to work, even if an extension doesn’t behave properly (I currently have an issue with CCTray were if I use my own custom icons it crashes after a day or so)
  • Modularity – should be able to build different front-ends that don’t include all the code for the other front-ends (e.g. WinForms, console, WPF, etc.)
  • An update mechanism – it would be great to have some sort of auto-update mechanism where CCTray would be updated to match the server automatically (although this would need to be optional as I know some environment would not want this). This could also be used for selecting and updating extensions
  • Logging – it would be nice (but not required) to have logging in CCTray, similar to the server, so it would make diagnostics and problem solving easier
  • International – finally it shouldn’t be limited to just English

I know this list may seem to be asking for a lot, but I’ve thought on this a bit for the past few weeks and in my next post I’ll start to write up what I think could work as a redesign.

Stay tuned…

Posted in CruiseControl.Net, Project Leo | Tagged: | 1 Comment »