THRIFT-4236: Add context support for go server.
Client: Go
Patch: taozle <zhangliyang26@gmail.com>

This closes #1298
diff --git a/Dockerfile b/Dockerfile
index 0d7ad21..2413b91 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -50,7 +50,7 @@
        /thrift \
     && cmake --build . --config Release \
     && make install \
-    && curl -k -sSL "https://storage.googleapis.com/golang/go1.5.2.linux-amd64.tar.gz" -o /tmp/go.tar.gz \
+    && curl -k -sSL "https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz" -o /tmp/go.tar.gz \
     && tar xzf /tmp/go.tar.gz -C /tmp \
     && cp /tmp/go/bin/gofmt /usr/bin/gofmt \
     && apt-get purge -y --auto-remove $buildDeps \
diff --git a/build/docker/centos/Dockerfile b/build/docker/centos/Dockerfile
index 1881343..974823b 100644
--- a/build/docker/centos/Dockerfile
+++ b/build/docker/centos/Dockerfile
@@ -102,7 +102,7 @@
       erlang-tools
 
 # Go Dependencies
-RUN curl -sSL https://storage.googleapis.com/golang/go1.4.3.linux-amd64.tar.gz | tar -C /usr/local/ -xz
+RUN curl -sSL https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz | tar -C /usr/local/ -xz
 ENV PATH /usr/local/go/bin:$PATH
 
 # Haskell Dependencies
diff --git a/build/docker/debian/Dockerfile b/build/docker/debian/Dockerfile
index 7bc74fc..8aa0902 100644
--- a/build/docker/debian/Dockerfile
+++ b/build/docker/debian/Dockerfile
@@ -155,7 +155,7 @@
 RUN pip3 install -U backports.ssl_match_hostname tornado
 
 # Go
-RUN curl -sSL https://storage.googleapis.com/golang/go1.4.3.linux-amd64.tar.gz | tar -C /usr/local/ -xz
+RUN curl -sSL https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz | tar -C /usr/local/ -xz
 ENV PATH /usr/local/go/bin:$PATH
 
 # Haxe
diff --git a/build/docker/ubuntu/Dockerfile b/build/docker/ubuntu/Dockerfile
index a1ff5a1..25089eb 100644
--- a/build/docker/ubuntu/Dockerfile
+++ b/build/docker/ubuntu/Dockerfile
@@ -177,7 +177,7 @@
 RUN pip3 install -U backports.ssl_match_hostname tornado
 
 # Go
-RUN curl -sSL https://storage.googleapis.com/golang/go1.4.3.linux-amd64.tar.gz | tar -C /usr/local/ -xz
+RUN curl -sSL https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz | tar -C /usr/local/ -xz
 ENV PATH /usr/local/go/bin:$PATH
 
 # Haxe
diff --git a/compiler/cpp/src/thrift/generate/t_go_generator.cc b/compiler/cpp/src/thrift/generate/t_go_generator.cc
index 8c8bda7..499d8c1 100644
--- a/compiler/cpp/src/thrift/generate/t_go_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_go_generator.cc
@@ -81,6 +81,7 @@
     gen_package_prefix_ = "";
     package_flag = "";
     read_write_private_ = false;
+    use_context_ = false;
     ignore_initialisms_ = false;
     for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
       if( iter->first.compare("package_prefix") == 0) {
@@ -91,6 +92,8 @@
         package_flag = (iter->second);
       } else if( iter->first.compare("read_write_private") == 0) {
         read_write_private_ = true;
+      } else if( iter->first.compare("use_context") == 0) {
+        use_context_ = true;
       } else if( iter->first.compare("ignore_initialisms") == 0) {
         ignore_initialisms_ =  true;
       } else {
@@ -258,7 +261,8 @@
   std::string function_signature(t_function* tfunction, std::string prefix = "");
   std::string function_signature_if(t_function* tfunction,
                                     std::string prefix = "",
-                                    bool addError = false);
+                                    bool addError = false,
+                                    bool enableContext = false);
   std::string argument_list(t_struct* tstruct);
   std::string type_to_enum(t_type* ttype);
   std::string type_to_go_type(t_type* ttype);
