THRIFT-1412 Thrift Transport classes should manage the lifetime of objects implementing IDisposable by implementing IDisposable themselves
Patch: Joshua Garvin

git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1325013 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/csharp/src/Server/TSimpleServer.cs b/lib/csharp/src/Server/TSimpleServer.cs
index c6fd99e..1099fc1 100644
--- a/lib/csharp/src/Server/TSimpleServer.cs
+++ b/lib/csharp/src/Server/TSimpleServer.cs
@@ -95,39 +95,35 @@
 				TProtocol outputProtocol = null;
 				try
 				{
-					client = serverTransport.Accept();
-					if (client != null)
-					{
-						inputTransport = inputTransportFactory.GetTransport(client);
-						outputTransport = outputTransportFactory.GetTransport(client);
-						inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
-						outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
-						while (processor.Process(inputProtocol, outputProtocol)) { }
-					}
-				}
-				catch (TTransportException ttx)
-				{
-					// Client died, just move on
-					if (stop)
-					{
-						logDelegate("TSimpleServer was shutting down, caught " + ttx.GetType().Name);
-					}
-				}
-				catch (Exception x)
-				{
-					logDelegate(x.ToString());
-				}
-
-				if (inputTransport != null)
-				{
-					inputTransport.Close();
-				}
-
-				if (outputTransport != null)
-				{
-					outputTransport.Close();
-				}
-			}
+          using(client = serverTransport.Accept())
+          {
+            if (client != null)
+            {
+              using(inputTransport = inputTransportFactory.GetTransport(client))
+              {
+                using (outputTransport = outputTransportFactory.GetTransport(client))
+                {
+                  inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+                  outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+                  while (processor.Process(inputProtocol, outputProtocol)) { }
+                }
+              }
+            }
+          }
+        }
+        catch (TTransportException ttx)
+        {
+          // Client died, just move on
+          if (stop)
+          {
+            logDelegate("TSimpleServer was shutting down, caught " + ttx.GetType().Name);
+          }
+        }
+        catch (Exception x)
+        {
+          logDelegate(x.ToString());
+        }
+      }
 
 			if (stop)
 			{
diff --git a/lib/csharp/src/Server/TThreadPoolServer.cs b/lib/csharp/src/Server/TThreadPoolServer.cs
index cf8354e..b257fd8 100644
--- a/lib/csharp/src/Server/TThreadPoolServer.cs
+++ b/lib/csharp/src/Server/TThreadPoolServer.cs
@@ -75,16 +75,20 @@
 			:base(processor, serverTransport, inputTransportFactory, outputTransportFactory,
 				  inputProtocolFactory, outputProtocolFactory, logDel)
 		{
-			if (!ThreadPool.SetMinThreads(minThreadPoolThreads, minThreadPoolThreads))
-			{
-				throw new Exception("Error: could not SetMinThreads in ThreadPool");
-			}
-			if (!ThreadPool.SetMaxThreads(maxThreadPoolThreads, maxThreadPoolThreads))
-			{
-				throw new Exception("Error: could not SetMaxThreads in ThreadPool");
+      lock (typeof(TThreadPoolServer))
+      {
+        if (!ThreadPool.SetMinThreads(minThreadPoolThreads, minThreadPoolThreads))
+        {
+          throw new Exception("Error: could not SetMinThreads in ThreadPool");
+        }
+        if (!ThreadPool.SetMaxThreads(maxThreadPoolThreads, maxThreadPoolThreads))
+        {
+          throw new Exception("Error: could not SetMaxThreads in ThreadPool");
+        }
 			}
 		}
 
+
 		/// <summary>
 		/// Use new ThreadPool thread for each new client connection
 		/// </summary>
diff --git a/lib/csharp/src/Server/TThreadedServer.cs b/lib/csharp/src/Server/TThreadedServer.cs
index f2be073..8e73bb7 100644
--- a/lib/csharp/src/Server/TThreadedServer.cs
+++ b/lib/csharp/src/Server/TThreadedServer.cs
@@ -185,14 +185,18 @@
 			TProtocol outputProtocol = null;
 			try
 			{
-				inputTransport = inputTransportFactory.GetTransport(client);
-				outputTransport = outputTransportFactory.GetTransport(client);
-				inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
-				outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
-				while (processor.Process(inputProtocol, outputProtocol))
-				{
-					//keep processing requests until client disconnects
-				}
+        using (inputTransport = inputTransportFactory.GetTransport(client))
+        {
+          using (outputTransport = outputTransportFactory.GetTransport(client))
+          {
+            inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
+            outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
+            while (processor.Process(inputProtocol, outputProtocol))
+            {
+              //keep processing requests until client disconnects
+            }
+          }
+        }
 			}
 			catch (TTransportException)
 			{
@@ -202,15 +206,6 @@
 				logDelegate("Error: " + x);
 			}
 
-			if (inputTransport != null)
-			{
-				inputTransport.Close();
-			}
-			if (outputTransport != null)
-			{
-				outputTransport.Close();
-			}
-
 			lock (clientLock)
 			{
 				clientThreads.Remove(Thread.CurrentThread);
diff --git a/lib/csharp/src/Transport/TBufferedTransport.cs b/lib/csharp/src/Transport/TBufferedTransport.cs
index 28a855a..14b5db0 100644
--- a/lib/csharp/src/Transport/TBufferedTransport.cs
+++ b/lib/csharp/src/Transport/TBufferedTransport.cs
@@ -22,7 +22,7 @@
 
 namespace Thrift.Transport
 {
-	public class TBufferedTransport : TTransport
+  public class TBufferedTransport : TTransport, IDisposable
 	{
 		private BufferedStream inputBuffer;
 		private BufferedStream outputBuffer;
@@ -96,5 +96,25 @@
 		{
 			outputBuffer.Flush();
 		}
-	}
+
+    #region " IDisposable Support "
+    private bool _IsDisposed;
+
+    // IDisposable
+    protected override void Dispose(bool disposing)
+    {
+      if (!_IsDisposed)
+      {
+        if (disposing)
+        {
+          if (inputBuffer != null)
+            inputBuffer.Dispose();
+          if (outputBuffer != null)
+            outputBuffer.Dispose();
+        }
+      }
+      _IsDisposed = true;
+    }
+    #endregion
+  }
 }
diff --git a/lib/csharp/src/Transport/TFramedTransport.cs b/lib/csharp/src/Transport/TFramedTransport.cs
index e259f5a..3d43112 100644
--- a/lib/csharp/src/Transport/TFramedTransport.cs
+++ b/lib/csharp/src/Transport/TFramedTransport.cs
@@ -16,12 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
+using System;
 using System.IO;
 
 namespace Thrift.Transport
 {
-	public class TFramedTransport : TTransport
+  public class TFramedTransport : TTransport, IDisposable
 	{
 		protected TTransport transport = null;
 		protected MemoryStream writeBuffer;
@@ -93,6 +93,7 @@
 				((i32rd[2] & 0xff) <<  8) |
 				((i32rd[3] & 0xff));
 
+
 			byte[] buff = new byte[size];
 			transport.ReadAll(buff, 0, size);
 			readBuffer = new MemoryStream(buff);
@@ -133,5 +134,22 @@
 			// Reserve space for message header to be put right before sending it out
 			writeBuffer.Write ( header_dummy, 0, header_size );
 		}
-	}
+    #region " IDisposable Support "
+    private bool _IsDisposed;
+
+    // IDisposable
+    protected override void Dispose(bool disposing)
+    {
+      if (!_IsDisposed)
+      {
+        if (disposing)
+        {
+          if (readBuffer != null)
+            readBuffer.Dispose();
+        }
+      }
+      _IsDisposed = true;
+    }
+    #endregion
+  }
 }
