avalon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "hammett" <hamm...@uol.com.br>
Subject Avalon.Net
Date Mon, 08 Sep 2003 11:23:26 GMT
Here is a working implementation of Avalon.Net: I would like to hear from
you about a few design decisions I made. To understand a little more,
explore the code while you read the following sections. The zip file is
attached to another post (I posted yesterday but the mailer refused it)


-= The beginning =-


Keeping the XP principles attached to my monitor, I created a simple
DefaultContainer class. The standard use is a simple instantiantion:


  DefaultContainer container = new DefaultContainer();


This kind of use tries to obtain the configuration from
ConfigurationSettings .Net class. If it can't be done, an exception is
throwed. The user can construct a config by himself and pass on to
DefaultContainer:


  String configFile =
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
  ContainerConfiguration config = new ContainerConfiguration(configFile);

  DefaultContainer container = new DefaultContainer(config);


-= Configuration section =-

The configuration is handled by
Apache.Avalon.Container.Configuration.ContainerConfiguration /
Apache.Avalon.Container.Configuration.ContainerConfigurationSectionHandler
pair. The format follows .Net standards:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <configSections>
 <section
  name="avalon.container"

type="Apache.Avalon.Container.Configuration.ContainerConfigurationSectionHan
dler, Apache.Avalon.Container" />
  </configSections>

  <avalon.container>
 <components>
  <assembly type="Apache.Avalon.Container.Test" />

  <component configurationName="Samples.Components\Authentication" >
   <username>JohnDoe</username>
  </component>
 </components>
  </avalon.container>

</configuration>

The assembly element adds assemblies to container. The container considers
true Avalon components/services classes which holds attribute
AvalonServiceAttribute. Others importants details are exposed by
AvalonComponentAttribute (should be apart?)

The configuration name maps what the component itself told us about it's
configuration, like:

 [AvalonService( typeof(IAuthentication) )]
 [AvalonComponent( @"Samples.Components\Authentication",
Lifestyle.Transient, LoggerName="AuthLog" )]
 public class Authentication :
  IAuthentication, IInitializable, ILogEnabled, IConfigurable, IDisposable
<...>

So one should feel free to use any convention he wants.


-= Lyfestyle =-

Lyfestyle are managed by AbstractComponentFactory. I don't like this way -
used in Fortress - cause is too fragile, but didn't have time to think in
another way without using proxies.

I added a new lifestyle named Custom but a Field is missing to allow the
component to tell us which Type is the factory for it. Currently Lifestyles
supported are:

  * Transient (Duh!)
  * Singleton
  * Thread


-= ComponentFactory =-

As stated in the TO DO List, the factories aren't considered true
components, so no "events" are fired to them (yet). Anyway they are
de-coupled (I think its the wrong word!) from container code. In fact the
class FactoryBuilder searchs the current assembly for types which holds the
LyfestyleTargetAttribute attribute.

Optionally a factory can tell which Builder manages it. Using an associated
Builder was fine and permitted clean factories implementations. Factories
which don't supports Custom Builder are handled by a common Builder
(FactoryBuilder). For instance this is the SingletonComponentFactory
implementation:


 /// <summary>
 /// Summary description for SingletonComponentFactory.
 /// </summary>
 [CustomBuilder(typeof(SingletonComponentFactoryBuilder))]
 [LifestyleTarget(Lifestyle.Singleton)]
 internal class SingletonComponentFactory : AbstractComponentFactory
 {
  public SingletonComponentFactory(Type componentType) : base(componentType)
  {
  }

  public override bool IsReusable
  {
   get
   {
    return true;
   }
  }

  public override object Create(ComponentEntry entry)
  {
   if (m_instance == null)
   {
    return base.Create(entry);
   }
   return m_instance;
  }

  public override void Destroy(object componentInstance)
  {
   // Can't call Dispose in a singleton component
  }
 }

 /// <summary>
 /// <see cref="SingletonComponentFactoryBuilder"/> is a <see
