Add NmsTransactionManager + tests

Initial work for SingleConnectionFactory
This commit is contained in:
markpollack
2008-07-17 01:16:00 +00:00
parent 90379aced9
commit 7641432576
17 changed files with 1262 additions and 211 deletions

View File

@@ -19,9 +19,10 @@
#endregion
using System;
using Apache.NMS;
using Common.Logging;
using Spring.Transaction.Support;
using Spring.Util;
using Apache.NMS;
namespace Spring.Messaging.Nms.IConnections
{
@@ -33,7 +34,11 @@ namespace Spring.Messaging.Nms.IConnections
/// <author>Mark Pollack (.NET)</author>
public abstract class ConnectionFactoryUtils
{
#region Logging
private static readonly ILog LOG = LogManager.GetLogger(typeof(ConnectionFactoryUtils));
#endregion
/// <summary> Obtain a NMS ISession that is synchronized with the current transaction, if any.</summary>
/// <param name="cf">the IConnectionFactory to obtain a ISession for
@@ -50,10 +55,13 @@ namespace Spring.Messaging.Nms.IConnections
/// <returns> the transactional ISession, or <code>null</code> if none found
/// </returns>
/// <throws> NMSException in case of NMS failure </throws>
public static ISession GetTransactionalSession(IConnectionFactory cf, IConnection existingCon, bool synchedLocalTransactionAllowed)
public static ISession GetTransactionalSession(IConnectionFactory cf, IConnection existingCon,
bool synchedLocalTransactionAllowed)
{
return DoGetTransactionalSession(cf, new AnonymousClassResourceFactory(existingCon, cf, synchedLocalTransactionAllowed));
return
DoGetTransactionalSession(cf,
new AnonymousClassResourceFactory(existingCon, cf,
synchedLocalTransactionAllowed));
}
/// <summary> Obtain a NMS ISession that is synchronized with the current transaction, if any.</summary>
@@ -66,13 +74,13 @@ namespace Spring.Messaging.Nms.IConnections
/// <returns> the transactional ISession, or <code>null</code> if none found
/// </returns>
/// <throws>NMSException in case of NMS failure </throws>
public static ISession DoGetTransactionalSession(System.Object resourceKey, ConnectionFactoryUtils.ResourceFactory resourceFactory)
public static ISession DoGetTransactionalSession(Object resourceKey, ResourceFactory resourceFactory)
{
AssertUtils.ArgumentNotNull(resourceKey, "Resource key must not be null");
AssertUtils.ArgumentNotNull(resourceKey, "ResourceFactory must not be null");
NmsResourceHolder resourceHolder = (NmsResourceHolder)TransactionSynchronizationManager.GetResource(resourceKey);
NmsResourceHolder resourceHolder =
(NmsResourceHolder)TransactionSynchronizationManager.GetResource(resourceKey);
if (resourceHolder != null)
{
ISession rssession = resourceFactory.GetSession(resourceHolder);
@@ -90,7 +98,7 @@ namespace Spring.Messaging.Nms.IConnections
{
conHolderToUse = new NmsResourceHolder();
}
Apache.NMS.IConnection con = resourceFactory.GetConnection(conHolderToUse);
IConnection con = resourceFactory.GetConnection(conHolderToUse);
ISession session = null;
try
{
@@ -115,7 +123,7 @@ namespace Spring.Messaging.Nms.IConnections
{
session.Close();
}
catch (System.Exception)
catch (Exception)
{
// ignore
}
@@ -126,7 +134,7 @@ namespace Spring.Messaging.Nms.IConnections
{
con.Close();
}
catch (System.Exception)
catch (Exception)
{
// ignore
}
@@ -135,52 +143,90 @@ namespace Spring.Messaging.Nms.IConnections
}
if (conHolderToUse != resourceHolder)
{
TransactionSynchronizationManager.RegisterSynchronization(new NmsResourceSynchronization(resourceKey, conHolderToUse, resourceFactory.SynchedLocalTransactionAllowed));
TransactionSynchronizationManager.RegisterSynchronization(
new NmsResourceSynchronization(resourceKey, conHolderToUse,
resourceFactory.SynchedLocalTransactionAllowed));
conHolderToUse.SynchronizedWithTransaction = true;
TransactionSynchronizationManager.BindResource(resourceKey, conHolderToUse);
}
return session;
}
public static void ReleaseConnection(IConnection connection, IConnectionFactory cf, bool started)
{
if (connection == null)
{
return;
}
if (started && cf is ISmartConnectionFactory && ((ISmartConnectionFactory)cf).ShouldStop(connection))
{
try
{
connection.Stop();
}
catch (Exception ex)
{
LOG.Debug("Could not stop NMS IConnection before closing it", ex);
}
}
try
{
connection.Close();
} catch (Exception ex)
{
LOG.Debug("Could not close NMS Connection", ex);
}
}
public static bool IsSessionTransactional(ISession session, IConnectionFactory cf)
{
if (session == null || cf == null)
{
return false;
}
NmsResourceHolder resourceHolder = (NmsResourceHolder) TransactionSynchronizationManager.GetResource(cf);
return (resourceHolder != null && resourceHolder.ContainsSession(session));
}
#region ResourceFactory helper classes
private class AnonymousClassResourceFactory : ConnectionFactoryUtils.ResourceFactory
private class AnonymousClassResourceFactory : ResourceFactory
{
private IConnection existingCon;
private IConnectionFactory cf;
private bool synchedLocalTransactionAllowed;
public AnonymousClassResourceFactory(Apache.NMS.IConnection existingCon, IConnectionFactory cf, bool synchedLocalTransactionAllowed)
public AnonymousClassResourceFactory(IConnection existingCon, IConnectionFactory cf,
bool synchedLocalTransactionAllowed)
{
InitBlock(existingCon, cf, synchedLocalTransactionAllowed);
}
private void InitBlock(Apache.NMS.IConnection existingCon, IConnectionFactory cf, bool synchedLocalTransactionAllowed)
private void InitBlock(IConnection existingCon, IConnectionFactory cf, bool synchedLocalTransactionAllowed)
{
this.existingCon = existingCon;
this.cf = cf;
this.synchedLocalTransactionAllowed = synchedLocalTransactionAllowed;
}
public virtual ISession GetSession(NmsResourceHolder holder)
{
return holder.GetSession(typeof(ISession), existingCon);
return holder.GetSession(typeof(ISession), existingCon);
}
public virtual Apache.NMS.IConnection GetConnection(NmsResourceHolder holder)
public virtual IConnection GetConnection(NmsResourceHolder holder)
{
return (existingCon != null ? existingCon : holder.GetConnection());
return (existingCon != null ? existingCon : holder.GetConnection());
}
public virtual Apache.NMS.IConnection CreateConnection()
public virtual IConnection CreateConnection()
{
return cf.CreateConnection();
}
public virtual ISession CreateSession(Apache.NMS.IConnection con)
public virtual ISession CreateSession(IConnection con)
{
if (synchedLocalTransactionAllowed)
{
@@ -190,7 +236,6 @@ namespace Spring.Messaging.Nms.IConnections
{
return con.CreateSession(AcknowledgementMode.AutoAcknowledge);
}
}
public bool SynchedLocalTransactionAllowed
@@ -198,6 +243,7 @@ namespace Spring.Messaging.Nms.IConnections
get { return synchedLocalTransactionAllowed; }
}
}
#endregion
#region Helper classes/interfaces
@@ -207,7 +253,6 @@ namespace Spring.Messaging.Nms.IConnections
/// </summary>
public interface ResourceFactory
{
/// <summary> Fetch an appropriate ISession from the given NmsResourceHolder.</summary>
/// <param name="holder">the NmsResourceHolder
/// </param>
@@ -236,7 +281,7 @@ namespace Spring.Messaging.Nms.IConnections
/// <returns> the new NMS ISession
/// </returns>
/// <throws>NMSException if thrown by NMS API methods </throws>
ISession CreateSession(Apache.NMS.IConnection con);
ISession CreateSession(IConnection con);
/// <summary>
@@ -247,17 +292,13 @@ namespace Spring.Messaging.Nms.IConnections
/// Returns whether to allow for synchronizing a local NMS transaction
/// </summary>
///
bool SynchedLocalTransactionAllowed
{
get;
}
bool SynchedLocalTransactionAllowed { get; }
}
/// <summary> Callback for resource cleanup at the end of a non-native NMS transaction
/// </summary>
private class NmsResourceSynchronization : TransactionSynchronizationAdapter
{
private object resourceKey;
private NmsResourceHolder resourceHolder;
@@ -275,7 +316,7 @@ namespace Spring.Messaging.Nms.IConnections
public override void Suspend()
{
if (this.holderActive)
if (holderActive)
{
TransactionSynchronizationManager.UnbindResource(resourceKey);
}
@@ -283,7 +324,7 @@ namespace Spring.Messaging.Nms.IConnections
public override void Resume()
{
if (this.holderActive)
if (holderActive)
{
TransactionSynchronizationManager.BindResource(resourceKey, resourceHolder);
}
@@ -291,22 +332,22 @@ namespace Spring.Messaging.Nms.IConnections
public override void BeforeCompletion()
{
TransactionSynchronizationManager.UnbindResource(this.resourceKey);
this.holderActive = false;
TransactionSynchronizationManager.UnbindResource(resourceKey);
holderActive = false;
if (!transacted)
{
this.resourceHolder.CloseAll();
resourceHolder.CloseAll();
}
}
//TODO bring in new Spring.Data library to Integration project which has this method in interface.
public override void AfterCommit()
{
if (this.transacted)
if (transacted)
{
try
{
this.resourceHolder.CommitAll();
resourceHolder.CommitAll();
}
catch (NMSException ex)
{
@@ -317,12 +358,13 @@ namespace Spring.Messaging.Nms.IConnections
public override void AfterCompletion(TransactionSynchronizationStatus status)
{
if (this.transacted)
if (transacted)
{
this.resourceHolder.CloseAll();
resourceHolder.CloseAll();
}
}
}
#endregion
}
}
}

View File

@@ -0,0 +1,42 @@
#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 Apache.NMS;
namespace Spring.Messaging.Nms.IConnections
{
/// <summary>
/// Extension of the <code>IConnectionFactory</code> interface,
/// indicating how to release Connections obtained from it.
/// </summary>
/// <author>Juergen Hoeller</author>
/// <author>Mark Pollack (.NET)</author>
public interface ISmartConnectionFactory
{
/// <summary>
/// Shoulds we stop the connection, obtained from this ConnectionFactory?
/// </summary>
/// <param name="con">The connection to check.</param>
/// <returns>wheter a stop call is necessary</returns>
bool ShouldStop(IConnection con);
}
}

View File

@@ -54,6 +54,7 @@ namespace Spring.Messaging.Nms.IConnections
private IList sessions = new LinkedList();
private IDictionary sessionsPerIConnection = new Hashtable();
private IConnectionFactory connectionFactory;
#endregion
@@ -71,12 +72,20 @@ namespace Spring.Messaging.Nms.IConnections
/// </param>
/// <param name="session">the NMS ISession
/// </param>
public NmsResourceHolder(Apache.NMS.IConnection connection, ISession session)
public NmsResourceHolder(Apache.NMS.IConnection connection, ISession session)
{
AddConnection(connection);
AddSession(session, connection);
this.frozen = true;
}
public NmsResourceHolder(IConnectionFactory connectionFactory, IConnection connection, ISession session)
{
this.connectionFactory = connectionFactory;
AddConnection(connection);
AddSession(session, connection);
this.frozen = true;
}
#endregion
#region Properties
@@ -191,25 +200,17 @@ namespace Spring.Messaging.Nms.IConnections
logger.Debug("Could not close NMS ISession after transaction", ex);
}
}
foreach (Apache.NMS.IConnection connection in connections)
foreach (IConnection connection in connections)
{
try
{
try
{
connection.Stop();
}
finally
{
connection.Close();
}
}
catch (Exception ex)
{
logger.Debug("Could not close NMS IConnection after transaction", ex);
}
ConnectionFactoryUtils.ReleaseConnection(connection, connectionFactory, true);
}
}
public bool ContainsSession(ISession session)
{
return this.sessions.Contains(session);
}
#endregion
}
}

