Chapter 33. IoC Quickstarts

The Spring.NET Framework

Chapter 33. IoC Quickstarts

33.1. Introduction

This chapter includes a grab bag of quickstart examples for using the Spring.NET framework.

33.2. Movie Finder

The source material for this simple demonstration of Spring.NET's IoC features is lifted straight from Martin Fowler's article that discussed the ideas underpinning the IoC pattern. See Inversion of Control Containers and the Dependency Injection pattern for more information. The motivation for basing this quickstart example on said article is because the article is pretty widely known, and most people who are looking at IoC for the first time typically will have read the article (at the time of writing a simple Google search for 'IoC' yields the article in the first five results).

Fowler's article used the example of a search facility for movies to illustrate IoC and Dependency Injection (DI). The article described how a MovieLister object might receive a reference to an implementation of the IMovieFinder interface (using DI).

The IMovieFinder returns a list of all movies and the MovieLister filters this list to return an array of Movieobjects that match a specified directors name. This example demonstrates how the Spring.NET IoC container can be used to supply an appropriate IMovieFinder implementation to an arbitrary MovieLister instance.

The C# code listings for the MovieFinder application can be found in the examples/Spring/Spring.Examples.MovieFinder directory off the top level directory of the Spring.NET distribution.

33.2.1. Getting Started - Movie Finder

The startup class for the MovieFinder example is the MovieApp class, which is an ordinary .NET class with a single application entry point...

using System;
namespace Spring.Examples.MovieFinder
{
  public class MovieApp
  {
    public static void Main ()
    {
    }
  }
}

What we want to do is get a reference to an instance of the MovieLister class... since this is a Spring.NET example we'll get this reference from Spring.NET's IoC container, the IApplicationContext. There are a number of ways to get a reference to an IApplicationContext instance, but for this example we'll be using an IApplicationContext that is instantiated from a custom configuration section in a standard .NET application config file...

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="spring">
            <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
            <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
        </sectionGroup>
    </configSections>
    <spring>
        <context>
            <resource uri="config://spring/objects"/>
        </context>
        <objects xmlns="http://www.springframework.net">
            <description>An  example that demonstrates simple IoC features.</description>
        </objects>
    </spring>
</configuration>

The objects that will be used in the example application will be configured as XML <object/> elements nested inside the <objects/> element.

The body of the Main method in the MovieApp class can now be fleshed out a little further...

using System;
using Spring.Context;
...
    public static void Main ()
    {
      IApplicationContext ctx = ContextRegistry.GetContext();
    }
...

As can be seen in the above C# snippet, a using statement has been added to the MovieApp source. The Spring.Context namespace gives the application access to the IApplicationContext class that will serve as the primary means for the application to access the IoC container. The line of code...

IApplicationContext ctx = ContextRegistry.GetContext();

... retrieves a fully configured IApplicationContext implementation that has been configured using the named <objects/> section from the application config file.

33.2.2. First Object Definition

As yet, no objects have been defined in the application config file, so let's do that now. The very miminal XML definition for the MovieLister instance that we are going to use in the application can be seen in the following XML snippet...

<objects xmlns="http://www.springframework.net">
    <object name="MyMovieLister"
      type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
    </object>
  </objects>

Notice that the full, assembly-qualified name of the MovieLister class has been specified in the type attribute of the object definition, and that the definition has been assigned the (unique) id of MyMovieLister. Using this id, an instance of the object so defined can be retrieved from the IApplicationContext reference like so...

...
    public static void Main ()
    {
      IApplicationContext ctx = ContextRegistry.GetContext();
      MovieLister lister = (MovieLister) ctx.GetObject ("MyMovieLister");
    }
...

The lister instance has not yet had an appropriate implementation of the IMovieFinder interface injected into it. Attempting to use the MoviesDirectedBy method will most probably result in a nasty NullReferenceException since the lister instance does not yet have a reference to an IMovieFinder. The XML configuration for the IMovieFinder implementation that is going to be injected into the lister instance looks like this...