diff --git a/lib/csharp/src/Transport/THttpClient.cs b/lib/csharp/src/Transport/THttpClient.cs
index 717907c..106f840 100644
--- a/lib/csharp/src/Transport/THttpClient.cs
+++ b/lib/csharp/src/Transport/THttpClient.cs
@@ -27,7 +27,7 @@
 
 namespace Thrift.Transport
 {
-	public class THttpClient : TTransport
+	public class THttpClient : TTransport, IDisposable
 	{
 		private readonly Uri uri;
 		private Stream inputStream;
@@ -142,9 +142,11 @@
 				byte[] data = outputStream.ToArray();
 				connection.ContentLength = data.Length;
 
-				Stream requestStream = connection.GetRequestStream();
-				requestStream.Write(data, 0, data.Length);
-				inputStream = connection.GetResponse().GetResponseStream();
+				using (Stream requestStream = connection.GetRequestStream())
+				{
+					requestStream.Write(data, 0, data.Length);
+					inputStream = connection.GetResponse().GetResponseStream();
+				}
 			}
 			catch (IOException iox)
 			{
@@ -156,7 +158,7 @@
 			}
 		}
 #endif
-        private HttpWebRequest CreateRequest()
+				private HttpWebRequest CreateRequest()
 		{
 			HttpWebRequest connection = (HttpWebRequest)WebRequest.Create(uri);
 
@@ -356,5 +358,24 @@
         }
 
 #endif