View File

@@ -0,0 +1,315 @@
using System;
using System.Data;
using Apache.NMS;
using Common.Logging;
using Spring.Objects.Factory;
using Spring.Transaction;
using Spring.Transaction.Support;
namespace Spring.Messaging.Nms.IConnections
{
/// <summary>
/// A <see cref="AbstractPlatformTransactionManager"/> implementation
/// for a single NMS <code>Apache.NMS.IConnectionFactory</code>. Binds a
/// Connection/Session pair from the specified ConnecctionFactory to the thread,
/// potentially allowing for one thread-bound Session per ConnectionFactory.
/// </summary>
/// <remarks>
/// <para>
/// Application code is required to retrieve the transactional Session via
/// <see cref="ConnectionFactoryUtils.GetTransactionalSession"/>. Spring's
/// <see cref="NmsTemplate"/> will autodetect a thread-bound Session and
/// automatically participate in it.
/// </para>
/// <para>
/// This transaction strategy will typically be used in combination with
/// <see cref="SingleConnectionFactory"/>, which uses a single NMS Connection
/// for all NMS access in order to avoid the overhead of repeated Connection
/// creation. Each transaction will then share the same NMS Connection, while still using
/// its own individual Session.
/// </para>
/// <para>
/// Transaction synchronization is turned off by default, as this manager might be used
/// alongside an IDbProvider based Spring transaction manager such as the
/// AdoPlatformTransactionManager, which has stronger needs for synchronization.
/// </para>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <author>Mark Pollack (.NET)</author>
public class NmsTransactionManager : AbstractPlatformTransactionManager,
IResourceTransactionManager, IInitializingObject
{
#region Logging Definition
private static readonly ILog LOG = LogManager.GetLogger(typeof(NmsTransactionManager));
#endregion
private IConnectionFactory connectionFactory;
/// <summary>
/// Initializes a new instance of the <see cref="NmsTransactionManager"/> class.
/// </summary>
/// <remarks>
/// The ConnectionFactory has to be set before using the instance.
/// This constructor can be used to prepare a NmsTemplate via a ApplicationContext,
/// typically setting the ConnectionFactory via ConnectionFactory property.
/// <para>
/// Turns off transaction synchronization by default, as this manager might
/// be used alongside a dbprovider-based Spring transaction manager like
/// AdoPlatformTransactionManager, which has stronger needs for synchronization.
/// Only one manager is allowed to drive synchronization at any point of time.
/// </para>
/// </remarks>
public NmsTransactionManager()
{
TransactionSynchronization = TransactionSynchronizationState.Never;
}
/// <summary>
/// Initializes a new instance of the <see cref="NmsTransactionManager"/> class
/// given a ConnectionFactory.
/// </summary>
/// <param name="connectionFactory">The connection factory to obtain connections from.</param>
public NmsTransactionManager(IConnectionFactory connectionFactory) : this()
{
ConnectionFactory = connectionFactory;
AfterPropertiesSet();
}
/// <summary>
/// Gets or sets the connection factory that this instance should manage transaction.
/// for.
/// </summary>
/// <value>The connection factory.</value>
public IConnectionFactory ConnectionFactory
{
get { return connectionFactory; }
set
{
//TODO if create TransactionAwareConnectionFactoryProxy need to check for it here.
connectionFactory = value;
}
}
#region IInitializingObject Members
/// <summary>
/// Make sure the ConnectionFactory has been set.
/// </summary>
public void AfterPropertiesSet()
{
if (ConnectionFactory == null)
{
throw new ArgumentException("Property 'ConnectionFactory' is required.");
}
}
#endregion
#region IResourceTransactionManager Members
/// <summary>
/// Gets the resource factory that this transaction manager operates on,
/// In tihs case the ConnectionFactory
/// </summary>
/// <value>The ConnectionFactory.</value>
public object ResourceFactory
{
get { return ConnectionFactory; }
}
#endregion
protected override object DoGetTransaction()
{
NmsTransactionObject txObject = new NmsTransactionObject();
txObject.ResourceHolder =
(NmsResourceHolder) TransactionSynchronizationManager.GetResource(ConnectionFactory);
return txObject;
}
protected override void DoBegin(object transaction, ITransactionDefinition definition)
{
//This is the default value defined in DefaultTransactionDefinition
if (definition.TransactionIsolationLevel != IsolationLevel.ReadCommitted)
{
throw new InvalidIsolationLevelException("NMS does not support an isoliation level concept");
}
NmsTransactionObject txObject = (NmsTransactionObject) transaction;
IConnection con = null;
ISession session = null;
try
{
con = CreateConnection();
session = CreateSession(con);
if (LOG.IsDebugEnabled)
{
log.Debug("Created NMS transaction on Session [" + session + "] from Connection [" + con + "]");
}
txObject.ResourceHolder = new NmsResourceHolder(ConnectionFactory, con, session);
txObject.ResourceHolder.SynchronizedWithTransaction = true;
int timeout = DetermineTimeout(definition);
if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
{
txObject.ResourceHolder.TimeoutInSeconds = timeout;
}
TransactionSynchronizationManager.BindResource(ConnectionFactory, txObject.ResourceHolder);
} catch (NMSException ex)
{
if (session != null)
{
try
{
session.Close();
} catch (Exception)
{}
}
if (con != null)
{
try
{
con.Close();
} catch (Exception){}
}
throw new CannotCreateTransactionException("Could not create NMS Transaction", ex);
}
}
protected override object DoSuspend(object transaction)
{
NmsTransactionObject txObject = (NmsTransactionObject) transaction;
txObject.ResourceHolder = null;
return TransactionSynchronizationManager.UnbindResource(ConnectionFactory);
}
protected override void DoResume(object transaction, object suspendedResources)
{
NmsResourceHolder conHolder = (NmsResourceHolder) suspendedResources;
TransactionSynchronizationManager.BindResource(ConnectionFactory, conHolder);
}
protected override void DoCommit(DefaultTransactionStatus status)
{
NmsTransactionObject txObject = (NmsTransactionObject)status.Transaction;
ISession session = txObject.ResourceHolder.GetSession();
try
{
if (status.Debug)
{
LOG.Debug("Committing NMS transaction on Session [" + session + "]");
}
session.Commit();
///https://issues.apache.org/activemq/browse/AMQNET-93
///TODO - need to mirror JMS exception classes in NMS API.
//} catch (TransactionRolledBackException ex)
//{
}
catch (NMSException ex)
{
throw new TransactionSystemException("Could not commit NMS transaction.", ex);
}
}
protected override void DoRollback(DefaultTransactionStatus status)
{
NmsTransactionObject txObject = (NmsTransactionObject)status.Transaction;
ISession session = txObject.ResourceHolder.GetSession();
try
{
if (status.Debug)
{
LOG.Debug("Rolling back NMS transaction on Session [" + session + "]");
}
session.Rollback();
}
catch (NMSException ex)
{
throw new TransactionSystemException("Could not roll back NMS transaction.", ex);
}
}
protected override void DoSetRollbackOnly(DefaultTransactionStatus status)
{
NmsTransactionObject txObject = (NmsTransactionObject)status.Transaction;
txObject.ResourceHolder.RollbackOnly = true;
}
protected override void DoCleanupAfterCompletion(object transaction)
{
NmsTransactionObject txObject = (NmsTransactionObject)transaction;
TransactionSynchronizationManager.UnbindResource(ConnectionFactory);
txObject.ResourceHolder.CloseAll();
txObject.ResourceHolder.Clear();
}
protected override bool IsExistingTransaction(object transaction)
{
NmsTransactionObject txObject = transaction as NmsTransactionObject;
if (txObject != null)
{
return txObject.ResourceHolder != null;
}
return false;
}
/// <summary>
/// Creates the connection via thie manager's ConnectionFactory.
/// </summary>
/// <returns>The new Connection</returns>
/// <exception cref="NMSException">If thrown by underlying messaging APIs</exception>
protected virtual IConnection CreateConnection()
{
return ConnectionFactory.CreateConnection();
}
/// <summary>
/// Creates the session for the given Connection
/// </summary>
/// <param name="connection">The connection to create a Session for.</param>
/// <returns>the new Session</returns>
/// <exception cref="NMSException">If thrown by underlying messaging APIs</exception>
protected virtual ISession CreateSession(IConnection connection)
{
return connection.CreateSession(AcknowledgementMode.Transactional);
}
/// <summary>
/// NMS Transaction object, representing a NmsResourceHolder.
/// Used as transaction object by NmsTransactionManager
/// </summary>
internal class NmsTransactionObject : ISmartTransactionObject
{
private NmsResourceHolder resourceHolder;
public NmsResourceHolder ResourceHolder
{
get { return resourceHolder; }
set { resourceHolder = value; }
}
#region ISmartTransactionObject Members
public bool RollbackOnly
{
get { return resourceHolder.RollbackOnly; }
}
#endregion
}
}
}