<objects xmlns="http://www.springframework.net">
    <object name="MyMovieFinder"
        type="Spring.Examples.MovieFinder.SimpleMovieFinder, Spring.Examples.MovieFinder"/>
    </object>
</objects>

33.2.3. Setter Injection

What we want to do is inject the IMovieFinder instance identified by the MyMovieFinder id into the MovieLister instance identified by the MyMovieLister id, which can be accomplished using Setter Injection and the following XML...

<objects xmlns="http://www.springframework.net">
    <object name="MyMovieLister"
      type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
        <!-- using setter injection... -->
        <property name="movieFinder" ref="MyMovieFinder"/>
    </object>
    <object name="MyMovieFinder"
        type="Spring.Examples.MovieFinder.SimpleMovieFinder, Spring.Examples.MovieFinder"/>
    </object>
</objects>

When the MyMovieLister object is retrieved from (i.e. instantiated by) the IApplicationContext in the application, the Spring.NET IoC container will inject the reference to the MyMovieFinder object into the MovieFinder property of the MyMovieLister object. The MovieLister object that is referenced in the application is then fully configured and ready to be used in the application to do what is does best... list movies by director.

...
    public static void Main ()
    {
      IApplicationContext ctx = ContextRegistry.GetContext();
      MovieLister lister = (MovieLister) ctx.GetObject ("MyMovieLister");
      Movie[] movies = lister.MoviesDirectedBy("Roberto Benigni");
      Console.WriteLine ("\nSearching for movie...\n");
      foreach (Movie movie in movies)
      {
          Console.WriteLine (
              string.Format ("Movie Title = '{0}', Director = '{1}'.",
              movie.Title, movie.Director));
      }
      Console.WriteLine ("\nMovieApp Done.\n\n");
    }
...

To help ensure that the XML configuration of the MovieLister class must specify a value for the MovieFinder property, you can add the [Required] attribute to the MovieLister's MovieFinder property. The example code shows uses this attribute. For more information on using and configuring the [Required] attribute, refer to this section of the reference documentation.

33.2.4. Constructor Injection

Let's define another implementation of the IMovieFinder interface in the application config file...

...
  <object name="AnotherMovieFinder"
      type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder, Spring.Examples.MovieFinder">
  </object>
...

This XML snippet describes an IMovieFinder implementation that uses a colon delimited text file as it's movie source. The C# source code for this class defines a single constructor that takes a System.IO.FileInfo as it's single constructor argument. As this object definition currently stands, attempting to get this object out of the IApplicationContext in the application with a line of code like so...

IMovieFinder finder = (IMovieFinder) ctx.GetObject ("AnotherMovieFinder");

will result in a fatal Spring.Objects.Factory.ObjectCreationException, because the Spring.Examples.MovieFinder.ColonDelimitedMovieFinder class does not have a default constructor that takes no arguments. If we want to use this implementation of the IMovieFinder interface, we will have to supply an appropriate constructor argument...

...
  <object name="AnotherMovieFinder"
      type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder, Spring.Examples.MovieFinder">
      <constructor-arg index="0" value="movies.txt"/>
  </object>
...

Unsurprisingly, the <constructor-arg/> element is used to supply constructor arguments to the constructors of managed objects. The Spring.NET IoC container uses the functionality offered by System.ComponentModel.TypeConverter specializations to convert the movies.txt string into an instance of the System.IO.FileInfo that is required by the single constructor of the Spring.Examples.MovieFinder.ColonDelimitedMovieFinder (see Section 6.3, “Type conversion” for a more in depth treatment concerning the automatic type conversion functionality offered by Spring.NET).

So now we have two implementations of the IMovieFinder interface that have been defined as distinct object definitions in the config file of the example application; if we wanted to, we could switch the implementation that the MyMovieLister object uses like so...

