#region License
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Threading;
using Common.Logging;
using Spring.Objects.Factory;
namespace Spring.Messaging.Listener{
/// <summary>
/// Provides basic lifecyle management methods for implementing a message listener container.
/// </summary>
/// <remarks>
/// This base class does not assume any specific listener programming model
/// or listener invoker mechanism. It just provides the general runtime
/// lifecycle management needed for any kind of message-based listening mechanism.
/// <para>
/// For a concrete listener programming model, check out the
/// <see cref="AbstractMessageListenerContainer"/> subclass. For a concrete listener
/// invoker mechanism, check out the <see cref="NonTransactionalMessageListenerContainer"/>,
/// <see cref="TransactionalMessageListenerContainer"/>, or
/// <see cref="DistributedTxMessageListenerContainer"/> classes.
/// </para>
/// </remarks>
/// <author>Mark Pollack</author>
public abstract class AbstractListenerContainer : IInitializingObject, IObjectNameAware, IDisposable
{
#region Logging Definition
private static readonly ILog LOG = LogManager.GetLogger(typeof (AbstractListenerContainer));
#endregion
private bool autoStartup = true;
private string objectName;
private bool active;
private bool running;
private object lifecycleMonitor = new object();
#region Properties
/// <summary>
/// Sets a value indicating whether to automatically start the container after initialization.
/// Default is "true"; set this to "false" to allow for manual startup though the
/// <see cref="Start"/> method.
/// </summary>
/// <value><c>true</c> if autostartup; otherwise, <c>false</c>.</value>
public bool AutoStartup
{
set { autoStartup = value; }
}
/// <summary>
/// Gets a value indicating whether this Container is active,
/// that is, whether it has been set up but not shut down yet.
/// </summary>
/// <value><c>true</c> if active; otherwise, <c>false</c>.</value>
public bool Active
{
get
{
lock (lifecycleMonitor)
{
return active;
}
}
}
/// <summary>
/// Gets a value indicating whether this Container is running,
/// that is whether it has been started and not stopped yet.
/// </summary>
/// <value><c>true</c> if running; otherwise, <c>false</c>.</value>
public bool Running
{
get
{
lock (lifecycleMonitor)
{
return (running && RunningAllowed());
}
}
}
#region IObjectNameAware Members
/// <summary>
/// Return the object name that this listener container has been assigned
/// in its containing object factory, if any.
/// </summary>
public string ObjectName
{
set { objectName = value; }
get { return objectName; }
}
#endregion
#endregion
#region IInitializingObject Members
/// <summary>
/// Delegates to <see cref="ValidateConfiguration"/> and <see cref="Initialize"/>
/// </summary>
public void AfterPropertiesSet()
{
ValidateConfiguration();
Initialize();
}
#endregion
#region IDisposable Members
/// <summary>
/// Calls <see cref="Shutdown"/> when the application context destroys the container instance.
/// </summary>
public void Dispose()
{
Shutdown();
}
#endregion
/// <summary>
/// Validates the configuration of this container
/// The default implementation is empty. To be overridden in subclasses.
/// </summary>
protected virtual void ValidateConfiguration()
{
}
/// <summary>
/// Initializes this container. Calls the abstract method <see cref="DoInitialize"/> to
/// initialize the listening infrastructure (i.e. subclasses will typically
/// resolve a MessageQueue instance from a MessageQueueObjectName) and then calls
/// the abstract method DoStart if the property <see cref="AutoStartup"/> is set to true,
/// </summary>
public virtual void Initialize()
{
lock (lifecycleMonitor)
{
active = true;
Monitor.PulseAll(lifecycleMonitor);
}
DoInitialize();
if (autoStartup)
{
DoStart();
}
}
/// <summary>
/// Sets the container state to inactive and not running, calls template method
/// <see cref="DoShutdown"/>
/// </summary>
public virtual void Shutdown()
{
LOG.Debug("Shutting down MessageListenerContainer");
lock (lifecycleMonitor)
{
running = false;
active = false;
Monitor.PulseAll(lifecycleMonitor);
}
DoShutdown();
}
/// <summary>
/// Starts this container.
/// </summary>
public virtual void Start()
{
DoStart();
}
/// <summary>
/// Sets the state to running, can be overridden in subclasses.
/// </summary>
protected virtual void DoStart()
{
lock (lifecycleMonitor)
{
running = true;
Monitor.PulseAll(lifecycleMonitor);
}
}
/// <summary>
/// Stops this instance.
/// </summary>
public virtual void Stop()
{
DoStop();
}
/// <summary>
/// Template method suitable for overriding that stops the container.
/// </summary>
protected virtual void DoStop()
{
lock (lifecycleMonitor)
{
running = false;
Monitor.PulseAll(lifecycleMonitor);
}
}
/// <summary>
/// Check whether this container's listeners are generally allowed to run.
/// </summary>
/// <remarks>
/// This implementation always returns <code>true</code>; the default 'running'
/// state is purely determined by <see cref="Start"/> and <see cref="Stop"/>
/// <para>
/// Subclasses may override this method to check against temporary
/// conditions that prevent listeners from actually running. In other words,
/// they may apply further restrictions to the 'running' state, returning
/// <code>false</code> if such a restriction prevents listeners from running.
/// </para>
/// </remarks>
/// <returns><code>false</code> if such a restriction prevents listeners from running.</returns>
protected virtual bool RunningAllowed()
{
return true;
}
#region Abstract Methods
/// <summary>
/// Subclasses need to implement this method for their specific
/// listener management process.
/// </summary>
protected abstract void DoInitialize();
/// <summary>
/// Subclasses need to implement this method for their specific
/// listener management process.
/// </summary>
protected abstract void DoShutdown();
#endregion
}
}
|