@@ -284,6 +288,7 @@
   std::string gen_package_prefix_;
   std::string gen_thrift_import_;
   bool read_write_private_;
+  bool use_context_;
   bool ignore_initialisms_;
 
   /**
@@ -872,12 +877,17 @@
  */
 string t_go_generator::go_imports_begin(bool consts) {
   string extra;
+
   // If not writing constants, and there are enums, need extra imports.
   if (!consts && get_program()->get_enums().size() > 0) {
-    extra =
+    extra +=
       "\t\"database/sql/driver\"\n"
       "\t\"errors\"\n";
   }
+  if (use_context_) {
+    extra +=
+      "\t\"context\"\n";
+  }
   return string(
       "import (\n"
       "\t\"bytes\"\n"
@@ -894,12 +904,20 @@
  * This will have to do in lieu of more intelligent import statement construction
  */
 string t_go_generator::go_imports_end() {
+  string extra;
+
+  if (use_context_) {
+    extra +=
+      "var _ = context.Background\n";
+  }
+
   return string(
       ")\n\n"
       "// (needed to ensure safety because of naive import list construction.)\n"
       "var _ = thrift.ZERO\n"
       "var _ = fmt.Printf\n"
       "var _ = reflect.DeepEqual\n"
+      + extra +
       "var _ = bytes.Equal\n\n");
 }
 
@@ -1824,7 +1842,7 @@
 
     for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
       generate_go_docstring(f_types_, (*f_iter));
-      f_types_ << indent() << function_signature_if(*f_iter, "", true) << endl;
+      f_types_ << indent() << function_signature_if(*f_iter, "", true, use_context_) << endl;
     }
   }
 
@@ -1938,7 +1956,7 @@
     // Open function
     generate_go_docstring(f_types_, (*f_iter));
     f_types_ << indent() << "func (p *" << serviceName << "Client) "
