Large refactor to:
- Introduce 'Channel' & 'Call' interfaces
- Unify the surfaces for the prototype generated stubs
- Lighten dependency on MessageLite outside of generated code (see Marshaller)
- Bridge Channel to Session pending Transport interface rewrite
- Update all tests to new interfaces

-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=68407406
diff --git a/core/src/main/java/com/google/net/stubby/AbstractOperation.java b/core/src/main/java/com/google/net/stubby/AbstractOperation.java
index 01896be..42f44e7 100644
--- a/core/src/main/java/com/google/net/stubby/AbstractOperation.java
+++ b/core/src/main/java/com/google/net/stubby/AbstractOperation.java
@@ -49,6 +49,9 @@
           "Canot move to " + desiredPhase.name() + " from " + phase.name()));
     } else {
       phase = desiredPhase;
+      if (phase == Phase.CLOSED) {
+        status = Status.OK;
+      }
     }
     return this;
   }
@@ -90,8 +93,9 @@
       logger.severefmt(status.getCause(),
           "Attempting to override status of already closed operation from %s to %s",
         this.status.getCode(), status.getCode());
+    } else {
+      this.status = status;
     }
-    this.status = status;
     return this;
   }
 
diff --git a/core/src/main/java/com/google/net/stubby/Status.java b/core/src/main/java/com/google/net/stubby/Status.java
index 7698533..0095725 100644
--- a/core/src/main/java/com/google/net/stubby/Status.java
+++ b/core/src/main/java/com/google/net/stubby/Status.java
@@ -1,6 +1,7 @@
 package com.google.net.stubby;
 
 import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
 import com.google.net.stubby.transport.Transport;
 
 import javax.annotation.Nullable;
@@ -14,6 +15,18 @@
 
   public static final Status OK = new Status(Transport.Code.OK);
 
+  public static Status fromThrowable(Throwable t) {
+    for (Throwable cause : Throwables.getCausalChain(t)) {
+      if (cause instanceof OperationException) {
+        return ((Status.OperationException) cause).getStatus();
+      } else if (cause instanceof  OperationRuntimeException) {
+        return ((Status.OperationRuntimeException) cause).getStatus();
+      }
+    }
+    // Couldn't find a cause with a Status
+    return new Status(Transport.Code.INTERNAL, t);
+  }
+
   private final Transport.Code code;
   private final String description;
   private final Throwable cause;
diff --git a/core/src/main/java/com/google/net/stubby/http/UrlConnectionClientSession.java b/core/src/main/java/com/google/net/stubby/http/UrlConnectionClientSession.java
index 96c5b7d..a268228 100644
--- a/core/src/main/java/com/google/net/stubby/http/UrlConnectionClientSession.java
+++ b/core/src/main/java/com/google/net/stubby/http/UrlConnectionClientSession.java
@@ -72,9 +72,22 @@
     }
 
     @Override
+    public Operation close(Status status) {
+      // TODO(user): This is broken but necessary to get test passing with the introduction
+      // of Channel as now for most calls the close() call is decoupled from the last call to
+      // addPayload. The real fix is to remove 'nextPhase' from the Operation interface and
+      // clean up Framer. For a follow up CL.
+      boolean alreadyClosed = getPhase() == Phase.CLOSED;
+      super.close(status);
+      if (!alreadyClosed) {
+        framer.writeStatus(status, true, this);
+      }
+      return this;
+    }
+
+    @Override
     public void deliverFrame(ByteBuffer frame, boolean endOfMessage) {
       boolean closed = getPhase() == Phase.CLOSED;
-
       try {
         ByteBuffers.asByteSource(frame).copyTo(outputStream);
         if (closed && endOfMessage) {
@@ -87,12 +100,7 @@
         }
       } catch (IOException ioe) {
         close(new Status(Transport.Code.INTERNAL, ioe));
-      } finally {
-        if (closed && endOfMessage) {
-          framer.close();
-        }
       }
     }
   }
 }
-
diff --git a/core/src/main/java/com/google/net/stubby/http2/netty/Http2Operation.java b/core/src/main/java/com/google/net/stubby/http2/netty/Http2Operation.java
index deec966..0b72e49 100644
--- a/core/src/main/java/com/google/net/stubby/http2/netty/Http2Operation.java
+++ b/core/src/main/java/com/google/net/stubby/http2/netty/Http2Operation.java
@@ -43,6 +43,16 @@
   }
 
   @Override
+  public Operation close(Status status) {
+    boolean alreadyClosed = getPhase() == Phase.CLOSED;
+    super.close(status);
+    if (!alreadyClosed) {
+      framer.writeStatus(status, true, this);
+    }
+    return this;
+  }
+
+  @Override
   public void deliverFrame(ByteBuffer frame, boolean endOfMessage) {
     boolean closed = getPhase() == Phase.CLOSED;
     DefaultHttp2DataFrame dataFrame = new DefaultHttp2DataFrame.Builder().setStreamId(getId())
diff --git a/core/src/main/java/com/google/net/stubby/http2/netty/Http2Response.java b/core/src/main/java/com/google/net/stubby/http2/netty/Http2Response.java
index ee8b2fa..5efc50f 100644
--- a/core/src/main/java/com/google/net/stubby/http2/netty/Http2Response.java
+++ b/core/src/main/java/com/google/net/stubby/http2/netty/Http2Response.java
@@ -1,8 +1,6 @@
 package com.google.net.stubby.http2.netty;
 
-import com.google.net.stubby.Operation;
 import com.google.net.stubby.Response;
-import com.google.net.stubby.Status;
 import com.google.net.stubby.transport.Framer;
 
 import io.netty.channel.Channel;
@@ -26,16 +24,6 @@
     };
   }
 