-    }
+#region " IDisposable Support "
+		private bool _IsDisposed;
+
+		// IDisposable
+		protected override void Dispose(bool disposing)
+		{
+			if (!_IsDisposed)
+			{
+				if (disposing)
+				{
+					if (inputStream != null)
+						inputStream.Dispose();
+					if (outputStream != null)
+						outputStream.Dispose();
+				}
+			}
+			_IsDisposed = true;
+		}
+#endregion
+	}
 }
diff --git a/lib/csharp/src/Transport/TServerSocket.cs b/lib/csharp/src/Transport/TServerSocket.cs
index fd5c662..1ad3bd8 100644
--- a/lib/csharp/src/Transport/TServerSocket.cs
+++ b/lib/csharp/src/Transport/TServerSocket.cs
@@ -126,22 +126,36 @@
 			{
 				TcpClient result = server.AcceptTcpClient();
 				TSocket result2 = new TSocket(result);
-				result2.Timeout = clientTimeout;
-				if (useBufferedSockets)
-				{
-					TBufferedTransport result3 = new TBufferedTransport(result2);
-					return result3;
-				}
-				else
-				{
-					return result2;
-				}
-			}
-			catch (Exception ex)
-			{
-				throw new TTransportException(ex.ToString());
-			}
-		}
+        try
+        {
+          result2 = new TSocket(result);
+          result2.Timeout = clientTimeout;
+          if (useBufferedSockets)
+          {
+            TBufferedTransport result3 = new TBufferedTransport(result2);
+            return result3;
+          }
+          else
+          {
+            return result2;
+          }
+        }
+        catch (System.Exception)
+        {
+          // If a TSocket was successfully created, then let 
+          // it do proper cleanup of the TcpClient object.
+          if (result2 != null)
+            result2.Dispose();
+          else //  Otherwise, clean it up ourselves.
+            ((IDisposable)result).Dispose();
+          throw;
+        }
+      }
+      catch (Exception ex)
+      {
+        throw new TTransportException(ex.ToString());
+      }
+    }
 
 		public override void Close()
 		{
diff --git a/lib/csharp/src/Transport/TSocket.cs b/lib/csharp/src/Transport/TSocket.cs
index feb5503..c05b6c2 100644
--- a/lib/csharp/src/Transport/TSocket.cs
+++ b/lib/csharp/src/Transport/TSocket.cs
@@ -145,5 +145,24 @@
 				client = null;
 			}
 		}
-	}
+
+    #region " IDisposable Support "
+    private bool _IsDisposed;
+
+    // IDisposable
+    protected override void Dispose(bool disposing)
+    {
+      if (!_IsDisposed)
+      {
+        if (disposing)
+        {
+          if (client != null)
+            ((IDisposable)client).Dispose();
+          base.Dispose(disposing);
+        }
+      }
+      _IsDisposed = true;
+    }
+    #endregion
+  }
 }
diff --git a/lib/csharp/src/Transport/TStreamTransport.cs b/lib/csharp/src/Transport/TStreamTransport.cs
index 60a8412..901b609 100644
--- a/lib/csharp/src/Transport/TStreamTransport.cs
+++ b/lib/csharp/src/Transport/TStreamTransport.cs
@@ -103,5 +103,26 @@
 
 			outputStream.Flush();
 		}
-	}
+
+
+    #region " IDisposable Support "
+    private bool _IsDisposed;
+
+    // IDisposable
+    protected override void Dispose(bool disposing)
+    {
+      if (!_IsDisposed)
+      {
+        if (disposing)
+        {
+          if (InputStream != null)
+            InputStream.Dispose();
+          if (OutputStream != null)
+            OutputStream.Dispose();
+        }
+      }
+      _IsDisposed = true;
+    }
+    #endregion
+  }
 }
diff --git a/lib/csharp/src/Transport/TTransport.cs b/lib/csharp/src/Transport/TTransport.cs
index 3fbc5d6..c03e9c2 100644
--- a/lib/csharp/src/Transport/TTransport.cs
+++ b/lib/csharp/src/Transport/TTransport.cs
@@ -25,7 +25,7 @@
 
 namespace Thrift.Transport
 {
-	public abstract class TTransport
+	public abstract class TTransport : IDisposable
 	{
 		public abstract bool IsOpen
 		{
@@ -82,5 +82,17 @@
         public virtual void EndFlush(IAsyncResult asyncResult)
         {
         }
-    }
+
+		#region " IDisposable Support "
+		// IDisposable
+		protected abstract void Dispose(bool disposing);
+
+		public void Dispose()
+		{
+			// Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
+			Dispose(true);
+			GC.SuppressFinalize(this);
+		}
+		#endregion
+	}
 }