-               << function_signature_if(*f_iter, "", true) << " {" << endl;
+               << function_signature_if(*f_iter, "", true, false) << " {" << endl;
     indent_up();
     /*
     f_types_ <<
@@ -2586,31 +2604,36 @@
   // Generate the header portion
   string self(tmp("self"));
 
+  string processorFunction("thrift.TProcessorFunction");
+  if (use_context_) {
+    processorFunction = "thrift.TProcessorFunction2";
+  }
+
   if (extends_processor.empty()) {
     f_types_ << indent() << "type " << serviceName << "Processor struct {" << endl;
-    f_types_ << indent() << "  processorMap map[string]thrift.TProcessorFunction" << endl;
+    f_types_ << indent() << "  processorMap map[string]" << processorFunction << endl;
     f_types_ << indent() << "  handler " << serviceName << endl;
     f_types_ << indent() << "}" << endl << endl;
     f_types_ << indent() << "func (p *" << serviceName
-               << "Processor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {"
+               << "Processor) AddToProcessorMap(key string, processor " << processorFunction << ") {"
                << endl;
     f_types_ << indent() << "  p.processorMap[key] = processor" << endl;
     f_types_ << indent() << "}" << endl << endl;
     f_types_ << indent() << "func (p *" << serviceName
                << "Processor) GetProcessorFunction(key string) "
-                  "(processor thrift.TProcessorFunction, ok bool) {" << endl;
+                  "(processor "<< processorFunction << ", ok bool) {" << endl;
     f_types_ << indent() << "  processor, ok = p.processorMap[key]" << endl;
     f_types_ << indent() << "  return processor, ok" << endl;
     f_types_ << indent() << "}" << endl << endl;
     f_types_ << indent() << "func (p *" << serviceName
-               << "Processor) ProcessorMap() map[string]thrift.TProcessorFunction {" << endl;
+               << "Processor) ProcessorMap() map[string]" << processorFunction << "{" << endl;
     f_types_ << indent() << "  return p.processorMap" << endl;
     f_types_ << indent() << "}" << endl << endl;
     f_types_ << indent() << "func New" << serviceName << "Processor(handler " << serviceName
                << ") *" << serviceName << "Processor {" << endl << endl;
     f_types_
         << indent() << "  " << self << " := &" << serviceName
-        << "Processor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)}"
+        << "Processor{handler:handler, processorMap:make(map[string]" << processorFunction << ")}"
         << endl;
 
     for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
@@ -2620,16 +2643,24 @@
                  << "{handler:handler}" << endl;
     }
 
+    string ctxParam("");
+    string ctxVar("");
+    if (use_context_) {
+        ctxParam = "ctx context.Context, ";
+        ctxVar = "ctx, ";
+    }
+
     string x(tmp("x"));
     f_types_ << indent() << "return " << self << endl;
     f_types_ << indent() << "}" << endl << endl;
     f_types_ << indent() << "func (p *" << serviceName
-               << "Processor) Process(iprot, oprot thrift.TProtocol) (success bool, err "
+               << "Processor) Process(" << ctxParam
+               << "iprot, oprot thrift.TProtocol) (success bool, err "
                   "thrift.TException) {" << endl;
     f_types_ << indent() << "  name, _, seqId, err := iprot.ReadMessageBegin()" << endl;
     f_types_ << indent() << "  if err != nil { return false, err }" << endl;
     f_types_ << indent() << "  if processor, ok := p.GetProcessorFunction(name); ok {" << endl;
-    f_types_ << indent() << "    return processor.Process(seqId, iprot, oprot)" << endl;
+    f_types_ << indent() << "    return processor.Process(" << ctxVar << "seqId, iprot, oprot)" << endl;
     f_types_ << indent() << "  }" << endl;
     f_types_ << indent() << "  iprot.Skip(thrift.STRUCT)" << endl;
     f_types_ << indent() << "  iprot.ReadMessageEnd()" << endl;
@@ -2682,6 +2713,13 @@
                          + publicize(tfunction->get_name());
   string argsname = publicize(tfunction->get_name() + "_args", true);
   string resultname = publicize(tfunction->get_name() + "_result", true);
+
+  string ctxParam("");
+  string ctxVar("");
+  if (use_context_) {
+      ctxParam = "ctx context.Context, ";
+      ctxVar = "ctx";
+  }
   // t_struct* xs = tfunction->get_xceptions();
   // const std::vector<t_field*>& xceptions = xs->get_members();
   vector<t_field*>::const_iterator x_iter;
@@ -2689,7 +2727,7 @@
   f_types_ << indent() << "  handler " << publicize(tservice->get_name()) << endl;
   f_types_ << indent() << "}" << endl << endl;
   f_types_ << indent() << "func (p *" << processorName
-             << ") Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err "
+             << ") Process(" << ctxParam << "seqId int32, iprot, oprot thrift.TProtocol) (success bool, err "
                 "thrift.TException) {" << endl;
   indent_up();
   f_types_ << indent() << "args := " << argsname << "{}" << endl;
@@ -2733,9 +2771,13 @@
   f_types_ << "err2 = p.handler." << publicize(tfunction->get_name()) << "(";
   bool first = true;
 
+  f_types_ << ctxVar;
   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
     if (first) {
       first = false;
+      if (use_context_) {
+        f_types_ << ", ";
+      }
     } else {
       f_types_ << ", ";
     }
@@ -3417,11 +3459,15 @@
  * Renders an interface function signature of the form 'type name(args)'
  *
  * @param tfunction Function definition
+ * @param disableContext Client doesn't suppport context for now.
  * @return String of rendered function definition
  */