-  @Override
-  public Operation close(Status status) {
-    boolean alreadyClosed = getPhase() == Phase.CLOSED;
-    super.close(status);
-    if (!alreadyClosed) {
-      framer.writeStatus(status, true, this);
-    }
-    return this;
-  }
-
   private Http2Response(int id, Channel channel, Framer framer) {
     super(id, channel, framer);
   }
diff --git a/core/src/main/java/com/google/net/stubby/spdy/netty/SpdyOperation.java b/core/src/main/java/com/google/net/stubby/spdy/netty/SpdyOperation.java
index bcfbd8e..74d9187 100644
--- a/core/src/main/java/com/google/net/stubby/spdy/netty/SpdyOperation.java
+++ b/core/src/main/java/com/google/net/stubby/spdy/netty/SpdyOperation.java
@@ -45,6 +45,16 @@
   }
 
   @Override
+  public Operation close(Status status) {
+    boolean alreadyClosed = getPhase() == Phase.CLOSED;
+    super.close(status);
+    if (!alreadyClosed) {
+      framer.writeStatus(status, true, this);
+    }
+    return this;
+  }
+
+  @Override
   public void deliverFrame(ByteBuffer frame, boolean endOfMessage) {
     boolean closed = getPhase() == Phase.CLOSED;
     DefaultSpdyDataFrame dataFrame = new DefaultSpdyDataFrame(getId(),
diff --git a/core/src/main/java/com/google/net/stubby/spdy/netty/SpdyResponse.java b/core/src/main/java/com/google/net/stubby/spdy/netty/SpdyResponse.java
index 3c9bc3c..e861ccb 100644
--- a/core/src/main/java/com/google/net/stubby/spdy/netty/SpdyResponse.java
+++ b/core/src/main/java/com/google/net/stubby/spdy/netty/SpdyResponse.java
@@ -1,8 +1,6 @@
 package com.google.net.stubby.spdy.netty;
 
-import com.google.net.stubby.Operation;
 import com.google.net.stubby.Response;
-import com.google.net.stubby.Status;
 import com.google.net.stubby.transport.Framer;
 
 import io.netty.channel.Channel;
@@ -29,16 +27,6 @@
     };
   }
 
-  @Override
-  public Operation close(Status status) {
-    boolean alreadyClosed = getPhase() == Phase.CLOSED;
-    super.close(status);
-    if (!alreadyClosed) {
-      framer.writeStatus(status, true, this);
-    }
-    return this;
-  }
-
   public static DefaultSpdySynReplyFrame createSynReply(int id) {
     DefaultSpdySynReplyFrame synReplyFrame = new DefaultSpdySynReplyFrame(id);
     // TODO(user): Need to review status code handling
diff --git a/core/src/main/java/com/google/net/stubby/spdy/okhttp/SpdyOperation.java b/core/src/main/java/com/google/net/stubby/spdy/okhttp/SpdyOperation.java
index f1cbe65..d82934c 100644
--- a/core/src/main/java/com/google/net/stubby/spdy/okhttp/SpdyOperation.java
+++ b/core/src/main/java/com/google/net/stubby/spdy/okhttp/SpdyOperation.java
@@ -44,6 +44,16 @@
   }
 
   @Override
+  public Operation close(Status status) {
+    boolean alreadyClosed = getPhase() == Phase.CLOSED;
+    super.close(status);
+    if (!alreadyClosed) {
+      framer.writeStatus(status, true, this);
+    }
+    return this;
+  }
+
+  @Override
   public void deliverFrame(ByteBuffer frame, boolean endOfMessage) {
     boolean closed = getPhase() == Phase.CLOSED;
     try {
diff --git a/core/src/main/java/com/google/net/stubby/spdy/okhttp/SpdyResponse.java b/core/src/main/java/com/google/net/stubby/spdy/okhttp/SpdyResponse.java
index 3d85ca1..9994c48 100644
--- a/core/src/main/java/com/google/net/stubby/spdy/okhttp/SpdyResponse.java
+++ b/core/src/main/java/com/google/net/stubby/spdy/okhttp/SpdyResponse.java
@@ -1,6 +1,5 @@
 package com.google.net.stubby.spdy.okhttp;
 
-import com.google.net.stubby.Operation;
 import com.google.net.stubby.Response;
 import com.google.net.stubby.Status;
 import com.google.net.stubby.transport.Framer;
@@ -30,16 +29,6 @@
     };
   }
 
-  @Override
-  public Operation close(Status status) {
-    boolean alreadyClosed = getPhase() == Phase.CLOSED;
-    super.close(status);
-    if (!alreadyClosed) {
-      framer.writeStatus(status, true, this);
-    }
-    return this;
-  }
-
   private SpdyResponse(int id, FrameWriter frameWriter, Framer framer) {
     super(id, frameWriter, framer);
     try {