...
  <object name="MyMovieLister"
    type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
      <!-- lets use the colon delimited implementation instead -->
      <property name="movieFinder" ref="AnotherMovieFinder"/>
  </object>
  <object name="MyMovieFinder"
      type="Spring.Examples.MovieFinder.SimpleMovieFinder, Spring.Examples.MovieFinder"/>
  </object>
  <object name="AnotherMovieFinder"
      type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder, Spring.Examples.MovieFinder">
      <constructor-arg index="0" value="movies.txt"/>
  </object>
...

Note that there is no need to recompile the application to effect this change of implementation... simply changing the application config file and then restarting the application will result in the Spring.NET IoC container injecting the colon delimited implementation of the IMovieFinder interface into the MyMovieLister object.

33.2.5. Summary

This example application is quite simple, and admittedly it doesn't do a whole lot. It does however demonstrate the basics of wiring together an object graph using an intuitive XML format. These simple features will get you through pretty much 80% of your object wiring needs. The remaining 20% of the available configuration options are there to cover corner cases such as factory methods, lazy initialization, and suchlike (all of the configuration options are described in detail in the Chapter 5, The IoC container).

33.2.6. Logging

Often enough the first use of Spring.NET is also a first introduction to log4net. To kick start your understanding of log4net this section gives a quick overview. The authoritative place for information on log4net is the log4net website. Other good online tutorials are Using log4net (OnDotNet article) and Quick and Dirty Guide to Configuring Log4Net For Web Applications. Spring.NET is using version 1.2.9 whereas most of the documentation out there is for version 1.2.0. There have been some changes between the two so always double check at the log4net web site for definitive information. Also note that we are investigating using a "commons" logging library so that Spring.NET will not be explicity tied to log4net but will be able to use other logging packages such as NLog and Microsoft enterprise logging application block.

The general usage pattern for log4net is to configure your loggers, (either in App/Web.config or a seperate file), initialize log4net in your main application, declare some loggers in code, and then log log log. (Sing along...) We are using App.config to configure the loggers. As such, we declare the log4net configuration section handler as shown below

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />

The corresponding configuration section looks like this

<log4net> 
  <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"> 
     <layout type="log4net.Layout.PatternLayout"> 
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" /> 
     </layout> 
  </appender> 

  <!-- Set default logging level to DEBUG -->
  <root> 
     <level value="DEBUG" /> 
     <appender-ref ref="ConsoleAppender" /> 
  </root> 
  
  <!-- Set logging for Spring to INFO.  Logger names in Spring correspond to the namespace -->
  <logger name="Spring"> 
     <level value="INFO" /> 
  </logger> 
</log4net> 
      

The appender is the output sink - in this case the console. There are a large variety of output sinks such as files, databases, etc. Refer to the log4net Config Examples for more information. Of interest as well is the PatternLayout which defines exactly the information and format of what gets logged. Usually this is the date, thread, logging level, logger name, and then finally the log message. Refer to PatternLayout Documentation for information on how to customize.

The logging name is up to you to decide when you declare the logger in code. In the case of this example we used the convention of giving the logging name the name of the fully qualified class name.

private static readonly ILog LOG = LogManager.GetLogger(typeof (MovieApp));

