THRIFT-3397 Implement TProcessorFactory in C# to enable per-client processors
Client: C#
Patch: Jonathan Heard

This closes #663
diff --git a/lib/csharp/src/Server/TServer.cs b/lib/csharp/src/Server/TServer.cs
index a2631a9..cee2ae3 100644
--- a/lib/csharp/src/Server/TServer.cs
+++ b/lib/csharp/src/Server/TServer.cs
@@ -31,7 +31,7 @@
   public abstract class TServer
   {
     //Attributes
-    protected TProcessor processor;
+    protected TProcessorFactory processorFactory;
     protected TServerTransport serverTransport;
     protected TTransportFactory inputTransportFactory;
     protected TTransportFactory outputTransportFactory;
@@ -65,14 +65,25 @@
     //Construction
     public TServer(TProcessor processor,
               TServerTransport serverTransport)
-      : this(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), DefaultLogDelegate)
+      : this(processor, serverTransport, 
+         new TTransportFactory(), 
+         new TTransportFactory(), 
+         new TBinaryProtocol.Factory(), 
+         new TBinaryProtocol.Factory(), 
+         DefaultLogDelegate)
     {
     }
 
     public TServer(TProcessor processor,
             TServerTransport serverTransport,
             LogDelegate logDelegate)
-      : this(processor, serverTransport, new TTransportFactory(), new TTransportFactory(), new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(), DefaultLogDelegate)
+      : this(processor, 
+         serverTransport, 
+         new TTransportFactory(), 
+         new TTransportFactory(), 
+         new TBinaryProtocol.Factory(), 
+         new TBinaryProtocol.Factory(), 
+         logDelegate)
     {
     }
 
@@ -104,6 +115,23 @@
     }
 
     public TServer(TProcessor processor,
+        TServerTransport serverTransport,
+        TTransportFactory inputTransportFactory,
+        TTransportFactory outputTransportFactory,
+        TProtocolFactory inputProtocolFactory,
+        TProtocolFactory outputProtocolFactory,
+        LogDelegate logDelegate)
+    {
+        this.processorFactory = new TSingletonProcessorFactory(processor);
+        this.serverTransport = serverTransport;
+        this.inputTransportFactory = inputTransportFactory;
+        this.outputTransportFactory = outputTransportFactory;
+        this.inputProtocolFactory = inputProtocolFactory;
+        this.outputProtocolFactory = outputProtocolFactory;
+        this.logDelegate = (logDelegate != null) ? logDelegate : DefaultLogDelegate;
+    }
+
+    public TServer(TProcessorFactory processorFactory,
               TServerTransport serverTransport,
               TTransportFactory inputTransportFactory,
               TTransportFactory outputTransportFactory,
@@ -111,13 +139,13 @@
               TProtocolFactory outputProtocolFactory,
               LogDelegate logDelegate)
     {
-      this.processor = processor;
-      this.serverTransport = serverTransport;
-      this.inputTransportFactory = inputTransportFactory;
-      this.outputTransportFactory = outputTransportFactory;
-      this.inputProtocolFactory = inputProtocolFactory;
-      this.outputProtocolFactory = outputProtocolFactory;
-      this.logDelegate = (logDelegate != null) ? logDelegate : DefaultLogDelegate;
+        this.processorFactory = processorFactory;
+        this.serverTransport = serverTransport;
+        this.inputTransportFactory = inputTransportFactory;
+        this.outputTransportFactory = outputTransportFactory;
+        this.inputProtocolFactory = inputProtocolFactory;
+        this.outputProtocolFactory = outputProtocolFactory;
+        this.logDelegate = (logDelegate != null) ? logDelegate : DefaultLogDelegate;
     }
 
     //Abstract Interface
diff --git a/lib/csharp/src/Server/TSimpleServer.cs b/lib/csharp/src/Server/TSimpleServer.cs
index 267b470..c73fecf 100644
--- a/lib/csharp/src/Server/TSimpleServer.cs
+++ b/lib/csharp/src/Server/TSimpleServer.cs
@@ -61,10 +61,24 @@
     }
 
     public TSimpleServer(TProcessor processor,
+        TServerTransport serverTransport,
+        TTransportFactory transportFactory,
+        TProtocolFactory protocolFactory)
+        : base(processor,
+           serverTransport,
+           transportFactory,
+           transportFactory,
+           protocolFactory,
+           protocolFactory,
+           DefaultLogDelegate)
+    {
+    }
+
+    public TSimpleServer(TProcessorFactory processorFactory,
               TServerTransport serverTransport,
               TTransportFactory transportFactory,
               TProtocolFactory protocolFactory)