View File

@@ -0,0 +1,363 @@
#region License
/*
* Copyright <20> 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 Apache.NMS;
using Common.Logging;
using Spring.Objects.Factory;
using Spring.Util;
namespace Spring.Messaging.Nms.IConnections
{
public class SingleConnectionFactory : IConnectionFactory, IInitializingObject, IDisposable
{
#region Logging Definition
private static readonly ILog LOG = LogManager.GetLogger(typeof (SingleConnectionFactory));
#endregion
private IConnectionFactory targetConnectionFactory;
private string clientId;
private ExceptionListener exceptionListenerDelegate;
private bool reconnectOnException = false;
/// <summary>
/// Wrapped Connection
/// </summary>
private IConnection target;
/// <summary>
/// Proxy Connection
/// </summary>
private IConnection connection;
/// <summary>
/// Synchronization monitor for the shared Connection
/// </summary>
private object connectionMonitor = new object();
/// <summary>
/// Initializes a new instance of the <see cref="SingleConnectionFactory"/> class.
/// </summary>
public SingleConnectionFactory()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SingleConnectionFactory"/> class
/// that alwasy returns the given Connection.
/// </summary>
/// <param name="target">The single Connection.</param>
public SingleConnectionFactory(IConnection target)
{
AssertUtils.ArgumentNotNull(target, "connection", "Target Connection must not be null");
this.target = target;
connection = GetSharedConnection(target);
}
/// <summary>
/// Initializes a new instance of the <see cref="SingleConnectionFactory"/> class
/// that alwasy returns a single Connection.
/// </summary>
/// <param name="targetConnectionFactory">The target connection factory.</param>
public SingleConnectionFactory(IConnectionFactory targetConnectionFactory)
{
AssertUtils.ArgumentNotNull(targetConnectionFactory, "targetConnectionFactory",
"Target ConnectionFactory must not be null");
this.targetConnectionFactory = targetConnectionFactory;
}
/// <summary>
/// Gets or sets the target connection factory which will be used to create a single
/// connection.
/// </summary>
/// <value>The target connection factory.</value>
public IConnectionFactory TargetConnectionFactory
{
get { return targetConnectionFactory; }
set { targetConnectionFactory = value; }
}
/// <summary>
/// Gets or sets the client id for the single Connection created and exposed by
/// this ConnectionFactory.
/// </summary>
/// <remarks>Note that the client IDs need to be unique among all active
/// Connections of teh underlying provider. Furthermore, a client ID can only
/// be assigned if the original ConnectionFactory hasn't already assigned one.</remarks>
/// <value>The client id.</value>
public string ClientId
{
get { return clientId; }
set { clientId = value; }
}
/// <summary>
/// Gets or sets the exception listener delegate that should be registered with
/// the single connection created by this factory.
/// </summary>
/// <value>The exception listener delegate.</value>
public ExceptionListener ExceptionListenerDelegate
{
get { return exceptionListenerDelegate; }
set { exceptionListenerDelegate = value; }
}
/// <summary>
/// Gets or sets a value indicating whether the single Connection
/// should be reset (to be subsequently renewed) when a NMSException
/// is reported by the underlying Connection.
/// </summary>
/// <remarks>
/// Default is <code>false</code>. Switch this to <code>true</code>
/// to automatically trigger recover based on your messaging provider's
/// exception notifications.
/// <para>
/// Internally, this will lead to a special ExceptionListener (this
/// SingleConnectionFactory itself) being registered with the underlying
/// Connection. This can also be combined with a user-specified
/// ExceptionListener, if desired.
/// </para>
/// </remarks>
/// <value>
/// <c>true</c> if [reconnect on exception]; otherwise, <c>false</c>.
/// </value>
public bool ReconnectOnException
{
get { return reconnectOnException; }
set { reconnectOnException = value; }
}
#region IConnectionFactory Members
public IConnection CreateConnection()
{
lock (connectionMonitor)
{
if (connection == null)
{
InitConnection();
}
return connection;
}
}
public void InitConnection()
{
if (TargetConnectionFactory == null)
{
throw new ArgumentException(
"'TargetConnectionFactory' is required for lazily initializing a Connection");
}
lock (connectionMonitor)
{
if (this.target != null)
{
CloseConnection(this.target);
}
this.target = DoCreateConnection();
PrepareConnection(this.target);
if (LOG.IsDebugEnabled)
{
LOG.Info("Established shared NMS Connection: " + this.target);
}
this.connection = GetSharedConnection(this.target);
}
}
protected virtual void PrepareConnection(IConnection con)
{
if (ClientId != null)
{
con.ClientId = ClientId;
}
if (ExceptionListenerDelegate != null || ReconnectOnException)
{
ExceptionListener listenerToUse = ExceptionListenerDelegate;
if (ReconnectOnException)
{
InternalChainedExceptionListenerSupport chained = new InternalChainedExceptionListenerSupport(this, listenerToUse);
con.ExceptionListener += chained.OnException;
}
}
}
protected virtual IConnection DoCreateConnection()
{
return TargetConnectionFactory.CreateConnection();
}
private void CloseConnection(IConnection con)
{
try
{
try
{
con.Stop();
} finally
{
con.Close();
}
} catch (Exception ex)
{
LOG.Warn("Could not close shared NMS connection.");
}
}
public IConnection CreateConnection(string userName, string password)
{
throw new NotImplementedException();
}
#endregion
#region IInitializingObject Members
public void AfterPropertiesSet()
{
if (connection == null && TargetConnectionFactory == null)
{
throw new ArgumentException("Connection or 'TargetConnectionFactory' is required.");
}
}
#endregion
#region IDisposable Members
public void Dispose()
{
ResetConnection();
}
public void ResetConnection()
{
lock (connectionMonitor)
{
if (this.target != null)
{
CloseConnection(this.target);
}
this.target = null;
this.connection = null;
}
}
#endregion
protected virtual IConnection GetSharedConnection(IConnection target)
{
lock (connectionMonitor)
{
return new CloseSupressingConnection(target);
}
}
}
internal class InternalChainedExceptionListenerSupport
{
private SingleConnectionFactory factory;
private ExceptionListener listenerToUse;
public InternalChainedExceptionListenerSupport(SingleConnectionFactory factory, ExceptionListener listenerToUse)
{
this.factory = factory;
this.listenerToUse = listenerToUse;
}
public void OnException(Exception exception)
{
//TODO exception mgmt.
}
}
internal class CloseSupressingConnection : IConnection
{
private IConnection target;
public CloseSupressingConnection(IConnection target)
{
this.target = target;
}
public event ExceptionListener ExceptionListener
{
add { target.ExceptionListener += value; }
remove { target.ExceptionListener -= value; }
}
public ISession CreateSession()
{
return target.CreateSession();
}
public ISession CreateSession(AcknowledgementMode acknowledgementMode)
{
return target.CreateSession(acknowledgementMode);
}
public void Close()
{
// don't pass the call to the target.
}
public AcknowledgementMode AcknowledgementMode
{
get { return target.AcknowledgementMode; }
set { target.AcknowledgementMode = value; }
}
public string ClientId
{
get { return target.ClientId; }
set { target.ClientId = value; }
}
public void Dispose()
{
target.Dispose();
}
public void Start()
{
target.Start();
}
public bool IsStarted
{
get { return target.IsStarted; }
}
public void Stop()
{
//don't pass the call to the target.
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections;
using Spring.Context;
using Spring.Messaging.Nms.IConnections;
using Spring.Messaging.Nms.Support;
using Spring.Messaging.Nms.Support.IDestinations;
using Spring.Util;
@@ -505,7 +506,7 @@ namespace Spring.Messaging.Nms.Listener
{
lock (this.sharedConnectionMonitor)
{
NmsUtils.CloseConnection(this.sharedConnection);
ConnectionFactoryUtils.ReleaseConnection(sharedConnection, ConnectionFactory, autoStartup);
}
throw;
}

View File

@@ -77,8 +77,6 @@ namespace Spring.Messaging.Nms
private TimeSpan timeToLive;
private bool cacheNmsResources = true;
private NmsResources jmsResources = new NmsResources();
#endregion
@@ -180,17 +178,10 @@ namespace Spring.Messaging.Nms
return action.DoInNms(sessionToUse);
}
//TODO make sure don't want to do exception translation.
//TODO investigate options to not close session/connection via caching since
//these objects are thread safe in tibco ems.
finally
{
if (!CacheNmsResources)
{
NmsUtils.CloseSession(sessionToClose);
NmsUtils.CloseConnection(conToClose, startConnection);
}
//TODO No IConnectionFactory interface so can't create
// non closing impl of IConnection Need NMS.
NmsUtils.CloseSession(sessionToClose);
ConnectionFactoryUtils.ReleaseConnection(conToClose, ConnectionFactory, startConnection);
}
}
@@ -358,12 +349,6 @@ namespace Spring.Messaging.Nms
}
virtual public bool CacheNmsResources
{
get { return cacheNmsResources; }
set { cacheNmsResources = value; }
}
#endregion
protected virtual object DoConvertFromMessage(IMessage message)
@@ -401,58 +386,6 @@ namespace Spring.Messaging.Nms
return holder.GetSession();
}
/// <summary>Create a NMS IConnection via this template's IConnectionFactory.
/// </summary>
/// <remarks>If CacheNmsResource is true, then the connection
/// will be created upon the first invocation and will retrun the same
/// connection on all subsequent calls.
/// </remarks>
/// <returns>A NMS IConnection
/// </returns>
/// <throws>NMSException if thrown by NMS API methods </throws>
protected virtual IConnection CreateConnection()
{
if (this.CacheNmsResources)
{
if (jmsResources.Connection == null)
{
jmsResources.Connection = ConnectionFactory.CreateConnection();
}
return jmsResources.Connection;
}
else
{
return ConnectionFactory.CreateConnection();
}
}
/// <summary> Create a NMS ISession for the given IConnection.
/// <p>This implementation uses NMS 1.1 API.</p>
/// </summary>
/// <param name="con">the NMS IConnection to create a ISession for
/// </param>
/// <returns> the new NMS ISession
/// </returns>
/// <throws>NMSException if thrown by NMS API methods </throws>
protected virtual ISession CreateSession(IConnection con)
{
if (CacheNmsResources)
{
if (jmsResources.Session == null)
{
jmsResources.Session = jmsResources.Connection.CreateSession(SessionAcknowledgeMode);
}
return jmsResources.Session;
}
else
{
return con.CreateSession(SessionAcknowledgeMode);
}
}
/// <summary> Create a NMS IMessageProducer for the given ISession and IDestination,
/// configuring it to disable message ids and/or timestamps (if necessary).
/// <p>Delegates to <code>doCreateProducer</code> for creation of the raw
@@ -498,18 +431,7 @@ namespace Spring.Messaging.Nms
/// <throws>NMSException if thrown by NMS API methods </throws>
protected virtual IMessageProducer DoCreateProducer(ISession session, IDestination destination)
{
if (CacheNmsResources)
{
if (jmsResources.MessageProducer == null)
{
jmsResources.MessageProducer = session.CreateProducer(destination);
}
return jmsResources.MessageProducer;
}
else
{
return session.CreateProducer(destination);
}
return session.CreateProducer(destination);
}
/// <summary> Create a NMS IMessageConsumer for the given ISession and IDestination.
@@ -595,19 +517,12 @@ namespace Spring.Messaging.Nms
}
}
finally
{
CloseProducer(producer);
}
}
private void CloseProducer(IMessageProducer producer)
{
if (!CacheNmsResources)
{
NmsUtils.CloseMessageProducer(producer);
}
}
/// <summary> Actually send the given NMS message.</summary>
/// <param name="producer">the NMS IMessageProducer to send with
/// </param>

View File

@@ -112,8 +112,14 @@ namespace Spring.Messaging.Nms.Support
/// </remarks>
public bool SessionTransacted
{
get { return sessionTransacted; }
set { sessionTransacted = value; }
get { return SessionAcknowledgeMode == AcknowledgementMode.Transactional; }
set
{
if (value)
{
sessionAcknowledgeMode = AcknowledgementMode.Transactional;
}
}
}
#endregion
@@ -126,5 +132,19 @@ namespace Spring.Messaging.Nms.Support
throw new ArgumentException("ConnectionFactory is required");
}
}
/// <summary>
/// Creates the connection via the ConnectionFactory.
/// </summary>
/// <returns></returns>
protected virtual IConnection CreateConnection()
{
return ConnectionFactory.CreateConnection();
}
protected virtual ISession CreateSession(IConnection con)
{
return con.CreateSession(SessionAcknowledgeMode);
}
}
}

View File

@@ -48,7 +48,10 @@
<ItemGroup>
<Compile Include="Context\ILifecycle.cs" />
<Compile Include="Messaging\Nms\Connections\ConnectionFactoryUtils.cs" />
<Compile Include="Messaging\Nms\Connections\ISmartConnectionFactory.cs" />
<Compile Include="Messaging\Nms\Connections\NmsResourceHolder.cs" />
<Compile Include="Messaging\Nms\Connections\NmsTransactionManager.cs" />
<Compile Include="Messaging\Nms\Connections\SingleConnectionFactory.cs" />
<Compile Include="Messaging\Nms\Connections\SynchedLocalTransactionFailedException.cs" />
<Compile Include="Messaging\Nms\IMessageCreator.cs" />
<Compile Include="Messaging\Nms\IMessageListener.cs" />
@@ -74,6 +77,10 @@
<Compile Include="Messaging\Nms\Support\NmsUtils.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Spring.Aop\Spring.Aop.2005.csproj">
<Project>{3A3A4E65-45A6-4B20-B460-0BEDC302C02C}</Project>
<Name>Spring.Aop.2005</Name>
</ProjectReference>
<ProjectReference Include="..\Spring.Core\Spring.Core.2005.csproj">
<Project>{710961A3-0DF4-49E4-A26E-F5B9C044AC84}</Project>
<Name>Spring.Core.2005</Name>

View File

@@ -53,6 +53,7 @@ namespace Spring.Data
SqlConnection conn = new SqlConnection(connString);
conn.Open();
conn.Open();
//conn.BeginTransaction(IsolationLevel.Unspecified);
SqlTransaction trans = conn.BeginTransaction();
Console.WriteLine(trans.IsolationLevel);

View File

@@ -4,9 +4,6 @@
<sectionGroup name="common">
<section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
</sectionGroup>
<sectionGroup name="spring">
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>

View File

@@ -1,58 +1,5 @@
using System.Reflection;
using System.Runtime.CompilerServices;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
//
// In order to sign your assembly you must specify a key to use. Refer to the
// Microsoft .NET Framework documentation for more information on assembly signing.
//
// Use the attributes below to control which key is used for signing.
//
// Notes:
// (*) If no key is specified, the assembly is not signed.
// (*) KeyName refers to a key that has been installed in the Crypto Service
// Provider (CSP) on your machine. KeyFile refers to a file which contains
// a key.
// (*) If the KeyFile and the KeyName values are both specified, the
// following processing occurs:
// (1) If the KeyName can be found in the CSP, that key is used.
// (2) If the KeyName does not exist and the KeyFile does exist, the key
// in the KeyFile is installed into the CSP and used.
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
// When specifying the KeyFile, the location of the KeyFile should be
// relative to the project output directory which is
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
// located in the project directory, you would specify the AssemblyKeyFile
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
// documentation for more information on this.
//
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]
[assembly: AssemblyTitle("Spring.Messaging.Nms Tests")]
[assembly: AssemblyDescription("Unit tests for Spring.Messaging.Nms assembly")]

View File

@@ -0,0 +1,338 @@
#region License
/*
* Copyright <20> 2002-2007 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
#region Imports
using System;
using Apache.NMS;
using NUnit.Framework;
using Rhino.Mocks;
using Spring.Messaging.Nms.IConnections;
using Spring.Transaction;
using Spring.Transaction.Support;
#endregion
namespace Spring.Messaging.Nms.Connections
{
/// <summary>
/// This class contains tests for
/// </summary>
/// <author>Mark Pollack</author>
/// <version>$Id:$</version>
[TestFixture]
public class NmsTransactionManagerTests
{
private MockRepository mocks;
[SetUp]
public void Setup()
{
mocks = new MockRepository();
}
[Test]
public void TransactionCommit()
{
IConnectionFactory connectionFactory = (IConnectionFactory) mocks.CreateMock(typeof (IConnectionFactory));
IConnection connection = (IConnection) mocks.CreateMock(typeof (IConnection));
ISession session = (ISession) mocks.CreateMock(typeof (ISession));
using (mocks.Ordered())
{
SetupCommitExpectations(connection, connectionFactory, session);
}
mocks.ReplayAll();
NmsTransactionManager tm = new NmsTransactionManager(connectionFactory);
ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition());
NmsTemplate nt = new NmsTemplate(connectionFactory);
nt.Execute(new AssertSessionCallback(session));
tm.Commit(ts);
mocks.VerifyAll();
}
[Test]
public void TransactionRollback()
{
IConnectionFactory connectionFactory = (IConnectionFactory) mocks.CreateMock(typeof (IConnectionFactory));
IConnection connection = (IConnection) mocks.CreateMock(typeof (IConnection));
ISession session = (ISession) mocks.CreateMock(typeof (ISession));
SetupRollbackExpectations(connection, connectionFactory, session);
mocks.ReplayAll();
NmsTransactionManager tm = new NmsTransactionManager(connectionFactory);
ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition());
NmsTemplate nt = new NmsTemplate(connectionFactory);
nt.Execute(new AssertSessionCallback(session));
tm.Rollback(ts);
mocks.VerifyAll();
}
/**
* TODO because using anonymous delegates - refactor to support .net 1.1 later.
*/
#if NET_2_0
[Test]
public void ParticipatingTransactionWithCommit()
{
IConnectionFactory connectionFactory = (IConnectionFactory)mocks.CreateMock(typeof(IConnectionFactory));
IConnection connection = (IConnection)mocks.CreateMock(typeof(IConnection));
ISession session = (ISession)mocks.CreateMock(typeof(ISession));
using (mocks.Ordered())
{
SetupCommitExpectations(connection, connectionFactory, session);
}
mocks.ReplayAll();
NmsTransactionManager tm = new NmsTransactionManager(connectionFactory);
ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition());
NmsTemplate nt = new NmsTemplate(connectionFactory);
nt.Execute(new AssertSessionCallback(session));
TransactionTemplate tt = new TransactionTemplate(tm);
tt.Execute(delegate(ITransactionStatus status)
{
nt.Execute(new AssertSessionCallback(session));
return null;
});
tm.Commit(ts);
mocks.VerifyAll();
}
[Test]
public void ParticipatingTransactionWithRollback()
{
IConnectionFactory connectionFactory = (IConnectionFactory) mocks.CreateMock(typeof (IConnectionFactory));
IConnection connection = (IConnection) mocks.CreateMock(typeof (IConnection));
ISession session = (ISession) mocks.CreateMock(typeof (ISession));
using (mocks.Ordered())
{
SetupRollbackExpectations(connection, connectionFactory, session);
}
mocks.ReplayAll();
NmsTransactionManager tm = new NmsTransactionManager(connectionFactory);
ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition());
NmsTemplate nt = new NmsTemplate(connectionFactory);
nt.Execute(new AssertSessionCallback(session));
TransactionTemplate tt = new TransactionTemplate(tm);
tt.Execute(delegate(ITransactionStatus status)
{
nt.Execute(new AssertSessionCallback(session));
status.RollbackOnly = true;
return null;
});
try
{
tm.Commit(ts);
Assert.Fail("Should have thrown UnexpectedRollbackException");
} catch (UnexpectedRollbackException)
{
}
mocks.VerifyAll();
}
[Test]
public void SuspendedTransaction()
{
IConnectionFactory connectionFactory = (IConnectionFactory) mocks.CreateMock(typeof (IConnectionFactory));
IConnection connection = (IConnection) mocks.CreateMock(typeof (IConnection));
ISession session = (ISession) mocks.CreateMock(typeof (ISession));
ISession session2 = (ISession)mocks.CreateMock(typeof(ISession));
Expect.Call(connectionFactory.CreateConnection()).Return(connection).Repeat.Twice();
Expect.Call(connection.CreateSession(AcknowledgementMode.Transactional)).Return(session).Repeat.Once();
Expect.Call(connection.CreateSession(AcknowledgementMode.AutoAcknowledge)).Return(session2).Repeat.Once();
session.Commit();
LastCall.On(session).Repeat.Once();
session.Close();
LastCall.On(session).Repeat.Once();
session2.Close();
LastCall.On(session2).Repeat.Once();
connection.Close();
LastCall.On(connection).Repeat.Twice();
mocks.ReplayAll();
NmsTransactionManager tm = new NmsTransactionManager(connectionFactory);
ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition());
NmsTemplate nt = new NmsTemplate(connectionFactory);
nt.Execute(new AssertSessionCallback(session));
TransactionTemplate tt = new TransactionTemplate(tm);
tt.PropagationBehavior = TransactionPropagation.NotSupported;
tt.Execute(delegate(ITransactionStatus status)
{
nt.Execute(new AssertNotSameSessionCallback(session));
return null;
});
nt.Execute(new AssertSessionCallback(session));
tm.Commit(ts);
mocks.VerifyAll();
}
[Test]
public void TransactionSuspension()
{
IConnectionFactory connectionFactory = (IConnectionFactory)mocks.CreateMock(typeof(IConnectionFactory));
IConnection connection = (IConnection)mocks.CreateMock(typeof(IConnection));
ISession session = (ISession)mocks.CreateMock(typeof(ISession));
ISession session2 = (ISession)mocks.CreateMock(typeof(ISession));
Expect.Call(connectionFactory.CreateConnection()).Return(connection).Repeat.Twice();
Expect.Call(connection.CreateSession(AcknowledgementMode.Transactional)).Return(session).Repeat.Once();
Expect.Call(connection.CreateSession(AcknowledgementMode.Transactional)).Return(session2).Repeat.Once();
session.Commit();
LastCall.On(session).Repeat.Once();
session2.Commit();
LastCall.On(session2).Repeat.Once();
session.Close();
LastCall.On(session).Repeat.Once();
session2.Close();
LastCall.On(session2).Repeat.Once();
connection.Close();
LastCall.On(connection).Repeat.Twice();
mocks.ReplayAll();
NmsTransactionManager tm = new NmsTransactionManager(connectionFactory);
ITransactionStatus ts = tm.GetTransaction(new DefaultTransactionDefinition());
NmsTemplate nt = new NmsTemplate(connectionFactory);
TransactionTemplate tt = new TransactionTemplate(tm);
tt.PropagationBehavior = TransactionPropagation.RequiresNew;
tt.Execute(delegate(ITransactionStatus status)
{
nt.Execute(new AssertNotSameSessionCallback(session));
return null;
});
nt.Execute(new AssertSessionCallback(session));
tm.Commit(ts);
mocks.VerifyAll();
}
#endif
private static void SetupRollbackExpectations(IConnection connection, IConnectionFactory connectionFactory, ISession session)
{
Expect.Call(connectionFactory.CreateConnection()).Return(connection).Repeat.Once();
Expect.Call(connection.CreateSession(AcknowledgementMode.Transactional)).Return(session).Repeat.Once();
session.Rollback();
LastCall.On(session).Repeat.Once();
session.Close();
LastCall.On(session).Repeat.Once();
connection.Close();
LastCall.On(connection).Repeat.Once();
}
private static void SetupCommitExpectations(IConnection connection, IConnectionFactory connectionFactory, ISession session)
{
Expect.Call(connectionFactory.CreateConnection()).Return(connection).Repeat.Once();
Expect.Call(connection.CreateSession(AcknowledgementMode.Transactional)).Return(session).Repeat.Once();
session.Commit();
LastCall.On(session).Repeat.Once();
session.Close();
LastCall.On(session).Repeat.Once();
connection.Close();
LastCall.On(connection).Repeat.Once();
}
[TearDown]
public void TearDown()
{
Assert.IsTrue(TransactionSynchronizationManager.ResourceDictionary.Count == 0);
Assert.IsFalse(TransactionSynchronizationManager.SynchronizationActive);
}
}
internal class AssertSessionCallback : ISessionCallback
{
private ISession session;
public AssertSessionCallback(ISession session)
{
this.session = session;
}
#region ISessionCallback Members
public object DoInNms(ISession session)
{
Assert.IsTrue(this.session == session);
return null;
}
#endregion
}
internal class AssertNotSameSessionCallback : ISessionCallback
{
private ISession session;
public AssertNotSameSessionCallback(ISession session)
{
this.session = session;
}
#region ISessionCallback Members
public object DoInNms(ISession session)
{
Assert.IsTrue(this.session != session);
return null;
}
#endregion
}
}

