Change API: Add getEdit() method

Change-Id: Ia0dc178072f1b4ace0ff5a94379858057dcddc6d
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
index b0f802d..06f0a75 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -16,6 +16,7 @@
 
 import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.EditInfo;
 import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
 import com.google.gerrit.extensions.restapi.NotImplementedException;
 import com.google.gerrit.extensions.restapi.RestApiException;
@@ -90,6 +91,8 @@
   ChangeInfo get() throws RestApiException;
   /** {@code get} with {@link ListChangesOption} set to none. */
   ChangeInfo info() throws RestApiException;
+  /** Retrieve change edit when exists. */
+  EditInfo getEdit() throws RestApiException;
 
   /**
    * Set hashtags on a change
@@ -232,6 +235,11 @@
     }
 
     @Override
+    public EditInfo getEdit() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
     public void setHashtags(HashtagsInput input) throws RestApiException {
       throw new NotImplementedException();
     }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java
index afe0e82..4345076 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java
@@ -55,6 +55,7 @@
     return obj;
   }
 
+  public abstract boolean isNone();
   public abstract int statusCode();
   public abstract T value();
   public abstract CacheControl caching();
@@ -73,6 +74,11 @@
     }
 
     @Override
+    public boolean isNone() {
+      return false;
+    }
+
+    @Override
     public int statusCode() {
       return statusCode;
     }
@@ -104,6 +110,11 @@
     }
 
     @Override
+    public boolean isNone() {
+      return true;
+    }
+
+    @Override
     public int statusCode() {
       return 204;
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
index bf5265b..161461d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
@@ -26,10 +26,13 @@
 import com.google.gerrit.extensions.api.changes.RevisionApi;
 import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.EditInfo;
 import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
 import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.server.change.Abandon;
+import com.google.gerrit.server.change.ChangeEdits;
 import com.google.gerrit.server.change.ChangeJson;
 import com.google.gerrit.server.change.ChangeResource;
 import com.google.gerrit.server.change.Check;
@@ -42,6 +45,7 @@
 import com.google.gerrit.server.change.Revert;
 import com.google.gerrit.server.change.Revisions;
 import com.google.gerrit.server.change.SuggestReviewers;
+import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -72,6 +76,7 @@
   private final PostHashtags postHashtags;
   private final GetHashtags getHashtags;
   private final Check check;
+  private final ChangeEdits.Detail editDetail;
 
   @Inject
   ChangeApiImpl(Changes changeApi,
@@ -88,6 +93,7 @@
       PostHashtags postHashtags,
       GetHashtags getHashtags,
       Check check,
+      ChangeEdits.Detail editDetail,
       @Assisted ChangeResource change) {
     this.changeApi = changeApi;
     this.revert = revert;
@@ -103,6 +109,7 @@
     this.postHashtags = postHashtags;
     this.getHashtags = getHashtags;
     this.check = check;
+    this.editDetail = editDetail;
     this.change = change;
   }
 
@@ -249,6 +256,16 @@
   }
 
   @Override
+  public EditInfo getEdit() throws RestApiException {
+    try {
+      Response<EditInfo> edit = editDetail.apply(change);
+      return edit.isNone() ? null : edit.value();
+    } catch (IOException | OrmException | InvalidChangeOperationException e) {
+      throw new RestApiException("Cannot retrieve change edit", e);
+    }
+  }
+
+  @Override
   public ChangeInfo info() throws RestApiException {
     return get(EnumSet.noneOf(ListChangesOption.class));
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
index e5f5381..9bd625d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
@@ -244,7 +244,7 @@
 
   // TODO(davido): Turn the boolean options to ChangeEditOption enum,
   // like it's already the case for ListChangesOption/ListGroupsOption
-  static class Detail implements RestReadView<ChangeResource> {
+  public static class Detail implements RestReadView<ChangeResource> {
     private final ChangeEditUtil editUtil;
     private final ChangeEditJson editJson;
     private final FileInfoJson fileInfoJson;