-      : base(processor,
+      : base(processorFactory,
          serverTransport,
          transportFactory,
          transportFactory,
@@ -92,6 +106,7 @@
 
       while (!stop)
       {
+        TProcessor processor = null;
         TTransport client = null;
         TTransport inputTransport = null;
         TTransport outputTransport = null;
@@ -102,6 +117,7 @@
         {
           using (client = serverTransport.Accept())
           {
+            processor = processorFactory.GetProcessor(client);
             if (client != null)
             {
               using (inputTransport = inputTransportFactory.GetTransport(client))
diff --git a/lib/csharp/src/Server/TThreadPoolServer.cs b/lib/csharp/src/Server/TThreadPoolServer.cs
index 4c201e9..f0c7fe4 100644
--- a/lib/csharp/src/Server/TThreadPoolServer.cs
+++ b/lib/csharp/src/Server/TThreadPoolServer.cs
@@ -38,7 +38,7 @@
     private volatile bool stop = false;
 
     public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport)
-      : this(processor, serverTransport,
+        : this(new TSingletonProcessorFactory(processor), serverTransport,
          new TTransportFactory(), new TTransportFactory(),
          new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
          DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, DefaultLogDelegate)
@@ -46,33 +46,43 @@
     }
 
     public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport, LogDelegate logDelegate)
-      : this(processor, serverTransport,
+        : this(new TSingletonProcessorFactory(processor), serverTransport,
          new TTransportFactory(), new TTransportFactory(),
          new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
          DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, logDelegate)
     {
     }
 
-
     public TThreadPoolServer(TProcessor processor,
+     TServerTransport serverTransport,
+     TTransportFactory transportFactory,
+     TProtocolFactory protocolFactory)
+        : this(new TSingletonProcessorFactory(processor), serverTransport,
+           transportFactory, transportFactory,
+           protocolFactory, protocolFactory,
+           DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, DefaultLogDelegate)
+    {
+    }
+
+    public TThreadPoolServer(TProcessorFactory processorFactory,
                  TServerTransport serverTransport,
                  TTransportFactory transportFactory,
                  TProtocolFactory protocolFactory)
-      : this(processor, serverTransport,
+        : this(processorFactory, serverTransport,
          transportFactory, transportFactory,
          protocolFactory, protocolFactory,
          DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, DefaultLogDelegate)
     {
     }
 
-    public TThreadPoolServer(TProcessor processor,
+    public TThreadPoolServer(TProcessorFactory processorFactory,
                  TServerTransport serverTransport,
                  TTransportFactory inputTransportFactory,
                  TTransportFactory outputTransportFactory,
                  TProtocolFactory inputProtocolFactory,
                  TProtocolFactory outputProtocolFactory,
                  int minThreadPoolThreads, int maxThreadPoolThreads, LogDelegate logDel)
-      : base(processor, serverTransport, inputTransportFactory, outputTransportFactory,
+        : base(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
           inputProtocolFactory, outputProtocolFactory, logDel)
     {
       lock (typeof(TThreadPoolServer))
@@ -149,6 +159,7 @@
     private void Execute(Object threadContext)
     {
       TTransport client = (TTransport)threadContext;
+      TProcessor processor = processorFactory.GetProcessor(client, this);
       TTransport inputTransport = null;
       TTransport outputTransport = null;
       TProtocol inputProtocol = null;
diff --git a/lib/csharp/src/Server/TThreadedServer.cs b/lib/csharp/src/Server/TThreadedServer.cs
index f8ed8e2..fe13dfd 100644
--- a/lib/csharp/src/Server/TThreadedServer.cs
+++ b/lib/csharp/src/Server/TThreadedServer.cs
@@ -45,7 +45,7 @@
     }
 
     public TThreadedServer(TProcessor processor, TServerTransport serverTransport)
-      : this(processor, serverTransport,
+        : this(new TSingletonProcessorFactory(processor), serverTransport,
          new TTransportFactory(), new TTransportFactory(),
          new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
          DEFAULT_MAX_THREADS, DefaultLogDelegate)
@@ -53,7 +53,7 @@
     }
 
     public TThreadedServer(TProcessor processor, TServerTransport serverTransport, LogDelegate logDelegate)
-      : this(processor, serverTransport,
+        : this(new TSingletonProcessorFactory(processor), serverTransport,
          new TTransportFactory(), new TTransportFactory(),
          new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
          DEFAULT_MAX_THREADS, logDelegate)
@@ -65,21 +65,31 @@
                  TServerTransport serverTransport,
                  TTransportFactory transportFactory,
                  TProtocolFactory protocolFactory)
-      : this(processor, serverTransport,
+        : this(new TSingletonProcessorFactory(processor), serverTransport,
          transportFactory, transportFactory,
          protocolFactory, protocolFactory,
          DEFAULT_MAX_THREADS, DefaultLogDelegate)
     {
     }
 
-    public TThreadedServer(TProcessor processor,
+    public TThreadedServer(TProcessorFactory processorFactory,
+           TServerTransport serverTransport,
+           TTransportFactory transportFactory,
+           TProtocolFactory protocolFactory)
+        : this(processorFactory, serverTransport,
+         transportFactory, transportFactory,
+         protocolFactory, protocolFactory,
+         DEFAULT_MAX_THREADS, DefaultLogDelegate)
+    {
+    }
+    public TThreadedServer(TProcessorFactory processorFactory,
                  TServerTransport serverTransport,
                  TTransportFactory inputTransportFactory,
                  TTransportFactory outputTransportFactory,
                  TProtocolFactory inputProtocolFactory,
                  TProtocolFactory outputProtocolFactory,
                  int maxThreads, LogDelegate logDel)
-      : base(processor, serverTransport, inputTransportFactory, outputTransportFactory,
+      : base(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
           inputProtocolFactory, outputProtocolFactory, logDel)
     {
       this.maxThreads = maxThreads;
@@ -183,6 +193,7 @@
     private void ClientWorker(Object context)
     {
       TTransport client = (TTransport)context;
+      TProcessor processor = processorFactory.GetProcessor(client);
       TTransport inputTransport = null;
       TTransport outputTransport = null;
       TProtocol inputProtocol = null;
diff --git a/lib/csharp/src/TControllingHandler.cs b/lib/csharp/src/TControllingHandler.cs
new file mode 100644
index 0000000..7b5203a
--- /dev/null
+++ b/lib/csharp/src/TControllingHandler.cs
@@ -0,0 +1,29 @@
+/*
+ * 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 Thrift.Server;
+
+namespace Thrift
+{
+    public interface TControllingHandler
+    {
+        TServer server { get; set; }
+    }
+}
diff --git a/lib/csharp/src/TProcessorFactory.cs b/lib/csharp/src/TProcessorFactory.cs
new file mode 100644
index 0000000..fdf631b
--- /dev/null
+++ b/lib/csharp/src/TProcessorFactory.cs
@@ -0,0 +1,30 @@
+/*
+ * 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 Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+    public interface TProcessorFactory
+    {
+        TProcessor GetProcessor(TTransport trans, TServer server = null);
+    }
+}
diff --git a/lib/csharp/src/TPrototypeProcessorFactory.cs b/lib/csharp/src/TPrototypeProcessorFactory.cs
new file mode 100644
index 0000000..d15b2d9
--- /dev/null
+++ b/lib/csharp/src/TPrototypeProcessorFactory.cs
@@ -0,0 +1,55 @@
+/*
+ * 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.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+    public class TPrototypeProcessorFactory<P, H> : TProcessorFactory where P : TProcessor
+    {
+        object[] handlerArgs = null;
+        
+        public TPrototypeProcessorFactory() 
+        {
+            handlerArgs = new object[0]; 
+        }
+
+        public TPrototypeProcessorFactory(params object[] handlerArgs)
+        {
+            this.handlerArgs = handlerArgs;
+        }
+
+        public TProcessor GetProcessor(TTransport trans, TServer server = null)
+        {
+            H handler = (H) Activator.CreateInstance(typeof(H), handlerArgs);
+
+            TControllingHandler handlerServerRef = handler as TControllingHandler;
+            if (handlerServerRef != null)
+            {
+                handlerServerRef.server = server;
+            }
+            return Activator.CreateInstance(typeof(P), new object[] { handler }) as TProcessor;
+        }
+    }
+}
diff --git a/lib/csharp/src/TSingletonProcessorFactory.cs b/lib/csharp/src/TSingletonProcessorFactory.cs
new file mode 100644
index 0000000..40dc44c
--- /dev/null
+++ b/lib/csharp/src/TSingletonProcessorFactory.cs
@@ -0,0 +1,43 @@
+/*
+ * 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.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace Thrift
+{
+    public class TSingletonProcessorFactory : TProcessorFactory
+    {
+        private readonly TProcessor processor_;
+
+        public TSingletonProcessorFactory(TProcessor processor)
+        {
+            processor_ = processor;
+        }
+
+        public TProcessor GetProcessor(TTransport trans, TServer server = null)
+        {
+            return processor_;
+        }
+    }
+}
diff --git a/lib/csharp/src/Thrift.csproj b/lib/csharp/src/Thrift.csproj
index 195005a..99c6b46 100644
--- a/lib/csharp/src/Thrift.csproj
+++ b/lib/csharp/src/Thrift.csproj
@@ -79,6 +79,8 @@
   <ItemGroup>
     <Compile Include="Collections\TCollections.cs" />
     <Compile Include="Collections\THashSet.cs" />
+    <Compile Include="TControllingHandler.cs" />
+    <Compile Include="TProcessorFactory.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Protocol\TAbstractBase.cs" />
     <Compile Include="Protocol\TBase.cs" />
@@ -101,6 +103,8 @@
     <Compile Include="Protocol\TSet.cs" />
     <Compile Include="Protocol\TStruct.cs" />
     <Compile Include="Protocol\TType.cs" />
+    <Compile Include="TPrototypeProcessorFactory.cs" />
+    <Compile Include="TSingletonProcessorFactory.cs" />
     <Compile Include="Server\TThreadedServer.cs" />
     <Compile Include="Server\TServer.cs" />
     <Compile Include="Server\TServerEventHandler.cs" />
@@ -147,4 +151,4 @@
   <ProjectExtensions>
     <VisualStudio AllowExistingFolder="true" />
   </ProjectExtensions>
-</Project>
+</Project>
\ No newline at end of file