cref="FactoryBuilder"/>
 /// implementation for <see cref="SingletonComponentFactory"/> that
 /// keep instances of factories
 /// </summary>
 internal sealed class SingletonComponentFactoryBuilder : FactoryBuilder
 {
  private static Hashtable factories = new Hashtable();

  public SingletonComponentFactoryBuilder()
  {
  }

  public override IComponentFactory GetFactory(Type componentType)
  {
   IComponentFactory factory = null;

   lock(factories)
   {
    factory = (IComponentFactory) factories[componentType];

    if (factory == null)
    {
     factory = new SingletonComponentFactory(componentType);
     factories[componentType] = factory;
    }
   }

   return factory;
  }
 }



And to implement the ThreadComponentFactory was even simpler:



 /// <summary>
 /// Summary description for ThreadComponentFactory.
 /// </summary>
 [CustomBuilder(typeof(ThreadComponentFactoryBuilder))]
 [LifestyleTarget(Lifestyle.Thread)]
 internal class ThreadComponentFactory : SingletonComponentFactory
 {
  public ThreadComponentFactory(Type componentType) : base(componentType)
  {
  }
 }

 /// <summary>
 ///
 /// </summary>
 internal sealed class ThreadComponentFactoryBuilder : FactoryBuilder
 {
  private static readonly LocalDataStoreSlot threadSlot =
Thread.AllocateDataSlot();

  public ThreadComponentFactoryBuilder()
  {
  }

  public override IComponentFactory GetFactory(Type componentType)
  {
   // TODO: Add syncronization code
   // TODO: Could be easily refactored to
   // extend SingletonComponentFactoryBuilder

   Hashtable factories = (Hashtable) Thread.GetData(threadSlot);

   if (factories == null)
   {
    factories = new Hashtable();
    Thread.SetData(threadSlot, factories);
   }

   IComponentFactory factory = null;

   lock(factories)
   {
    factory = (IComponentFactory) factories[componentType];

    if (factory == null)
    {
     factory = new SingletonComponentFactory(componentType);
     factories[componentType] = factory;
    }
   }

   return factory;
  }
 }



I hope you guys like it  :-)


-= Extensions =-

I didn't write any extensions or some supported to them neither. But it
should be easy to add them in the next day as soon as Logger/Lookup works in
a decent way.


-= Samples =-

I added two projects as samples. A Web project and a components project. Web
uses the components project. I'm focusing the Web cause it will be my
primary use, with cross process boundaries issues.

By now there is not NAnt build files yet.



-= Code conventions =-

I tried hard to follow Avalon conventions despite the fact it differs from
MS recomendations (Pascal case and Camel case). Avalon seems to use a mix of
Hungarian notation and Java convention.
Also I used the Jeffrey Ritcher recommended style for declaring "using":

namespace Apache.Avalon.Container
{
 using System;
 using System.Xml;
 using System.Collections;
 using System.Collections.Specialized;

 using Apache.Avalon.Framework;

 /// <summary>
 ///
 /// </summary>
 public class ComponentEntry

Didn't know what to do about constants (CAPITALIZE?) and static fields so I
used the convetion I'm used to.


-= CVS =-

Don't know if it is the right time to upload it to avalon-sandbox, but for
sure it's the right time to criticize it and make suggestions. Anyway I'm
attaching a ZIP file (last time I used CVS diff I had a CR/LF problem)

I made several modifications in framework project and pratically rewritten
the container project, so it's now using a different project tree:

cscontainer
  + AvalonContainer
    . Attributes
    . Configuration
    . Factory
    . Lookup
    . Util
  . AvalonContainerTest
  + Samples
    . Components
    . Web
  . bin (binary, pdb and config files used by Test Cases)

csframework
  . AvalonFramework
  . AvalonFrameworkTest
  . bin

This tree is humam readable and integrated with VS.Net.

You'll find a TO DO List.txt in cscontainer\AvalonConainer directory.



Regards,

hammett



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Mime
View raw message