-string t_go_generator::function_signature_if(t_function* tfunction, string prefix, bool addError) {
+string t_go_generator::function_signature_if(t_function* tfunction, string prefix, bool addError, bool enableContext) {
   // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
   string signature = publicize(prefix + tfunction->get_name()) + "(";
+  if (enableContext) {
+    signature += "ctx context.Context, ";
+  }
   signature += argument_list(tfunction->get_arglist()) + ") (";
   t_type* ret = tfunction->get_returntype();
   t_struct* exceptions = tfunction->get_xceptions();
@@ -3678,7 +3724,7 @@
   // before submitting a patch that enables this feature again. Thank you.
   (void) file_path;
   return false;
-  
+
   /*
   const string command = "gofmt -w " + file_path;
 
@@ -3698,4 +3744,6 @@
                           "    ignore_initialisms\n"
                           "                     Disable automatic spelling correction of initialisms (e.g. \"URL\")\n" \
                           "    read_write_private\n"
-                          "                     Make read/write methods private, default is public Read/Write\n")
+                          "                     Make read/write methods private, default is public Read/Write\n" \
+                          "    use_context\n"
+                          "                     Make service method receive a context as first argument.\n")
diff --git a/configure.ac b/configure.ac
index 0c628da..fcb9c6d 100755
--- a/configure.ac
+++ b/configure.ac
@@ -397,7 +397,7 @@
   AC_PATH_PROG([GO], [go])
   if [[ -x "$GO" ]] ; then
     AS_IF([test -n "$GO"],[
-      ax_go_version="1.4"
+      ax_go_version="1.7"
 
       AC_MSG_CHECKING([for Go version])
       golang_version=`$GO version 2>&1 | $SED -e 's/\(go \)\(version \)\(go\)\(@<:@0-9@:>@.@<:@0-9@:>@.@<:@0-9@:>@\)\(@<:@\*@:>@*\).*/\4/'`
diff --git a/doc/install/README.md b/doc/install/README.md
index e37f4ff..9e42115 100644
--- a/doc/install/README.md
+++ b/doc/install/README.md
@@ -39,5 +39,5 @@
     * Bit::Vector
     * Class::Accessor
 * Haxe 3.1.3
-* Go 1.4
+* Go 1.7
 * Delphi 2010
diff --git a/lib/go/thrift/http_transport.go b/lib/go/thrift/http_transport.go
index e395d20..d5b5b7c 100644
--- a/lib/go/thrift/http_transport.go
+++ b/lib/go/thrift/http_transport.go
@@ -21,6 +21,7 @@
 
 import (
 	"compress/gzip"
+	"context"
 	"io"
 	"net/http"
 	"strings"
@@ -38,6 +39,18 @@
 	})
 }
 
+// NewThriftHandlerFunc2 is same as NewThriftHandlerFunc but requires a Context as its first param.
+func NewThriftHandlerFunc2(ctx context.Context, processor TProcessor2,
+	inPfactory, outPfactory TProtocolFactory) func(w http.ResponseWriter, r *http.Request) {
+
+	return gz(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Add("Content-Type", "application/x-thrift")
+
+		transport := NewStreamTransport(r.Body, w)
+		processor.Process(ctx, inPfactory.GetProtocol(transport), outPfactory.GetProtocol(transport))
+	})
+}
+
 // gz transparently compresses the HTTP response if the client supports it.
 func gz(handler http.HandlerFunc) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