Other conventions are to give the same logger name across multiple classes that constitute a logical component or subsystem within the application, for example a data access layer. One tip in selecting the pattern layout is to shorten the logging name to only the last 2 parts of the fully qualified name to avoid the message sneaking off to the right too much (where can't see it) because of all the other information logged that precedes it. Shortening the logging name is done using the format %logger{2}.

To initialize the logging system add the following to the start of your application

XmlConfigurator.Configure();

Note that if you are using or reading information on version 1.2.0 this used to be called DOMConfigurator.Configure();

The logger sections associate logger names with logging levels and appenders. You have great flexibility to mix and match names, levels, and appenders. In this case we have defined the root logger (using the special tag root) to be at the debug level and have an console sink. We can then specialize other loggers with different setting. In this case, loggers that start with "Spring" in their name are logged at the info level and also sent to the console. Setting the value of this logger from INFO to DEBUG will show you detailed logging information as the Spring container goes about its job of creating and configuring your objects. Coincidentally, the example code itself uses Spring in the logger name, so this logger also controls the output level you see from running MainApp. Finally, you are ready to use the simple logger api to log, i.e.

LOG.Info("Searching for movie...");

Logging exceptions is another common task, which can be done using the error level

try {
   //do work
{
catch (Exception e)
{
  LOG.Error("Movie Finder is broken.", e);
}

33.3. ApplicationContext and IMessageSource

33.3.1. Introduction

The example program Spring.Examples.AppContext shows the use of the application context for text localization, retrieving objects contained in ResourceSets, and applying the values of embedded resource properties to an object. The values that are retrieved are displayed in a window.

The application context configuration file contains an object definition with the name messageSource of the type Spring.Context.Support.ResourceSetMessageSource which implements the interface IMessageSource. This interface provides various methods for retrieving localized resources such as text and images as described in Section 5.12.2, “Using IMessageSource”. When creating an instance of IApplicationContext, an object with the name 'messageSource' is searched for and used as the implementation for the context's IMessageSource functionality.

The ResourceSetMessageSource takes a list of ResourceManagers to define the collection of culture-specific resources. The ResourceManager can be contructed in two ways. The first way is to specifying a two part string consisting of the base resource name and the containing assembly. In this example there is an embedded resource file, Images.resx in the project. The second way is to use helper factory class ResourceManagerFactoryObject that takes a resource base name and assembly name as properties. This second way of specifying a ResourceManager is useful if you would like direct access to the ResourceManager in other parts of your application. In the example program an embedded resource file, MyResource.resx and a Spanish specific resource file, MyResources.es.resx are declared in this manner. The corresponding XML fragment is shown below

...
        <object name="messageSource" type="Spring.Context.Support.ResourceSetMessageSource, Spring.Core">
          <property name="resourceManagers">
            <list>
              <value>Spring.Examples.AppContext.Images, Spring.Examples.AppContext</value>
              <ref object="myResourceManager"/>
            </list>
          </property>
        </object>
  
        <object name="myResourceManager" type="Spring.Objects.Factory.Config.ResourceManagerFactoryObject, Spring.Core">
          <property name="baseName">
            <value>Spring.Examples.AppContext.MyResource</value>
          </property>
          <property name="assemblyName">
            <value>Spring.Examples.AppContext</value>
          </property>    
        </object>
...

The main application creates the application context and then retrieves various resources via their key names. In the code all the key names are declared as static fields in the class Keys. The resource file Images.resx contains image data under the key name bubblechamber (aka Keys.BUBBLECHAMBER). The code Image image = (Image)ctx.GetResourceObject(Keys.BUBBLECHAMBER); is used to retrieve the image from the context. The resource files MyResource.resx contains a text resource, Hello {0} {1} under the key name HelloMessage (aka Keys.HELLO_MESSAGE) that can be used for string text formatting purposes. The example code

string msg = ctx.GetMessage(Keys.HELLO_MESSAGE,
                            CultureInfo.CurrentCulture,
                            "Mr.", "Anderson");

retrieves the text string and replaces the placeholders in the string with the passed argument values resulting in the text, "Hello Mr. Anderson". The current culture is used to select the resource file MyResource.resx. If instead the Spanish culture is specified

CultureInfo spanishCultureInfo = new CultureInfo("es");
string esMsg = ctx.GetMessage(Keys.HELLO_MESSAGE,
                              spanishCultureInfo,
                              "Mr.", "Anderson");

Then the resource file MyResource.es.resx is used instead as in standard .NET localization. Spring is simply delegating to .NET ResourceManager to select the appropriate localized resource. The Spanish version of the resource differs from the English one in that the text under the key HelloMessage is Hola {0} {1} resulting in the text "Hola Mr. Anderson".

As you can see in this example, the title "Mr." should not be used in the case of the spanish localization. The title can be abstracted out into a key of its own, called FemaleGreeting (aka Keys.FEMALE_GREETING). The replacement value for the message argument {0} can then be made localization aware by wrapping the key in a convenience class DefaultMessageResolvable. The code

string[] codes = {Keys.FEMALE_GREETING};
DefaultMessageResolvable dmr = new DefaultMessageResolvable(codes, null);

msg = ctx.GetMessage(Keys.HELLO_MESSAGE,
                     CultureInfo.CurrentCulture,
                     dmr, "Anderson");

will assign msg the value, Hello Mrs. Anderson, since the value for the key FemaleGreeting in MyResource.resx is 'Mrs.' Similarly, the code

esMsg = ctx.GetMessage(Keys.HELLO_MESSAGE,
                       spanishCultureInfo,
                       dmr, "Anderson");

will assign esMsg the value, Hola Senora Anderson, since the value for the key FemaleGreeting in MyResource.es.resx is 'Senora'.

Localization can also apply to objects and not just strings. The .NET 1.1 framework provides the utility class ComponentResourceManager that can apply multiple resource values to object properties in a performant manner. (VS.NET 2005 makes heavy use of this class in the code it generates for winform applications.) The example program has a simple class, Person, that has an integer property Age and a string property Name. The resource file, Person.resx contains key names that follow the pattern, person.<PropertyName>. In this case it contains person.Name and person.Age. The code to assign these resource values to an object is shown below

Person p = new Person();
ctx.ApplyResources(p, "person", CultureInfo.CurrentUICulture);

While you could also use the Spring itself to set the properties of these objects, the configuration of simple properties using Spring will not take into account localization. It may be convenient to combine approaches and use Spring to configure the Person's object references while using IApplicationContext inside an AfterPropertiesSet callback (see IInitializingObject) to set the Person's culture aware properties.

33.4. ApplicationContext and IEventRegistry

33.4.1. Introduction

The example program Spring.Examples.EventRegistry shows how to use the application context to wire .NET events in a loosely coupled manner.

Loosely coupled eventing is normally associated with Message Oriented Middleware (MOM) where a daemon process acts as a message broker between other independent processes. Processes communicate indirectly with each other by sending messages though the message broker. The process that initiates the communication is known as a publisher and the process that receives the message is known as the subscriber. By using an API specific to the middleware these processes register themselves as either publishers or subscribers with the message broker. The communication between the publisher and subscriber is considered loosely coupled because neither the publisher nor subscriber has a direct reference to each other, the messages broker acts as an intermediary between the two processes. The IEventRegistry is the analogue of the message broker as applied to .NET events. Publishers are classes that invoke a .NET event, subscribers are the classes that register interest in these events, and the messages sent between them are instances of System.EventArgs. The implementation of IEventRegistry determines the exact semantics of the notification style and coupling between subscribers and publishers.

The IApplicationContext interface extends the IEventRegistry interface and implementations of IApplicationContext delegate the event registry functionality to an instance of Spring.Objects.Events.Support.EventRegistry. IEventRegistry is a simple inteface with one publish method and two subscribe methods. Refer to Section 5.12.4, “Loosely coupled events” for a reminder of their signatures. The Spring.Objects.Events.Support.EventRegistry implementation is essentially a convenience to decouple the event wiring process between publisher and subscribers. In this implementation, after the event wiring is finished, publishers are directly coupled to the subscribers via the standard .NET eventing mechanisms. Alternate implementations could increase the decoupling further by having the event registry subscribe to the events and be responsible for then notifying the subscribers.

In this example the class MyClientEventArgs is a subclass of System.EventArgs that defines a string property EventMessage. The class MyEventPublisher defines a public event with the delegate signature void SimpleClientEvent( object sender, MyClientEventArgs args ) The method void ClientMethodThatTriggersEvent1() fires this event. On the subscribing side, the class MyEventSubscriber contains a method, HandleClientEvents that matches the delegate signature and has a boolean property which is set to true if this method is called.

The publisher and subscriber classes are defined in an application context configuration file but that is not required in order to participate with the event registry. The main program, EventRegistryApp creates the application context and asks it for an instance of MyEventPublisher The publisher is registered with the event registry via the call, ctx.PublishEvents( publisher ). The event registry keeps a reference to this publisher for later use to register any subscribers that match its event signature. Two subscribers are then created and one of them is wired to the publisher by calling the method ctx.Subscribe( subscriber, typeof(MyEventPublisher) ) Specifying the type indicates that the subscriber should be registered only to events from objects of the type MyEventPublisher. This acts as a simple filtering mechanism on the subscriber.

The publisher then fires the event using normal .NET eventing semantics and the subscriber is called. The subscriber prints a message to the console and sets a state variable to indicate it has been called. The program then simply prints the state variable of the two subscribers, showing that only one of them (the one that registered with the event registry) was called.

33.5. Pooling example

The idea is to build an executor backed by a pool of QueuedExecutor: this will show how Spring.NET provides some useful low-level/high-quality reusable threading and pooling abstractions. This executor will provide parallel executions (in our case grep-like file scans). Note: This example is not in the 1.0.0 release to its use of classes in the Spring.Threading namespace scheduled for release in Spring 1.1. To access ths example please get the code from CVS (instructions) or from the download section of the Spring.NET website that contains an .zip with the full CVS tree.

Some information on QueuedExecutor is helpful to better understand the implementation and to possibly disagree with it. Keep in mind that the point is to show how to develop your own object-pool.

A QueuedExecutor is an executor where IRunnable instances are run serialy by a worker thread. When you Execute with a QueuedExecutor, your request is queued; at some point in the future your request will be taken and executed by the worker thread: in case of error the thread is terminated. However this executor recreates its worker thread as needed.

Last but not least, this executor can be shut down in a few different ways (please refer to the Spring.NET SDK documentation). Given its simplicity, it is very powerful.

The example project Spring.Examples.Pool provides an implementation of a pooled executor, backed by n instances of Spring.Threading.QueuedExecutor: please ignore the fact that Spring.Threading includes already a very different implementation of a PooledExecutor: here we wanto to use a pool of QueuedExecutors.

This executor will be used to implement a parallel recursive grep-like console executable.

33.5.1. Implementing Spring.Pool.IPoolableObjectFactory

In order to use the SimplePool implementation, the first thing to do is to implement the IPoolableObjectFactory interface. This interface is intended to be implemented by objects that can create the type of objects that should be pooled. The SimplePool will call the lifecycle methods on IPoolableObjectFactory interface (MakeObject, ActivateObject, ValidateObject, PassivateObject, and DestroyObject) as appropriate when the pool is created, objects are borrowed and returned to the pool, and when the pool is destroyed.

In our case, as already said, we want to to implement a pool of QueuedExecutor. Ok, here the declaration:

public class QueuedExecutorPoolableFactory : IPoolableObjectFactory
{

the first task a factory should do is to create objects:

object IPoolableObjectFactory.MakeObject()
{            
    // to actually make this work as a pooled executor
    // use a bounded queue of capacity 1.
    // If we don't do this one of the queued executors
    // will accept all the queued IRunnables as, by default
    // its queue is unbounded, and the PooledExecutor
    // will happen to always run only one thread ...
    return new QueuedExecutor(new BoundedBuffer(1));
}

and should be also able to destroy them:

void IPoolableObjectFactory.DestroyObject(object o)
{
    // ah, self documenting code:
    // Here you can see that we decided to let the 
    // executor process all the currently queued tasks.
    QueuedExecutor executor = o as QueuedExecutor;
    executor.ShutdownAfterProcessingCurrentlyQueuedTasks();
}

When an object is taken from the pool, to satisfy a client request, may be the object should be activated. We can possibly implement the activation like this:

void IPoolableObjectFactory.ActivateObject(object o)
{
    QueuedExecutor executor = o as QueuedExecutor;
    executor.Restart();
}

even if a QueuedExecutor restarts itself as needed and so a valid implementation could leave this method empty.

After activation, and before the pooled object can be succesfully returned to the client, it is validated (should the object be invalid, it will be discarded: this can lead to an empty unusable pool [5]). Here we check that the worker thread exists:

bool IPoolableObjectFactory.ValidateObject(object o)
{
    QueuedExecutor executor = o as QueuedExecutor;
    return executor.Thread != null;
}

Passivation, symmetrical to activation, is the process a pooled object is subject to when the object is returned to the pool. In our case we simply do nothing:

void IPoolableObjectFactory.PassivateObject(object o)
{
}

At this point, creating a pool is simply a matter of creating an SimplePool as in:

pool = new SimplePool(new QueuedExecutorPoolableFactory(), size);

33.5.2. Being smart using pooled objects

Taking advantage of the using keyword seems to be very important in these c# days, so we implement a very simple helper (PooledObjectHolder) that can allow us to do things like:

using (PooledObjectHolder holder = PooledObjectHolder.UseFrom(pool))
{
    QueuedExecutor executor = (QueuedExecutor) holder.Pooled;
    executor.Execute(runnable);
}

without worrying about obtaining and returning an object from/to the pool.

Here is the implementation:

public class PooledObjectHolder : IDisposable
{
    IObjectPool pool;
    object pooled;

    /// <summary>
    /// Builds a new <see cref="PooledObjectHolder"/>
    /// trying to borrow an object form it
    /// </summary>
    /// <param name="pool"></param>
    private PooledObjectHolder(IObjectPool pool)
    {
        this.pool = pool;
        this.pooled = pool.BorrowObject();
    }

    /// <summary>
    /// Allow to access the borrowed pooled object
    /// </summary>
    public object Pooled
    {
        get
        {
            return pooled;
        }
    }

    /// <summary>
    /// Returns the borrowed object to the pool
    /// </summary>
    public void Dispose()
    {
        pool.ReturnObject(pooled);
    }

    /// <summary>
    /// Creates a new <see cref="PooledObjectHolder"/> for the 
    /// given pool.
    /// </summary>
    public static PooledObjectHolder UseFrom(IObjectPool pool)
    {
        return new PooledObjectHolder(pool);
    }
}

Please don't forget to destroy all the pooled istances once you have finished! How? Well using something like this in PooledQueuedExecutor:

public void Stop ()
{
    // waits for all the grep-task to have been queued ...
    foreach (ISync sync in syncs)
    {
        sync.Acquire();
    }
    pool.Close();
}

33.5.3. Using the executor to do a parallel grep

The use of the just built executor is quite straigtforward but a little tricky if we want to really exploit the pool.

private PooledQueuedExecutor executor;

public ParallelGrep(int size)
{
    executor = new PooledQueuedExecutor(size);
}

public void Recurse(string startPath, string filePattern, string regexPattern)
{            
    foreach (string file in Directory.GetFiles(startPath, filePattern))
    {
        executor.Execute(new Grep(file, regexPattern));
    }
    foreach (string directory in Directory.GetDirectories(startPath))
    {
        Recurse(directory, filePattern, regexPattern);
    }
}

public void Stop()
{
    executor.Stop();
}

public static void Main(string[] args)
{
    if (args.Length < 3)
    {
        Console.Out.WriteLine("usage: {0} regex directory file-pattern [pool-size]", Assembly.GetEntryAssembly().CodeBase);
        Environment.Exit(1);
    }

    string regexPattern = args[0];
    string startPath = args[1];
    string filePattern = args[2];
    int size = 10;
    try
    {
        size = Int32.Parse(args[3]);
    }
    catch
    {
    }
    Console.Out.WriteLine ("pool size {0}", size);

    ParallelGrep grep = new ParallelGrep(size);
    grep.Recurse(startPath, filePattern, regexPattern);
    grep.Stop();
}

33.6. AOP

Refer to Chapter 34, AOP Guide.


[5] You may think that we can provide a smarter implementation and you are probably right. However, it is not so difficult to create a new pool in case the old one became unusable. It could not be your preferred choice but surely it leverages simplicity and object immutability