Define API to invoke the REST API from within extensions and plugins

The REST API available over HTTP is planned to be supported for a long
time in the future.  It is very well documented and has fairly clean
resource semantics.  Extension and plugin authors want to use this API
from within the server itself to access resources, shielding them from
any internal changes.

GerritApi is a simple API exposed to plugins as an interface. The
API mirrors the REST API resource tree. Posting a review on a commit
is similar:

  @Inject
  private GerritApi api;
  [...]

  ReviewInput input = new ReviewInput();
  input.message = "Looks good!";
  input.labels = new HashMap<String, Short>();
  input.labels.put("Code-Review", (short) 2);

  api.changes().id(12345).revision("c0ffee....").review(input);

In this commit we provide only the basic skeleton and a single API
call for posting review comments.

An alternative approach is to use reflection to generate a proxy
implementation of the interfaces and bind everything dynamically at
runtime similar to the way RestApiServlet is implemented.  The hand
coded implementation offered here provides some compile-time
assurances the server has each API implemented and the API accepts the
correct input type.

Change-Id: Ic25c69c0660e2796d090a4a37445820726e543d2
This commit is contained in:
Shawn Pearce
2013-08-10 15:48:53 -07:00
parent 4dbf281d67
commit db99f5415f
20 changed files with 483 additions and 87 deletions

View File

@@ -0,0 +1,21 @@
// Copyright (C) 2013 The Android Open Source Project
//
// Licensed 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 com.google.gerrit.extensions.api;
import com.google.gerrit.extensions.api.changes.Changes;
public interface GerritApi {
public Changes changes();
}

View File

@@ -0,0 +1,22 @@
// Copyright (C) 2013 The Android Open Source Project
//
// Licensed 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 com.google.gerrit.extensions.api.changes;
import com.google.gerrit.extensions.restapi.RestApiException;
public interface ChangeApi {
RevisionApi revision(int id) throws RestApiException;
RevisionApi revision(String id) throws RestApiException;
}

View File

@@ -0,0 +1,24 @@
// Copyright (C) 2013 The Android Open Source Project
//
// Licensed 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 com.google.gerrit.extensions.api.changes;
import com.google.gerrit.extensions.restapi.RestApiException;
public interface Changes {
ChangeApi id(int id) throws RestApiException;
ChangeApi id(String triplet) throws RestApiException;
ChangeApi id(String project, String branch, String id)
throws RestApiException;
}

View File

@@ -0,0 +1,88 @@
// Copyright (C) 2013 The Android Open Source Project
//
// Licensed 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 com.google.gerrit.extensions.api.changes;
import com.google.gerrit.extensions.restapi.DefaultInput;
import java.util.List;
import java.util.Map;
/** Input passed to {@code POST /changes/{id}/revisions/{id}/review}. */
public class ReviewInput {
@DefaultInput
public String message;
public Map<String, Short> labels;
public Map<String, List<Comment>> comments;
/**
* If true require all labels to be within the user's permitted ranges based
* on access controls, attempting to use a label not granted to the user
* will fail the entire modify operation early. If false the operation will
* execute anyway, but the proposed labels given by the user will be
* modified to be the "best" value allowed by the access controls, or
* ignored if the label does not exist.
*/
public boolean strictLabels = true;
/**
* How to process draft comments already in the database that were not also
* described in this input request.
*/
public DraftHandling drafts = DraftHandling.DELETE;
/** Who to send email notifications to after review is stored. */
public NotifyHandling notify = NotifyHandling.ALL;
/**
* Account ID, name, email address or username of another user. The review
* will be posted/updated on behalf of this named user instead of the
* caller. Caller must have the labelAs-$NAME permission granted for each
* label that appears in {@link #labels}. This is in addition to the named
* user also needing to have permission to use the labels.
* <p>
* {@link #strictLabels} impacts how labels is processed for the named user,
* not the caller.
*/
public String onBehalfOf;
public static enum DraftHandling {
DELETE, PUBLISH, KEEP;
}
public static enum NotifyHandling {
NONE, OWNER, OWNER_REVIEWERS, ALL;
}
public static enum Side {
PARENT, REVISION;
}
public static class Comment {
public String id;
public Side side;
public int line;
public String inReplyTo;
public String message;
public Range range;
public static class Range {
public int startLine;
public int startCharacter;
public int endLine;
public int endCharacter;
}
}
}

View File

@@ -0,0 +1,21 @@
// Copyright (C) 2013 The Android Open Source Project
//
// Licensed 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 com.google.gerrit.extensions.api.changes;
import com.google.gerrit.extensions.restapi.RestApiException;
public interface RevisionApi {
void review(ReviewInput in) throws RestApiException;
}

View File

@@ -15,7 +15,7 @@
package com.google.gerrit.extensions.restapi;
/** Root exception type for JSON API failures. */
public abstract class RestApiException extends Exception {
public class RestApiException extends Exception {
private static final long serialVersionUID = 1L;
private CacheControl caching = CacheControl.NONE;