diff --git a/lib/go/thrift/multiplexed_processor.go b/lib/go/thrift/multiplexed_processor.go
new file mode 100644
index 0000000..d205db8
--- /dev/null
+++ b/lib/go/thrift/multiplexed_processor.go
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+	"context"
+	"fmt"
+	"strings"
+)
+
+/*
+TMultiplexedProcessor2 is a TProcessor allowing
+a single TServer to provide multiple services with
+context support in TProcessor.
+
+To do so, you instantiate the processor and then register additional
+processors with it, as shown in the following example:
+
+var processor = thrift.NewTMultiplexedProcessor2()
+
+firstProcessor :=
+processor.RegisterProcessor("FirstService", firstProcessor)
+
+processor.registerProcessor(
+  "Calculator",
+  Calculator.NewCalculatorProcessor(&CalculatorHandler{}),
+)
+
+processor.registerProcessor(
+  "WeatherReport",
+  WeatherReport.NewWeatherReportProcessor(&WeatherReportHandler{}),
+)
+
+serverTransport, err := thrift.NewTServerSocketTimeout(addr, TIMEOUT)
+if err != nil {
+  t.Fatal("Unable to create server socket", err)
+}
+server := thrift.NewTSimpleServer2(processor, serverTransport)
+server.Serve();
+*/
+
+type TMultiplexedProcessor2 struct {
+	serviceProcessorMap map[string]TProcessor2
+	DefaultProcessor    TProcessor2
+}
+
+func NewTMultiplexedProcessor2() *TMultiplexedProcessor2 {
+	return &TMultiplexedProcessor2{
+		serviceProcessorMap: make(map[string]TProcessor2),
+	}
+}
+
+func (t *TMultiplexedProcessor2) RegisterDefault(processor TProcessor2) {
+	t.DefaultProcessor = processor
+}
+
+func (t *TMultiplexedProcessor2) RegisterProcessor(name string, processor TProcessor2) {
+	if t.serviceProcessorMap == nil {
+		t.serviceProcessorMap = make(map[string]TProcessor2)
+	}
+	t.serviceProcessorMap[name] = processor
+}
+
+func (t *TMultiplexedProcessor2) Process(ctx context.Context, in, out TProtocol) (bool, TException) {
+	name, typeId, seqid, err := in.ReadMessageBegin()
+	if err != nil {
+		return false, err
+	}
+	if typeId != CALL && typeId != ONEWAY {
+		return false, fmt.Errorf("Unexpected message type %v", typeId)
+	}
+	//extract the service name
+	v := strings.SplitN(name, MULTIPLEXED_SEPARATOR, 2)
+	if len(v) != 2 {
+		if t.DefaultProcessor != nil {
+			smb := NewStoredMessageProtocol(in, name, typeId, seqid)
+			return t.DefaultProcessor.Process(ctx, smb, out)
+		}
+		return false, fmt.Errorf("Service name not found in message name: %s.  Did you forget to use a TMultiplexProtocol in your client?", name)
+	}
+	actualProcessor, ok := t.serviceProcessorMap[v[0]]
+	if !ok {
+		return false, fmt.Errorf("Service name not found: %s.  Did you forget to call registerProcessor()?", v[0])
+	}
+	smb := NewStoredMessageProtocol(in, v[1], typeId, seqid)
+	return actualProcessor.Process(ctx, smb, out)
+}
diff --git a/lib/go/thrift/multiplexed_protocol.go b/lib/go/thrift/multiplexed_protocol.go
index 3157e0d..6ae7be6 100644
--- a/lib/go/thrift/multiplexed_protocol.go
+++ b/lib/go/thrift/multiplexed_protocol.go
@@ -76,33 +76,11 @@
 }
 
 /*
-TMultiplexedProcessor is a TProcessor allowing
-a single TServer to provide multiple services.
+This is the non-context version for TProcessor.
 
-To do so, you instantiate the processor and then register additional
-processors with it, as shown in the following example:
+See description at file: multiplexed_processor.go
 
-var processor = thrift.NewTMultiplexedProcessor()
-
-firstProcessor :=
-processor.RegisterProcessor("FirstService", firstProcessor)
-
-processor.registerProcessor(
-  "Calculator",
-  Calculator.NewCalculatorProcessor(&CalculatorHandler{}),
-)
-
-processor.registerProcessor(
-  "WeatherReport",
-  WeatherReport.NewWeatherReportProcessor(&WeatherReportHandler{}),
-)
-
-serverTransport, err := thrift.NewTServerSocketTimeout(addr, TIMEOUT)
-if err != nil {
-  t.Fatal("Unable to create server socket", err)
-}
-server := thrift.NewTSimpleServer2(processor, serverTransport)
-server.Serve();
+Deprecated: use TMultiplexedProcessor2 for strong server programming.
 */
 
 type TMultiplexedProcessor struct {
diff --git a/lib/go/thrift/processor.go b/lib/go/thrift/processor.go
index ca0d3fa..7f8f365 100644
--- a/lib/go/thrift/processor.go
+++ b/lib/go/thrift/processor.go
@@ -19,6 +19,8 @@
 
 package thrift
 
+import "context"
+
 // A processor is a generic object which operates upon an input stream and
 // writes to some output stream.
 type TProcessor interface {
@@ -28,3 +30,12 @@
 type TProcessorFunction interface {
 	Process(seqId int32, in, out TProtocol) (bool, TException)
 }
+
+// TProcessor2 is TProcessor with ctx as its first argument.
+type TProcessor2 interface {
+	Process(ctx context.Context, in, out TProtocol) (bool, TException)
+}
+
+type TProcessorFunction2 interface {
+	Process(ctx context.Context, seqId int32, in, out TProtocol) (bool, TException)
+}
diff --git a/lib/go/thrift/processor_factory2.go b/lib/go/thrift/processor_factory2.go
new file mode 100644
index 0000000..bd587ad
--- /dev/null
+++ b/lib/go/thrift/processor_factory2.go
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+// The default processor2 factory just returns a singleton
+// instance.
+// The TProcessorFactory2 is a context version of the orignal.
+type TProcessorFactory2 interface {
+	GetProcessor(trans TTransport) TProcessor2
+}
+
+type tProcessorFactory2 struct {
+	processor TProcessor2
+}
+
+func NewTProcessorFactory2(p TProcessor2) TProcessorFactory2 {
+	return &tProcessorFactory2{processor: p}
+}
+
+func (p *tProcessorFactory2) GetProcessor(trans TTransport) TProcessor2 {
+	return p.processor
+}
+
+/**
+ * The default processor factory2 just returns a singleton
+ * instance.
+ */
+type TProcessorFunctionFactory2 interface {
+	GetProcessorFunction(trans TTransport) TProcessorFunction2
+}
+
+type tProcessorFunctionFactory2 struct {
+	processor TProcessorFunction2
+}
+
+func NewTProcessorFunctionFactory2(p TProcessorFunction2) TProcessorFunctionFactory2 {
+	return &tProcessorFunctionFactory2{processor: p}
+}
+
+func (p *tProcessorFunctionFactory2) GetProcessorFunction(trans TTransport) TProcessorFunction2 {
+	return p.processor
+}
diff --git a/lib/go/thrift/server.go b/lib/go/thrift/server.go
index f813fa3..3e8a656 100644
--- a/lib/go/thrift/server.go
+++ b/lib/go/thrift/server.go
@@ -33,3 +33,19 @@
 	// all servers are required to be cleanly stoppable.
 	Stop() error
 }
+
+// Same as TServer but use TProcessorFactory2 as processor factory.
+type TServer2 interface {
+	ProcessorFactory() TProcessorFactory2
+	ServerTransport() TServerTransport
+	InputTransportFactory() TTransportFactory
+	OutputTransportFactory() TTransportFactory
+	InputProtocolFactory() TProtocolFactory
+	OutputProtocolFactory() TProtocolFactory
+
+	// Starts the server
+	Serve() error
+	// Stops the server. This is optional on a per-implementation basis. Not
+	// all servers are required to be cleanly stoppable.
+	Stop() error
+}
diff --git a/lib/go/thrift/simple_server2.go b/lib/go/thrift/simple_server2.go
new file mode 100644
index 0000000..9e9961f
--- /dev/null
+++ b/lib/go/thrift/simple_server2.go
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+	"context"
+	"log"
+	"runtime/debug"
+	"sync"
+)
+
+/*
+ * This is only a simple sample same as TSimpleServer but add context
+ * usage support.
+ */
+type TSimpleServer2 struct {
+	quit chan struct{}
+
+	processorFactory       TProcessorFactory2
+	serverTransport        TServerTransport
+	inputTransportFactory  TTransportFactory
+	outputTransportFactory TTransportFactory
+	inputProtocolFactory   TProtocolFactory
+	outputProtocolFactory  TProtocolFactory
+	sync.WaitGroup
+}
+
+func NewTSimpleServerWithContext(processor TProcessor2, serverTransport TServerTransport) *TSimpleServer2 {
+	return NewTSimpleServerFactoryWithContext(NewTProcessorFactory2(processor), serverTransport)
+}
+
+func NewTSimpleServerFactoryWithContext(processorFactory TProcessorFactory2, serverTransport TServerTransport) *TSimpleServer2 {
+	return &TSimpleServer2{
+		quit:                   make(chan struct{}, 1),
+		processorFactory:       processorFactory,
+		serverTransport:        serverTransport,
+		inputTransportFactory:  NewTTransportFactory(),
+		outputTransportFactory: NewTTransportFactory(),
+		inputProtocolFactory:   NewTBinaryProtocolFactoryDefault(),
+		outputProtocolFactory:  NewTBinaryProtocolFactoryDefault(),
+	}
+}
+
+func (p *TSimpleServer2) ProcessorFactory() TProcessorFactory2 {
+	return p.processorFactory
+}
+
+func (p *TSimpleServer2) ServerTransport() TServerTransport {
+	return p.serverTransport
+}
+
+func (p *TSimpleServer2) InputTransportFactory() TTransportFactory {
+	return p.inputTransportFactory
+}
+
+func (p *TSimpleServer2) OutputTransportFactory() TTransportFactory {
+	return p.outputTransportFactory
+}
+
+func (p *TSimpleServer2) InputProtocolFactory() TProtocolFactory {
+	return p.inputProtocolFactory
+}
+
+func (p *TSimpleServer2) OutputProtocolFactory() TProtocolFactory {
+	return p.outputProtocolFactory
+}
+
+func (p *TSimpleServer2) Listen() error {
+	return p.serverTransport.Listen()
+}
+
+func (p *TSimpleServer2) AcceptLoop() error {
+	for {
+		client, err := p.serverTransport.Accept()
+		if err != nil {
+			select {
+			case <-p.quit:
+				return nil
+			default:
+			}
+			return err
+		}
+		if client != nil {
+			p.Add(1)
+			go func() {
+				if err := p.processRequests(client); err != nil {
+					log.Println("error processing request:", err)
+				}
+			}()
+		}
+	}
+}
+
+func (p *TSimpleServer2) Serve() error {
+	err := p.Listen()
+	if err != nil {
+		return err
+	}
+	p.AcceptLoop()
+	return nil
+}
+
+var once2 sync.Once
+
+func (p *TSimpleServer2) Stop() error {
+	q := func() {
+		close(p.quit)
+		p.serverTransport.Interrupt()
+		p.Wait()
+	}
+	once2.Do(q)
+	return nil
+}
+
+func (p *TSimpleServer2) processRequests(client TTransport) error {
+	defer p.Done()
+
+	processor := p.processorFactory.GetProcessor(client)
+	inputTransport, err := p.inputTransportFactory.GetTransport(client)
+	if err != nil {
+		return err
+	}
+	outputTransport, err := p.outputTransportFactory.GetTransport(client)
+	if err != nil {
+		return err
+	}
+	inputProtocol := p.inputProtocolFactory.GetProtocol(inputTransport)
+	outputProtocol := p.outputProtocolFactory.GetProtocol(outputTransport)
+	defer func() {
+		if e := recover(); e != nil {
+			log.Printf("panic in processor: %s: %s", e, debug.Stack())
+		}
+	}()
+
+	if inputTransport != nil {
+		defer inputTransport.Close()
+	}
+	if outputTransport != nil {
+		defer outputTransport.Close()
+	}
+	for {
+		select {
+		case <-p.quit:
+			return nil
+		default:
+		}
+
+		ctx := context.Background()
+		ok, err := processor.Process(ctx, inputProtocol, outputProtocol)
+		if err, ok := err.(TTransportException); ok && err.TypeId() == END_OF_FILE {
+			return nil
+		} else if err != nil {
+			return err
+		}
+		if err, ok := err.(TApplicationException); ok && err.TypeId() == UNKNOWN_METHOD {
+			continue
+		}
+		if !ok {
+			break
+		}
+	}
+	return nil
+}