diff options
author | Martin Ritchie <ritchiem@apache.org> | 2007-06-28 08:09:20 +0000 |
---|---|---|
committer | Martin Ritchie <ritchiem@apache.org> | 2007-06-28 08:09:20 +0000 |
commit | 79cd6c772da003ddc917eff362f9adaa99e28b49 (patch) | |
tree | bbb1e4b46add9a52f4eb15afe83fb16b5ff6af66 /dotnet | |
parent | e1de334597e23b55c9e91c1f853f52e8313ba103 (diff) | |
download | qpid-python-79cd6c772da003ddc917eff362f9adaa99e28b49.tar.gz |
Merged revisions 539783-539788 via svnmerge from
https://svn.apache.org/repos/asf/incubator/qpid/branches/M2
........
r539783 | tomasr | 2007-05-19 18:40:32 +0100 (Sat, 19 May 2007) | 8 lines
* QPID-495 (Contributed by Carlos Medina) Implement default timeouts for AttainState and SyncWrite
* Fix method signatures
* Remove SSL test with client-side certificates (requires extra setup)
* Add locks AMSQtateManager and AMQProtocolListener to prevent modification of listener collections while processing notifications
* Add library/runtime information to ConnectionStartMethodHandler
* Fix some compiler warnings
* Added XML documentation for some api interfaces
........
r539788 | tomasr | 2007-05-19 19:55:33 +0100 (Sat, 19 May 2007) | 1 line
* Excluded failover tests from nant builds and SSL tests on mono
........
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@551497 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'dotnet')
22 files changed, 361 insertions, 157 deletions
diff --git a/dotnet/Qpid.Client.Tests/Channel/ChannelQueueTest.cs b/dotnet/Qpid.Client.Tests/Channel/ChannelQueueTest.cs index 88a056a245..92f30f8f4d 100644 --- a/dotnet/Qpid.Client.Tests/Channel/ChannelQueueTest.cs +++ b/dotnet/Qpid.Client.Tests/Channel/ChannelQueueTest.cs @@ -93,20 +93,6 @@ namespace Qpid.Client.Tests.Channel }
[Test]
- public void DeleteInExistentQueue()
- {
- try
- {
- _channel.DeleteQueue("Q1", false, false, true);
- _logger.Info("queue deleted");
- }
- catch (AMQException e)
- {
- _logger.Info(e.ToString());
- }
- }
-
- [Test]
public void DeleteUsedQueue()
{
// Create the consumer
@@ -123,7 +109,7 @@ namespace Qpid.Client.Tests.Channel }
[Test]
- public void DeleteUnUsedQueue()
+ public void DeleteUnusedQueue()
{
// delete the queue
_channel.DeleteQueue(_queueName, true, true, true);
diff --git a/dotnet/Qpid.Client.Tests/Qpid.Client.Tests.csproj b/dotnet/Qpid.Client.Tests/Qpid.Client.Tests.csproj index a2c71a5432..d74337b42b 100644 --- a/dotnet/Qpid.Client.Tests/Qpid.Client.Tests.csproj +++ b/dotnet/Qpid.Client.Tests/Qpid.Client.Tests.csproj @@ -95,7 +95,6 @@ </ItemGroup>
<ItemGroup>
<None Include="App.config" />
- <EmbeddedResource Include="connection\QpidTestCert.pfx" />
<None Include="Qpid.Common.DLL.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
diff --git a/dotnet/Qpid.Client.Tests/connection/ConnectionTest.cs b/dotnet/Qpid.Client.Tests/connection/ConnectionTest.cs index d597b013bb..4204a42015 100644 --- a/dotnet/Qpid.Client.Tests/connection/ConnectionTest.cs +++ b/dotnet/Qpid.Client.Tests/connection/ConnectionTest.cs @@ -62,7 +62,7 @@ namespace Qpid.Client.Tests.Connection [Test] [ExpectedException(typeof(AMQConnectionException))] - public void connectionFailure() + public void ConnectionFailure() { string url = "amqp://guest:guest@clientid/testpath?brokerlist='tcp://localhost:5673?retries='0''"; new AMQConnection(QpidConnectionInfo.FromUrl(url)); diff --git a/dotnet/Qpid.Client.Tests/connection/QpidTestCert.pfx b/dotnet/Qpid.Client.Tests/connection/QpidTestCert.pfx Binary files differdeleted file mode 100644 index 3f1855c6e9..0000000000 --- a/dotnet/Qpid.Client.Tests/connection/QpidTestCert.pfx +++ /dev/null diff --git a/dotnet/Qpid.Client.Tests/connection/SslConnectionTest.cs b/dotnet/Qpid.Client.Tests/connection/SslConnectionTest.cs index c3e9affa29..8994279da1 100644 --- a/dotnet/Qpid.Client.Tests/connection/SslConnectionTest.cs +++ b/dotnet/Qpid.Client.Tests/connection/SslConnectionTest.cs @@ -31,7 +31,7 @@ namespace Qpid.Client.Tests.Connection /// <summary>
/// Test SSL/TLS connections to the broker
/// </summary>
- [TestFixture]
+ [TestFixture, Category("SSL")]
public class SslConnectionTest
{
/// <summary>
@@ -48,20 +48,6 @@ namespace Qpid.Client.Tests.Connection MakeBrokerConnection(sslConfig);
}
- /// <summary>
- /// Make a TLS connection to the broker with a
- /// client-side certificate
- /// </summary>
- [Test]
- public void DoSslConnectionWithClientCert()
- {
- // because for tests we don't usually trust the server certificate
- // we need here to tell the client to ignore certificate validation errors
- SslOptions sslConfig = new SslOptions(LoadClientCert(), true);
-
- MakeBrokerConnection(sslConfig);
- }
-
private static void MakeBrokerConnection(SslOptions options)
{
IConnectionInfo connectionInfo = new QpidConnectionInfo();
@@ -73,19 +59,5 @@ namespace Qpid.Client.Tests.Connection Console.WriteLine("connection = " + connection);
}
}
-
- private static X509Certificate LoadClientCert()
- {
- // load a self-issued certificate from an embedded
- // resource
- const string name = "Qpid.Client.Tests.connection.QpidTestCert.pfx";
- Assembly assembly = typeof(SslConnectionTest).Assembly;
-
- Stream res = assembly.GetManifestResourceStream(name);
- byte[] buffer = new byte[res.Length];
- res.Read(buffer, 0, buffer.Length);
-
- return new X509Certificate(buffer);
- }
}
}
diff --git a/dotnet/Qpid.Client.Tests/default.build b/dotnet/Qpid.Client.Tests/default.build index 3020f760b8..88d06284d7 100644 --- a/dotnet/Qpid.Client.Tests/default.build +++ b/dotnet/Qpid.Client.Tests/default.build @@ -18,9 +18,6 @@ <include name="${build.dir}/Qpid.Messaging.dll" /> <include name="${build.dir}/Qpid.Sasl.dll" /> </references> - <resources dynamicprefix="true" prefix="${project::get-name()}.Tests"> - <include name="connection/QpidTestCert.pfx"/> - </resources> </csc> <copy tofile="${build.dir}/${project::get-name()}.Tests.dll.config" @@ -34,7 +31,15 @@ <target name="test" depends="build"> <nunit2> <formatter type="${nant.formatter}" usefile="false" /> - <test assemblyname="${build.dir}/${project::get-name()}.Tests.dll" /> + <test> + <assemblies> + <include name="${build.dir}/${project::get-name()}.tests.dll"/> + </assemblies> + <categories> + <exclude name="Failover"/> + <exclude name="SSL" if="${framework::get-target-framework() == 'mono-2.0'}"/> + </categories> + </test> </nunit2> </target> </project> diff --git a/dotnet/Qpid.Client.Tests/failover/FailoverTest.cs b/dotnet/Qpid.Client.Tests/failover/FailoverTest.cs index 24b16e37ec..7d7426a6a5 100644 --- a/dotnet/Qpid.Client.Tests/failover/FailoverTest.cs +++ b/dotnet/Qpid.Client.Tests/failover/FailoverTest.cs @@ -27,7 +27,7 @@ using Qpid.Messaging; namespace Qpid.Client.Tests.failover { - [TestFixture] + [TestFixture, Category("Failover")] public class FailoverTest : IConnectionListener { private static readonly ILog _logger = LogManager.GetLogger(typeof(FailoverTest)); diff --git a/dotnet/Qpid.Client.Tests/failover/FailoverTxTest.cs b/dotnet/Qpid.Client.Tests/failover/FailoverTxTest.cs index ccb95b0c7d..9063149bad 100644 --- a/dotnet/Qpid.Client.Tests/failover/FailoverTxTest.cs +++ b/dotnet/Qpid.Client.Tests/failover/FailoverTxTest.cs @@ -28,7 +28,7 @@ using Qpid.Messaging; namespace Qpid.Client.Tests.failover { - [TestFixture] + [TestFixture, Category("Failover")] public class FailoverTxTest : IConnectionListener { private static readonly ILog _log = LogManager.GetLogger(typeof(FailoverTxTest)); diff --git a/dotnet/Qpid.Client/Client/BasicMessageProducer.cs b/dotnet/Qpid.Client/Client/BasicMessageProducer.cs index fd430694df..c1af826102 100644 --- a/dotnet/Qpid.Client/Client/BasicMessageProducer.cs +++ b/dotnet/Qpid.Client/Client/BasicMessageProducer.cs @@ -44,7 +44,7 @@ namespace Qpid.Client /// <summary> /// Time to live of messages. Specified in milliseconds but AMQ has 1 second resolution. - /// + /// </summary> private long _timeToLive; /// <summary> @@ -88,17 +88,6 @@ namespace Qpid.Client /// </summary> private AmqChannel _channel; - /// <summary> - /// Default value for immediate flag is false, i.e. a consumer does not need to be attached to a queue - /// </summary> - protected const bool DEFAULT_IMMEDIATE = false; - - /// <summary> - /// Default value for mandatory flag is true, i.e. server will not silently drop messages where no queue is - /// connected to the exchange for the message - /// </summary> - protected const bool DEFAULT_MANDATORY = true; - public BasicMessageProducer(string exchangeName, string routingKey, bool transacted, ushort channelId, @@ -206,15 +195,31 @@ namespace Qpid.Client public void Send(IMessage msg, DeliveryMode deliveryMode, int priority, long timeToLive) { CheckNotClosed(); - SendImpl(_exchangeName, _routingKey, (AbstractQmsMessage)msg, deliveryMode, priority, (uint)timeToLive, DEFAULT_MANDATORY, - DEFAULT_IMMEDIATE); + SendImpl( + _exchangeName, + _routingKey, + (AbstractQmsMessage)msg, + deliveryMode, + priority, + (uint)timeToLive, + _mandatory, + _immediate + ); } public void Send(IMessage msg) { CheckNotClosed(); - SendImpl(_exchangeName, _routingKey, (AbstractQmsMessage)msg, _deliveryMode, _messagePriority, (uint)_timeToLive, - DEFAULT_MANDATORY, DEFAULT_IMMEDIATE); + SendImpl( + _exchangeName, + _routingKey, + (AbstractQmsMessage)msg, + _deliveryMode, + _messagePriority, + (uint)_timeToLive, + _mandatory, + _immediate + ); } // This is a short-term hack (knowing that this code will be re-vamped sometime soon) @@ -222,8 +227,16 @@ namespace Qpid.Client public void Send(IMessage msg, bool mandatory) { CheckNotClosed(); - SendImpl(_exchangeName, _routingKey, (AbstractQmsMessage)msg, _deliveryMode, _messagePriority, (uint)_timeToLive, - mandatory, DEFAULT_IMMEDIATE); + SendImpl( + _exchangeName, + _routingKey, + (AbstractQmsMessage)msg, + _deliveryMode, + _messagePriority, + (uint)_timeToLive, + mandatory, + _immediate + ); } public long TimeToLive @@ -248,6 +261,11 @@ namespace Qpid.Client public string MimeType { + get + { + CheckNotClosed(); + return _mimeType; + } set { CheckNotClosed(); @@ -257,6 +275,11 @@ namespace Qpid.Client public string Encoding { + get + { + CheckNotClosed(); + return _encoding; + } set { CheckNotClosed(); diff --git a/dotnet/Qpid.Client/Client/Handler/ConnectionStartMethodHandler.cs b/dotnet/Qpid.Client/Client/Handler/ConnectionStartMethodHandler.cs index 99ee7e2587..3cb7c76e23 100644 --- a/dotnet/Qpid.Client/Client/Handler/ConnectionStartMethodHandler.cs +++ b/dotnet/Qpid.Client/Client/Handler/ConnectionStartMethodHandler.cs @@ -89,16 +89,16 @@ namespace Qpid.Client.Handler private string GetFullSystemInfo() { - /*StringBuffer fullSystemInfo = new StringBuffer(); - fullSystemInfo.append(System.getProperty("java.runtime.name")); - fullSystemInfo.append(", " + System.getProperty("java.runtime.version")); - fullSystemInfo.append(", " + System.getProperty("java.vendor")); - fullSystemInfo.append(", " + System.getProperty("os.arch")); - fullSystemInfo.append(", " + System.getProperty("os.name")); - fullSystemInfo.append(", " + System.getProperty("os.version")); - fullSystemInfo.append(", " + System.getProperty("sun.os.patch.level"));*/ - // TODO: add in details here - return ".NET 1.1 Client"; + StringBuilder sysInfo = new StringBuilder(); + // check if we're running on mono or .net + Type monoRuntime = Type.GetType("Mono.Runtime"); + if ( monoRuntime != null ) + sysInfo.Append("Mono"); + else + sysInfo.Append(".NET"); + sysInfo.Append(" ").Append(Environment.Version); + sysInfo.Append(", ").Append(Environment.OSVersion); + return sysInfo.ToString(); } private string ChooseMechanism(string mechanisms) diff --git a/dotnet/Qpid.Client/Client/Message/AbstractQmsMessage.cs b/dotnet/Qpid.Client/Client/Message/AbstractQmsMessage.cs index 8e90e852dd..7a28d7a85f 100644 --- a/dotnet/Qpid.Client/Client/Message/AbstractQmsMessage.cs +++ b/dotnet/Qpid.Client/Client/Message/AbstractQmsMessage.cs @@ -30,8 +30,6 @@ namespace Qpid.Client.Message { public abstract class AbstractQmsMessage : AMQMessage, IMessage { - private static readonly ILog _log = LogManager.GetLogger(typeof(AbstractQmsMessage)); - protected bool _redelivered; protected ByteBuffer _data; diff --git a/dotnet/Qpid.Client/Client/Protocol/AMQProtocolListener.cs b/dotnet/Qpid.Client/Client/Protocol/AMQProtocolListener.cs index 2b6f239127..2bf9f9a4c1 100644 --- a/dotnet/Qpid.Client/Client/Protocol/AMQProtocolListener.cs +++ b/dotnet/Qpid.Client/Client/Protocol/AMQProtocolListener.cs @@ -234,16 +234,21 @@ namespace Qpid.Client.Protocol { // FIXME: not sure if required as StateManager is in _frameListeners. Probably something to do with fail-over. _stateManager.Error(e); - - foreach (IAMQMethodListener listener in _frameListeners) + lock ( _lock ) { - listener.Error(e); + foreach ( IAMQMethodListener listener in _frameListeners ) + { + listener.Error(e); + } } } public void AddFrameListener(IAMQMethodListener listener) { - _frameListeners.Add(listener); + lock ( _lock ) + { + _frameListeners.Add(listener); + } } public void RemoveFrameListener(IAMQMethodListener listener) @@ -252,7 +257,10 @@ namespace Qpid.Client.Protocol { _log.Debug("Removing frame listener: " + listener.ToString()); } - _frameListeners.Remove(listener); + lock ( _lock ) + { + _frameListeners.Remove(listener); + } } public void BlockUntilNotFailingOver() diff --git a/dotnet/Qpid.Client/Client/Protocol/DefaultTimeouts.cs b/dotnet/Qpid.Client/Client/Protocol/DefaultTimeouts.cs new file mode 100644 index 0000000000..0638bf0704 --- /dev/null +++ b/dotnet/Qpid.Client/Client/Protocol/DefaultTimeouts.cs @@ -0,0 +1,47 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+ */
+
+using System;
+using System.Text;
+
+namespace Qpid.Client.Protocol
+{
+ /// <summary>
+ /// Default timeout values for the protocol
+ /// </summary>
+ sealed class DefaultTimeouts
+ {
+ /// <summary>
+ /// Maximum number of milliseconds to wait for a state change
+ /// in the protocol's state machine
+ /// </summary>
+ public const int MaxWaitForState = 30* 1000;
+ /// <summary>
+ /// Maximum number of milliseconds to wait for a reply
+ /// frame when doing synchronous writer to the broker
+ /// </summary>
+ public const int MaxWaitForSyncWriter = 30 * 1000;
+
+ private DefaultTimeouts()
+ {
+ }
+ }
+}
diff --git a/dotnet/Qpid.Client/Client/Protocol/Listener/BlockingMethodFrameListener.cs b/dotnet/Qpid.Client/Client/Protocol/Listener/BlockingMethodFrameListener.cs index 99643fe59f..a020efbf21 100644 --- a/dotnet/Qpid.Client/Client/Protocol/Listener/BlockingMethodFrameListener.cs +++ b/dotnet/Qpid.Client/Client/Protocol/Listener/BlockingMethodFrameListener.cs @@ -80,9 +80,10 @@ namespace Qpid.Client.Protocol.Listener /// <summary> /// This method is called by the thread that wants to wait for a frame. /// </summary> - public AMQMethodEvent BlockForFrame() + /// <param name="timeout">Set the number of milliseconds to wait</param> + public AMQMethodEvent BlockForFrame(int timeout) { - _resetEvent.WaitOne(); + _resetEvent.WaitOne(timeout, true); //at this point the event will have been signalled. The error field might or might not be set // depending on whether an error occurred if (_error != null) diff --git a/dotnet/Qpid.Client/Client/Protocol/ProtocolWriter.cs b/dotnet/Qpid.Client/Client/Protocol/ProtocolWriter.cs index 32847f9b9b..0ef337501e 100644 --- a/dotnet/Qpid.Client/Client/Protocol/ProtocolWriter.cs +++ b/dotnet/Qpid.Client/Client/Protocol/ProtocolWriter.cs @@ -23,6 +23,8 @@ using Qpid.Client.Protocol.Listener; using Qpid.Client.Transport; using Qpid.Framing; +using log4net; + namespace Qpid.Client.Protocol { /// <summary> @@ -30,6 +32,9 @@ namespace Qpid.Client.Protocol /// </summary> public class ProtocolWriter { + + private ILog _logger = LogManager.GetLogger(typeof(ProtocolWriter)); + IProtocolWriter _protocolWriter; IProtocolListener _protocolListener; @@ -51,13 +56,15 @@ namespace Qpid.Client.Protocol /// </summary> /// <param name="frame">the frame</param> /// <param name="listener">the blocking listener. Note the calling thread will block.</param> - private AMQMethodEvent SyncWrite(AMQFrame frame, BlockingMethodFrameListener listener) + /// <param name="timeout">set the number of milliseconds to wait</param> + private AMQMethodEvent SyncWrite(AMQFrame frame, BlockingMethodFrameListener listener, int timeout) { try { _protocolListener.AddFrameListener(listener); _protocolWriter.Write(frame); - return listener.BlockForFrame(); + + return listener.BlockForFrame(timeout); } finally { @@ -67,11 +74,32 @@ namespace Qpid.Client.Protocol // that matches the criteria defined in the blocking listener } + /// <summary> + /// Convenience method that writes a frame to the protocol session and waits for + /// a particular response. Equivalent to calling getProtocolSession().write() then + /// waiting for the response. + /// </summary> + /// <param name="frame">the frame</param> + /// <param name="responseType">the type of method response</param> public AMQMethodEvent SyncWrite(AMQFrame frame, Type responseType) { // TODO: If each frame knew it's response type, then the responseType argument would // TODO: not be neccesary. - return SyncWrite(frame, new SpecificMethodFrameListener(frame.Channel, responseType)); + return SyncWrite(frame, responseType, DefaultTimeouts.MaxWaitForSyncWriter); + } + + /// <summary> + /// Convenience method that writes a frame to the protocol session and waits for + /// a particular response. Equivalent to calling getProtocolSession().write() then + /// waiting for the response. + /// </summary> + /// <param name="frame">the frame</param> + /// <param name="responseType">the type of method response</param> + /// <param name="timeout">set the number of milliseconds to wait</param> + /// <returns>set the number of milliseconds to wait</returns> + public AMQMethodEvent SyncWrite(AMQFrame frame, Type responseType, int timeout) + { + return SyncWrite(frame, new SpecificMethodFrameListener(frame.Channel, responseType), timeout); } } } diff --git a/dotnet/Qpid.Client/Client/State/AMQStateManager.cs b/dotnet/Qpid.Client/Client/State/AMQStateManager.cs index 1233f9d836..9ce6d3c76a 100644 --- a/dotnet/Qpid.Client/Client/State/AMQStateManager.cs +++ b/dotnet/Qpid.Client/Client/State/AMQStateManager.cs @@ -43,13 +43,15 @@ namespace Qpid.Client.State /// Maps from an AMQState instance to a Map from Class to StateTransitionHandler. /// The class must be a subclass of AMQFrame. /// </summary> - private readonly IDictionary _state2HandlersMap = new Hashtable(); - - //private CopyOnWriteArraySet _stateListeners = new CopyOnWriteArraySet(); - private ArrayList _stateListeners = ArrayList.Synchronized(new ArrayList(5)); + private readonly IDictionary _state2HandlersMap; + private ArrayList _stateListeners; + private object _syncLock; public AMQStateManager() { + _syncLock = new object(); + _state2HandlersMap = new Hashtable(); + _stateListeners = ArrayList.Synchronized(new ArrayList(5)); _currentState = AMQState.CONNECTION_NOT_STARTED; RegisterListeners(); } @@ -132,18 +134,24 @@ namespace Qpid.Client.State AMQState oldState = _currentState; _currentState = newState; - foreach (IStateListener l in _stateListeners) + lock ( _syncLock ) { - l.StateChanged(oldState, newState); + foreach ( IStateListener l in _stateListeners ) + { + l.StateChanged(oldState, newState); + } } } public void Error(Exception e) { _logger.Debug("State manager receive error notification: " + e); - foreach (IStateListener l in _stateListeners) + lock ( _syncLock ) { - l.Error(e); + foreach ( IStateListener l in _stateListeners ) + { + l.Error(e); + } } } @@ -206,23 +214,37 @@ namespace Qpid.Client.State public void AddStateListener(IStateListener listener) { _logger.Debug("Adding state listener"); - _stateListeners.Add(listener); + lock ( _syncLock ) + { + _stateListeners.Add(listener); + } } public void RemoveStateListener(IStateListener listener) { - _stateListeners.Remove(listener); + lock ( _syncLock ) + { + _stateListeners.Remove(listener); + } } public void AttainState(AMQState s) { if (_currentState != s) { - _logger.Debug("Adding state wait to reach state " + s); - StateWaiter sw = new StateWaiter(s); - AddStateListener(sw); - sw.WaituntilStateHasChanged(); - // at this point the state will have changed. + StateWaiter sw = null; + try + { + _logger.Debug("Adding state wait to reach state " + s); + sw = new StateWaiter(s); + AddStateListener(sw); + sw.WaituntilStateHasChanged(); + // at this point the state will have changed. + } + finally + { + RemoveStateListener(sw); + } } } } diff --git a/dotnet/Qpid.Client/Client/State/StateWaiter.cs b/dotnet/Qpid.Client/Client/State/StateWaiter.cs index cb7f604499..34667da744 100644 --- a/dotnet/Qpid.Client/Client/State/StateWaiter.cs +++ b/dotnet/Qpid.Client/Client/State/StateWaiter.cs @@ -20,6 +20,7 @@ */ using System; using System.Threading; +using Qpid.Client.Protocol; using log4net; namespace Qpid.Client.State @@ -29,6 +30,7 @@ namespace Qpid.Client.State private static readonly ILog _logger = LogManager.GetLogger(typeof(StateWaiter)); private readonly AMQState _state; + private AMQState _newState; private volatile bool _newStateAchieved; @@ -42,7 +44,8 @@ namespace Qpid.Client.State } public void StateChanged(AMQState oldState, AMQState newState) - { + { + _newState = newState; if (_logger.IsDebugEnabled) { _logger.Debug("stateChanged called"); @@ -76,23 +79,42 @@ namespace Qpid.Client.State // The guard is required in case we are woken up by a spurious // notify(). // - while (!_newStateAchieved && _exception == null) - { + + TimeSpan waitTime = TimeSpan.FromMilliseconds(DefaultTimeouts.MaxWaitForState); + DateTime waitUntilTime = DateTime.Now + waitTime; + + while ( !_newStateAchieved + && _exception == null + && waitTime.TotalMilliseconds > 0 ) + { _logger.Debug("State not achieved so waiting..."); - _resetEvent.WaitOne(); + try + { + _resetEvent.WaitOne(waitTime, true); + } + finally + { + if (!_newStateAchieved) + { + waitTime = waitUntilTime - DateTime.Now; + } + } } if (_exception != null) { _logger.Debug("Throwable reached state waiter: " + _exception); if (_exception is AMQException) - { throw _exception; - } else - { throw new AMQException("Error: " + _exception, _exception); - } + } + + if (!_newStateAchieved) + { + string error = string.Format("State not achieved within permitted time. Current state: {0}, desired state: {1}", _state, _newState); + _logger.Warn(error); + throw new AMQException(error); } } } diff --git a/dotnet/Qpid.Client/Client/Transport/AmqpChannel.cs b/dotnet/Qpid.Client/Client/Transport/AmqpChannel.cs index 4e4ca03322..e23037d1de 100644 --- a/dotnet/Qpid.Client/Client/Transport/AmqpChannel.cs +++ b/dotnet/Qpid.Client/Client/Transport/AmqpChannel.cs @@ -82,10 +82,11 @@ namespace Qpid.Client.Transport _byteChannel.Write(Encode(o)); } - private void OnAsyncWriteDone(IAsyncResult result) - { - _byteChannel.EndWrite(result); - } + // not used for now + //private void OnAsyncWriteDone(IAsyncResult result) + //{ + // _byteChannel.EndWrite(result); + //} private void Decode(ByteBuffer buffer) { diff --git a/dotnet/Qpid.Client/Qpid.Client.csproj b/dotnet/Qpid.Client/Qpid.Client.csproj index 7ac6f94800..e7c05ffebc 100644 --- a/dotnet/Qpid.Client/Qpid.Client.csproj +++ b/dotnet/Qpid.Client/Qpid.Client.csproj @@ -52,6 +52,7 @@ <Compile Include="Client\Configuration\AuthenticationConfigurationSectionHandler.cs" />
<Compile Include="Client\Handler\QueueDeleteOkMethodHandler.cs" />
<Compile Include="Client\Handler\QueuePurgeOkMethodHandler.cs" />
+ <Compile Include="Client\Protocol\DefaultTimeouts.cs" />
<Compile Include="Client\SslOptions.cs" />
<Compile Include="Client\Message\QpidHeaders.cs" />
<Compile Include="Client\QpidConnectionInfo.cs" />
diff --git a/dotnet/Qpid.Messaging/IMessageConsumer.cs b/dotnet/Qpid.Messaging/IMessageConsumer.cs index 20e9bd4b38..7767fae995 100644 --- a/dotnet/Qpid.Messaging/IMessageConsumer.cs +++ b/dotnet/Qpid.Messaging/IMessageConsumer.cs @@ -22,12 +22,56 @@ using System; namespace Qpid.Messaging { - public interface IMessageConsumer : IDisposable - { - MessageReceivedDelegate OnMessage { get; set; } + /// <summary> + /// Describes an object that can be used to receive (consume) + /// messages from an AMQP queue. + /// </summary> + /// <remarks> + /// Consumers are created using either + /// <see cref="IChannel.CreateConsumer"/> or using + /// the builder pattern (preferred) with + /// <see cref="IChannel.CreateConsumerBuilder"/>. + /// + /// <para> + /// Consumers offer two different ways of receiving messages: + /// You can attach a delegate to the <see cref="OnMessage"/> + /// event and be notified when a message arrives, or you can + /// use the <see cref="Receive"/> and <see cref="ReceiveNoWait"/> + /// methods to control when you receive messages. Be aware that you can use + /// one or the other, but not both at the same time. + /// </para> + /// <para> + /// Regardless of which method you choose, the prefetch settings + /// specified when creating the channel will still control when messages + /// are actually received from the AMQP broker. Any messages that arrive + /// between the prefetch window will be queued by the channel + /// until they can be delivered to the consumer (either though the event + /// or until the consumer actively calls <see cref="Receive"/>). + /// </para> + /// </remarks> + public interface IMessageConsumer : IDisposable + { + /// <summary> + /// Fired when a message is received from the broker by the consumer + /// </summary> + MessageReceivedDelegate OnMessage { get; set; } - IMessage Receive(); - IMessage Receive(long delay); - IMessage ReceiveNoWait(); - } + /// <summary> + /// Wait infinitely for a message to be received from the broker + /// </summary> + /// <returns>The message received</returns> + IMessage Receive(); + /// <summary> + /// Wait the specified time until a message is receive from the broker + /// </summary> + /// <param name="delay">Maximum number of milliseconds to wait for a message</param> + /// <returns>The message received, or null if the timeout expires</returns> + IMessage Receive(long delay); + /// <summary> + /// Return a message if one is already available in the channel. + /// Does not wait for one to be received from the broker. + /// </summary> + /// <returns>The message, if it was available, otherwise null</returns> + IMessage ReceiveNoWait(); + } } diff --git a/dotnet/Qpid.Messaging/IMessagePublisher.cs b/dotnet/Qpid.Messaging/IMessagePublisher.cs index ba9b9a2d14..edba868539 100644 --- a/dotnet/Qpid.Messaging/IMessagePublisher.cs +++ b/dotnet/Qpid.Messaging/IMessagePublisher.cs @@ -22,34 +22,71 @@ using System; namespace Qpid.Messaging { - public interface IMessagePublisher : IDisposable - { - DeliveryMode DeliveryMode { get; set; } - string ExchangeName { get; } - string RoutingKey { get; } - bool DisableMessageID { get; set; } - bool DisableMessageTimestamp { get; set; } - int Priority { get; set; } - long TimeToLive { get; set; } + /// <summary> + /// Defines an object capable of publishing messages + /// to an AMQP broker. + /// </summary> + /// <remarks> + /// A publisher can be created using either + /// <see cref="IChannel.CreatePublisher"/> or + /// using the builder pattern (preferred) with + /// <see cref="IChannel.CreatePublisherBuilder"/> + /// </remarks> + public interface IMessagePublisher : IDisposable + { + /// <summary> + /// Default delivery mode to use with this publisher + /// </summary> + DeliveryMode DeliveryMode { get; set; } + /// <summary> + /// Name of exchange messages are published to + /// </summary> + string ExchangeName { get; } + /// <summary> + /// Routing key used when publishing messages + /// </summary> + string RoutingKey { get; } + /// <summary> + /// If true, a message ID will not be generated by the publisher + /// when sending the message + /// </summary> + bool DisableMessageID { get; set; } + /// <summary> + /// If true, no timestamp will be added to the message + /// when publishing it + /// </summary> + bool DisableMessageTimestamp { get; set; } + /// <summary> + /// Default priority used when publishing messages + /// </summary> + int Priority { get; set; } + /// <summary> + /// Default time to live used when publishing messages + /// </summary> + long TimeToLive { get; set; } + /// <summary> + /// Set the default MIME type for messages produced by this producer. + /// This reduces the overhead of each message. + /// </summary> + string MimeType { get; set; } + /// <summary> + /// Set the default encoding for messages produced by this producer. + /// This reduces the overhead of each message. + /// </summary> + string Encoding { get; set; } - /// <summary> - /// Set the default MIME type for messages produced by this producer. This reduces the overhead of each message. - /// </summary> - /// <param>mimeType</param> - string MimeType - { - set; - } - - /// <summary> - /// Set the default encoding for messages produced by this producer. This reduces the overhead of each message. - /// </summary> - string Encoding - { - set; - } - - void Send(IMessage msg); - void Send(IMessage msg, DeliveryMode deliveryMode, int priority, long timeToLive); - } + /// <summary> + /// Publish a message, using any default values configured + /// </summary> + /// <param name="msg">Message to publish</param> + void Send(IMessage msg); + /// <summary> + /// Publish a message with the specified options + /// </summary> + /// <param name="msg">Message to publish</param> + /// <param name="deliveryMode">Delivery mode to use</param> + /// <param name="priority">Priority of the message</param> + /// <param name="timeToLive">Time to live of the message</param> + void Send(IMessage msg, DeliveryMode deliveryMode, int priority, long timeToLive); + } } diff --git a/dotnet/default.build b/dotnet/default.build index 89cb3209db..b9d0bf2762 100644 --- a/dotnet/default.build +++ b/dotnet/default.build @@ -26,10 +26,15 @@ <include name="Qpid.Sasl.Tests/default.build" />
<include name="Qpid.Common.Tests/default.build" />
<include name="Qpid.Client.Tests/default.build" />
+ </fileset>
+
+ <!--
+ Other test or utility assemblies
+ -->
+ <fileset id='other.builds'>
<include name="TopicListener/default.build" />
<include name="TopicPublisher/default.build" />
</fileset>
-
<!--
Prepare environment for a debug build
-->
@@ -80,7 +85,12 @@ <nant target="build">
<buildfiles refid="tests.builds" />
</nant>
- -->
+ <!--
+ Compile test assemblies
+ -->
+ <nant target="build">
+ <buildfiles refid="other.builds" />
+ </nant>
</target>
<!--
|