View File

@@ -15,7 +15,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\..\build\VS.NET.2005\Spring.Messaging.Nms.Tests\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DefineConstants>TRACE;DEBUG;NET_2_0</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
@@ -28,24 +28,61 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Accessibility" />
<Reference Include="antlr.runtime, Version=2.7.5.22, Culture=neutral, PublicKeyToken=65e474d141e25e07, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\net\2.0\antlr.runtime.dll</HintPath>
</Reference>
<Reference Include="Apache.NMS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=65e474d141e25e07, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\Apache.NMS.dll</HintPath>
</Reference>
<Reference Include="Common.Logging, Version=1.2.0.0, Culture=neutral, PublicKeyToken=af08829b84f0328e">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\Common.Logging.dll</HintPath>
</Reference>
<Reference Include="Common.Logging.Log4Net, Version=1.2.0.2, Culture=neutral, PublicKeyToken=af08829b84f0328e, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\Common.Logging.Log4Net.dll</HintPath>
</Reference>
<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\log4net.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=2.2.7.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\net\2.0\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="Rhino.Mocks, Version=2.9.6.40380, Culture=neutral, PublicKeyToken=0b3305902db7183f, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\Rhino.Mocks.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Spring\Spring.Core\Spring.Core.2005.csproj">
<Project>{710961A3-0DF4-49E4-A26E-F5B9C044AC84}</Project>
<Name>Spring.Core.2005</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Spring\Spring.Data\Spring.Data.2005.csproj">
<Project>{AE00E5AB-C39A-436F-86D2-33BFE33E2E40}</Project>
<Name>Spring.Data.2005</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Spring\Spring.Messaging.Nms\Spring.Messaging.Nms.2005.csproj">
<Project>{AEB1578C-9018-4D49-B440-789F38DD2F29}</Project>
<Name>Spring.Messaging.Nms.2005</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Messaging\Nms\Connections\NmsTransactionManagerTests.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Spring.Messaging.Nms.Tests.dll.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>

View File

@@ -20,7 +20,7 @@
<include name="**/*.cs" />
<include name="../CommonAssemblyInfo.cs" />
</sources>
<resources prefix="Spring" dynamicprefix="true" failonempty="true">
<resources prefix="Spring" dynamicprefix="true" failonempty="false">
<include name="**/*.xml" />
</resources>
<references basedir="${current.bin.dir}">

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2002-2005 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.
-->
<configuration>
<configSections>
</configSections>
</configuration>

View File

@@ -192,7 +192,7 @@
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEvent>echo "Copying .xml files for tests"
xcopy "$(ProjectDir)Data" ..\..\..\..\build\VS.Net.2005\Spring.Web.Tests\$(ConfigurationName)\ /y /s /q /d
%25SystemRoot%25\system32\xcopy "$(ProjectDir)Data" ..\..\..\..\build\VS.Net.2005\Spring.Web.Tests\$(ConfigurationName)\ /y /s /q /d
</PostBuildEvent>
</PropertyGroup>
</Project>