Add top level /config REST API
/config/server/ part is hard coded for now, but we may add more
config specific resource names later.
/config/server/capabilities retrieves the known server wide
capabilities list. The list has to be loaded dynamically from
the server to permit plugins to declare their own capabilities.
Change-Id: I83692bd021925d37659bfbc88b3e3b67b92c18c1
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
new file mode 100644
index 0000000..65e18a7
--- /dev/null
+++ b/Documentation/rest-api-config.txt
@@ -0,0 +1,123 @@
+Gerrit Code Review - /config/ REST API
+======================================
+
+This page describes the config related REST endpoints.
+Please also take note of the general information on the
+link:rest-api.html[REST API].
+
+[[config-endpoints]]
+Config Endpoints
+---------------
+
+[[list-capabilities]]
+List Capabilities
+~~~~~~~~~~~~~~~~~
+[verse]
+'GET /config/server/capabilities'
+
+Lists the capabilities that are available in system. There are two kinds of
+capabilities: core and plugin-owned capabilities.
+
+As result a map is returned that maps the capability names to
+capability descriptions. The entries in the map are sorted
+by capability name.
+
+.Request
+----
+ GET /config/server/capabilities/ HTTP/1.0
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "accessDatabase": {
+ "kind": "gerritcodereview#capability",
+ "id": "accessDatabase",
+ "name": "Access Database"
+ },
+ "administrateServer": {
+ "kind": "gerritcodereview#capability",
+ "id": "administrateServer",
+ "name": "Administrate Server"
+ },
+ "createAccount": {
+ "kind": "gerritcodereview#capability",
+ "id": "createAccount",
+ "name": "Create Account"
+ },
+ "createGroup": {
+ "kind": "gerritcodereview#capability",
+ "id": "createGroup",
+ "name": "Create Group"
+ },
+ "createProject": {
+ "kind": "gerritcodereview#capability",
+ "id": "createProject",
+ "name": "Create Project"
+ },
+ "emailReviewers": {
+ "kind": "gerritcodereview#capability",
+ "id": "emailReviewers",
+ "name": "Email Reviewers"
+ },
+ "flushCaches": {
+ "kind": "gerritcodereview#capability",
+ "id": "flushCaches",
+ "name": "Flush Caches"
+ },
+ "killTask": {
+ "kind": "gerritcodereview#capability",
+ "id": "killTask",
+ "name": "Kill Task"
+ },
+ "priority": {
+ "kind": "gerritcodereview#capability",
+ "id": "priority",
+ "name": "Priority"
+ },
+ "queryLimit": {
+ "kind": "gerritcodereview#capability",
+ "id": "queryLimit",
+ "name": "Query Limit"
+ },
+ "runGC": {
+ "kind": "gerritcodereview#capability",
+ "id": "runGC",
+ "name": "Run Garbage Collection"
+ },
+ "startReplication": {
+ "kind": "gerritcodereview#capability",
+ "id": "startReplication",
+ "name": "Start Replication"
+ },
+ "streamEvents": {
+ "kind": "gerritcodereview#capability",
+ "id": "streamEvents",
+ "name": "Stream Events"
+ },
+ "viewCaches": {
+ "kind": "gerritcodereview#capability",
+ "id": "viewCaches",
+ "name": "View Caches"
+ },
+ "viewConnections": {
+ "kind": "gerritcodereview#capability",
+ "id": "viewConnections",
+ "name": "View Connections"
+ },
+ "viewQueue": {
+ "kind": "gerritcodereview#capability",
+ "id": "viewQueue",
+ "name": "View Queue"
+ }
+ }
+----
+
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/rest-api.txt b/Documentation/rest-api.txt
index ccc8604..c0dde1c 100644
--- a/Documentation/rest-api.txt
+++ b/Documentation/rest-api.txt
@@ -13,6 +13,8 @@
Account related REST endpoints
link:rest-api-changes.html[/changes/]::
Change related REST endpoints
+link:rest-api-config.html[/config/]::
+ Config related REST endpoints
link:rest-api-groups.html[/groups/]::
Group related REST endpoints
link:rest-api-projects.html[/projects/]::
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
index 904c5c7..ee6cc95 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
@@ -17,6 +17,7 @@
import com.google.gerrit.reviewdb.client.Project;
import java.util.List;
+import java.util.Map;
import java.util.Set;
public class ProjectAccess {
@@ -28,6 +29,7 @@
protected boolean isConfigVisible;
protected boolean canUpload;
protected LabelTypes labelTypes;
+ protected Map<String, String> capabilities;
public ProjectAccess() {
}
@@ -112,4 +114,12 @@
public void setLabelTypes(LabelTypes labelTypes) {
this.labelTypes = labelTypes;
}
+
+ public Map<String, String> getCapabilities() {
+ return capabilities;
+ }
+
+ public void setCapabilities(Map<String, String> capabilities) {
+ this.capabilities = capabilities;
+ }
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java
index 344104d..16be43c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java
@@ -93,9 +93,8 @@
public AccessSectionEditor(ProjectAccess access) {
projectAccess = access;
-
- permissionSelector =
- new ValueListBox<String>(PermissionNameRenderer.INSTANCE);
+ permissionSelector = new ValueListBox<String>(
+ new PermissionNameRenderer(access.getCapabilities()));
permissionSelector.addValueChangeHandler(new ValueChangeHandler<String>() {
@Override
public void onValueChange(ValueChangeEvent<String> event) {
@@ -222,7 +221,7 @@
List<String> perms = new ArrayList<String>();
if (AccessSection.GLOBAL_CAPABILITIES.equals(value.getName())) {
- for (String varName : Util.C.capabilityNames().keySet()) {
+ for (String varName : projectAccess.getCapabilities().keySet()) {
addPermission(varName, perms);
}
} else if (RefConfigSection.isValid(value.getName())) {
@@ -282,7 +281,7 @@
@Override
public PermissionEditor create(int index) {
PermissionEditor subEditor =
- new PermissionEditor(projectAccess.getProjectName(), readOnly, value,
+ new PermissionEditor(projectAccess, readOnly, value,
projectAccess.getLabelTypes());
permissionContainer.insert(subEditor, index);
return subEditor;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
index f4c0b55..e505860 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
@@ -125,8 +125,6 @@
String refErrorPrintable();
String errorsMustBeFixed();
- Map<String, String> capabilityNames();
-
String sectionTypeReference();
String sectionTypeSection();
Map<String, String> sectionNames();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
index fe75b83..2f2345d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
@@ -144,43 +144,6 @@
refErrorPrintable = References may contain only printable characters
errorsMustBeFixed = Errors must be fixed before committing changes.
-# Capability Names
-capabilityNames = \
- accessDatabase, \
- administrateServer, \
- createAccount, \
- createGroup, \
- createProject, \
- emailReviewers, \
- flushCaches, \
- killTask, \
- priority, \
- queryLimit, \
- runAs, \
- runGC, \
- startReplication, \
- streamEvents, \
- viewCaches, \
- viewConnections, \
- viewQueue
-accessDatabase = Access Database
-administrateServer = Administrate Server
-createAccount = Create Account
-createGroup = Create Group
-createProject = Create Project
-emailReviewers = Email Reviewers
-flushCaches = Flush Caches
-killTask = Kill Task
-priority = Priority
-queryLimit = Query Limit
-runAs = Run As
-runGC = Run Garbage Collection
-startReplication = Start Replication
-streamEvents = Stream Events
-viewCaches = View Caches
-viewConnections = View Connections
-viewQueue = View Queue
-
# Section Names
sectionTypeReference = Reference:
sectionTypeSection = Section:
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java
index 9848c18..c2487cf 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java
@@ -24,6 +24,7 @@
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.common.data.PermissionRule;
+import com.google.gerrit.common.data.ProjectAccess;
import com.google.gerrit.common.data.RefConfigSection;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.core.client.GWT;
@@ -107,17 +108,19 @@
private PermissionRange.WithDefaults validRange;
private boolean isDeleted;
- public PermissionEditor(Project.NameKey projectName,
+ public PermissionEditor(ProjectAccess projectAccess,
boolean readOnly,
AccessSection section,
LabelTypes labelTypes) {
this.readOnly = readOnly;
this.section = section;
- this.projectName = projectName;
+ this.projectName = projectAccess.getProjectName();
this.labelTypes = labelTypes;
- normalName = new ValueLabel<String>(PermissionNameRenderer.INSTANCE);
- deletedName = new ValueLabel<String>(PermissionNameRenderer.INSTANCE);
+ PermissionNameRenderer nameRenderer =
+ new PermissionNameRenderer(projectAccess.getCapabilities());
+ normalName = new ValueLabel<String>(nameRenderer);
+ deletedName = new ValueLabel<String>(nameRenderer);
initWidget(uiBinder.createAndBindUi(this));
groupToAdd.setProject(projectName);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionNameRenderer.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionNameRenderer.java
index ad3473c..6ee44a2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionNameRenderer.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionNameRenderer.java
@@ -22,33 +22,48 @@
import java.util.Map;
class PermissionNameRenderer implements Renderer<String> {
- static final PermissionNameRenderer INSTANCE = new PermissionNameRenderer();
-
- private static final Map<String, String> all;
+ private static final Map<String, String> permissions;
static {
- all = new HashMap<String, String>();
- for (Map.Entry<String, String> e : Util.C.capabilityNames().entrySet()) {
- all.put(e.getKey(), e.getValue());
- all.put(e.getKey().toLowerCase(), e.getValue());
- }
+ permissions = new HashMap<String, String>();
for (Map.Entry<String, String> e : Util.C.permissionNames().entrySet()) {
- all.put(e.getKey(), e.getValue());
- all.put(e.getKey().toLowerCase(), e.getValue());
+ permissions.put(e.getKey(), e.getValue());
+ permissions.put(e.getKey().toLowerCase(), e.getValue());
}
}
+ private final Map<String, String> fromServer;
+
+ PermissionNameRenderer(Map<String, String> allFromOutside) {
+ fromServer = allFromOutside;
+ }
+
@Override
public String render(String varName) {
if (Permission.isLabel(varName)) {
return Util.M.label(new Permission(varName).getLabel());
}
- String desc = all.get(varName);
- if (desc == null) {
- desc = all.get(varName.toLowerCase());
+ String desc = permissions.get(varName);
+ if (desc != null) {
+ return desc;
}
- return desc != null ? desc : varName;
+
+ desc = fromServer.get(varName);
+ if (desc != null) {
+ return desc;
+ }
+
+ desc = permissions.get(varName.toLowerCase());
+ if (desc != null) {
+ return desc;
+ }
+
+ desc = fromServer.get(varName.toLowerCase());
+ if (desc != null) {
+ return desc;
+ }
+ return varName;
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
index 96824f3..28f5d85 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
@@ -18,7 +18,12 @@
import static com.google.gerrit.common.ProjectAccessUtil.removeEmptyPermissionsAndSections;
import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.config.CapabilityInfo;
+import com.google.gerrit.client.config.ConfigServerApi;
+import com.google.gerrit.client.rpc.CallbackGroup;
import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gerrit.client.rpc.NativeMap;
+import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.data.AccessSection;
@@ -33,6 +38,7 @@
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Label;
@@ -41,8 +47,10 @@
import com.google.gwtexpui.globalkey.client.NpTextArea;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
public class ProjectAccessScreen extends ProjectScreen {
@@ -90,6 +98,8 @@
private ProjectAccess access;
+ private NativeMap<CapabilityInfo> capabilityMap;
+
public ProjectAccessScreen(final Project.NameKey toShow) {
super(toShow);
}
@@ -107,18 +117,36 @@
@Override
protected void onLoad() {
super.onLoad();
+ CallbackGroup cbs = new CallbackGroup();
+ ConfigServerApi.capabilities(
+ cbs.add(new AsyncCallback<NativeMap<CapabilityInfo>>() {
+ @Override
+ public void onSuccess(NativeMap<CapabilityInfo> result) {
+ capabilityMap = result;
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ // Handled by ScreenLoadCallback.onFailure().
+ }
+ }));
Util.PROJECT_SVC.projectAccess(getProjectKey(),
- new ScreenLoadCallback<ProjectAccess>(this) {
+ cbs.addGwtjsonrpc(new ScreenLoadCallback<ProjectAccess>(this) {
@Override
public void preDisplay(ProjectAccess access) {
displayReadOnly(access);
}
- });
+ }));
savedPanel = ACCESS;
}
private void displayReadOnly(ProjectAccess access) {
this.access = access;
+ Map<String, String> allCapabilities = new HashMap<String, String>();
+ for (CapabilityInfo c : Natives.asList(capabilityMap.values())) {
+ allCapabilities.put(c.id(), c.name());
+ }
+ this.access.setCapabilities(allCapabilities);
accessEditor.setEditing(false);
UIObject.setVisible(editTools, !access.getOwnerOf().isEmpty() || access.canUpload());
edit.setEnabled(!access.getOwnerOf().isEmpty() || access.canUpload());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/CapabilityInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/CapabilityInfo.java
new file mode 100644
index 0000000..45abbd6
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/CapabilityInfo.java
@@ -0,0 +1,25 @@
+// 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.client.config;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+public class CapabilityInfo extends JavaScriptObject {
+ public final native String id() /*-{ return this.id; }-*/;
+ public final native String name() /*-{ return this.name; }-*/;
+
+ protected CapabilityInfo() {
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/ConfigServerApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/ConfigServerApi.java
new file mode 100644
index 0000000..b283a0d
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/config/ConfigServerApi.java
@@ -0,0 +1,30 @@
+// 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.client.config;
+
+import com.google.gerrit.client.rpc.NativeMap;
+import com.google.gerrit.client.rpc.RestApi;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+/**
+ * A collection of static methods which work on the Gerrit REST API for server
+ * configuration.
+ */
+public class ConfigServerApi {
+ /** map of the server wide capabilities (core & plugins). */
+ public static void capabilities(AsyncCallback<NativeMap<CapabilityInfo>> cb) {
+ new RestApi("/config/server/capabilities/").get(cb);
+ }
+}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java
index bd25faf..47219ca 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java
@@ -27,6 +27,7 @@
import com.google.gerrit.httpd.rpc.account.AccountsRestApiServlet;
import com.google.gerrit.httpd.rpc.change.ChangesRestApiServlet;
import com.google.gerrit.httpd.rpc.change.DeprecatedChangeQueryServlet;
+import com.google.gerrit.httpd.rpc.config.ConfigRestApiServlet;
import com.google.gerrit.httpd.rpc.group.GroupsRestApiServlet;
import com.google.gerrit.httpd.rpc.project.ProjectsRestApiServlet;
import com.google.gerrit.reviewdb.client.Change;
@@ -102,6 +103,7 @@
serveRegex("^/(?:a/)?tools/(.*)$").with(ToolServlet.class);
serveRegex("^/(?:a/)?accounts/(.*)$").with(AccountsRestApiServlet.class);
serveRegex("^/(?:a/)?changes/(.*)$").with(ChangesRestApiServlet.class);
+ serveRegex("^/(?:a/)?config/(.*)$").with(ConfigRestApiServlet.class);
serveRegex("^/(?:a/)?groups/(.*)?$").with(GroupsRestApiServlet.class);
serveRegex("^/(?:a/)?projects/(.*)?$").with(ProjectsRestApiServlet.class);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/config/ConfigRestApiServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/config/ConfigRestApiServlet.java
new file mode 100644
index 0000000..f951ad3
--- /dev/null
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/config/ConfigRestApiServlet.java
@@ -0,0 +1,32 @@
+// 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.httpd.rpc.config;
+
+import com.google.gerrit.httpd.restapi.RestApiServlet;
+import com.google.gerrit.server.config.ConfigCollection;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+@Singleton
+public class ConfigRestApiServlet extends RestApiServlet {
+ private static final long serialVersionUID = 1L;
+
+ @Inject
+ ConfigRestApiServlet(RestApiServlet.Globals globals,
+ Provider<ConfigCollection> configCollection) {
+ super(globals, configCollection);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilitiesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilitiesCollection.java
new file mode 100644
index 0000000..3a8bcc5
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilitiesCollection.java
@@ -0,0 +1,52 @@
+// 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.server.config;
+
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.restapi.ChildCollection;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestView;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class CapabilitiesCollection implements
+ ChildCollection<ConfigResource, CapabilityResource> {
+ private final DynamicMap<RestView<CapabilityResource>> views;
+ private final Provider<ListCapabilities> list;
+
+ @Inject
+ CapabilitiesCollection(DynamicMap<RestView<CapabilityResource>> views,
+ Provider<ListCapabilities> list) {
+ this.views = views;
+ this.list = list;
+ }
+
+ @Override
+ public RestView<ConfigResource> list() throws ResourceNotFoundException {
+ return list.get();
+ }
+
+ @Override
+ public CapabilityResource parse(ConfigResource parent, IdString id)
+ throws ResourceNotFoundException {
+ throw new ResourceNotFoundException(id);
+ }
+
+ @Override
+ public DynamicMap<RestView<CapabilityResource>> views() {
+ return views;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilityConstants.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilityConstants.java
new file mode 100644
index 0000000..c0a014c
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilityConstants.java
@@ -0,0 +1,42 @@
+// 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.server.config;
+
+import org.eclipse.jgit.nls.NLS;
+import org.eclipse.jgit.nls.TranslationBundle;
+
+public class CapabilityConstants extends TranslationBundle {
+ public static CapabilityConstants get() {
+ return NLS.getBundleFor(CapabilityConstants.class);
+ }
+
+ public String accessDatabase;
+ public String administrateServer;
+ public String createAccount;
+ public String createGroup;
+ public String createProject;
+ public String emailReviewers;
+ public String flushCaches;
+ public String killTask;
+ public String priority;
+ public String queryLimit;
+ public String runAs;
+ public String runGC;
+ public String startReplication;
+ public String streamEvents;
+ public String viewCaches;
+ public String viewConnections;
+ public String viewQueue;
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilityResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilityResource.java
new file mode 100644
index 0000000..7e3c87e
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilityResource.java
@@ -0,0 +1,23 @@
+// 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.server.config;
+
+import com.google.gerrit.extensions.restapi.RestView;
+import com.google.inject.TypeLiteral;
+
+public class CapabilityResource extends ConfigResource {
+ public static final TypeLiteral<RestView<CapabilityResource>> CAPABILITY_KIND =
+ new TypeLiteral<RestView<CapabilityResource>>() {};
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigCollection.java
new file mode 100644
index 0000000..5ed007a
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigCollection.java
@@ -0,0 +1,52 @@
+// 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.server.config;
+
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestCollection;
+import com.google.gerrit.extensions.restapi.RestView;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.inject.Inject;
+
+public class ConfigCollection implements
+ RestCollection<TopLevelResource, ConfigResource> {
+ private final DynamicMap<RestView<ConfigResource>> views;
+
+ @Inject
+ ConfigCollection(DynamicMap<RestView<ConfigResource>> views) {
+ this.views = views;
+ }
+
+ @Override
+ public RestView<TopLevelResource> list() throws ResourceNotFoundException {
+ throw new ResourceNotFoundException();
+ }
+
+ @Override
+ public DynamicMap<RestView<ConfigResource>> views() {
+ return views;
+ }
+
+ @Override
+ public ConfigResource parse(TopLevelResource root, IdString id)
+ throws ResourceNotFoundException {
+ if (id.equals("server")) {
+ return new ConfigResource();
+ }
+ throw new ResourceNotFoundException(id);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigResource.java
new file mode 100644
index 0000000..ec0e0c2
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigResource.java
@@ -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.server.config;
+
+import com.google.gerrit.extensions.restapi.RestResource;
+import com.google.gerrit.extensions.restapi.RestView;
+import com.google.inject.TypeLiteral;
+
+public class ConfigResource implements RestResource {
+ public static final TypeLiteral<RestView<ConfigResource>> CONFIG_KIND =
+ new TypeLiteral<RestView<ConfigResource>>() {};
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 9370a89..160b33f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -240,6 +240,7 @@
install(new AuditModule());
install(new com.google.gerrit.server.account.Module());
install(new com.google.gerrit.server.change.Module());
+ install(new com.google.gerrit.server.config.Module());
install(new com.google.gerrit.server.group.Module());
install(new com.google.gerrit.server.project.Module());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCapabilities.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCapabilities.java
new file mode 100644
index 0000000..d92dfa7
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCapabilities.java
@@ -0,0 +1,54 @@
+// 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.server.config;
+
+import com.google.common.collect.Maps;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.RestReadView;
+
+import java.util.Map;
+
+/** List capabilities visible to the calling user. */
+public class ListCapabilities implements RestReadView<ConfigResource> {
+ @Override
+ public Map<String, CapabilityInfo> apply(ConfigResource resource)
+ throws AuthException, BadRequestException, ResourceConflictException,
+ IllegalArgumentException, SecurityException, IllegalAccessException,
+ NoSuchFieldException {
+ Map<String, CapabilityInfo> output = Maps.newTreeMap();
+ Class<? extends CapabilityConstants> bundleClass =
+ CapabilityConstants.get().getClass();
+ CapabilityConstants c = CapabilityConstants.get();
+ for (String id : GlobalCapability.getAllNames()) {
+ String name = (String) bundleClass.getField(id).get(c);
+ output.put(id, new CapabilityInfo(id, name));
+ }
+ return output;
+ }
+
+ public static class CapabilityInfo {
+ final String kind = "gerritcodereview#capability";
+ public String id;
+ public String name;
+
+ public CapabilityInfo(String id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java
new file mode 100644
index 0000000..81c2de9
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java
@@ -0,0 +1,30 @@
+// 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.server.config;
+
+import static com.google.gerrit.server.config.ConfigResource.CONFIG_KIND;
+import static com.google.gerrit.server.config.CapabilityResource.CAPABILITY_KIND;
+
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.restapi.RestApiModule;
+
+public class Module extends RestApiModule {
+ @Override
+ protected void configure() {
+ DynamicMap.mapOf(binder(), CONFIG_KIND);
+ DynamicMap.mapOf(binder(), CAPABILITY_KIND);
+ child(CONFIG_KIND, "capabilities").to(CapabilitiesCollection.class);
+ }
+}
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/config/CapabilityConstants.properties b/gerrit-server/src/main/resources/com/google/gerrit/server/config/CapabilityConstants.properties
new file mode 100644
index 0000000..d19fd22
--- /dev/null
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/config/CapabilityConstants.properties
@@ -0,0 +1,17 @@
+accessDatabase = Access Database
+administrateServer = Administrate Server
+createAccount = Create Account
+createGroup = Create Group
+createProject = Create Project
+emailReviewers = Email Reviewers
+flushCaches = Flush Caches
+killTask = Kill Task
+priority = Priority
+queryLimit = Query Limit
+runAs = Run As
+runGC = Run Garbage Collection
+startReplication = Start Replication
+streamEvents = Stream Events
+viewCaches = View Caches
+viewConnections = View Connections
+viewQueue = View Queue
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/config/ListCapabilitiesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/config/ListCapabilitiesTest.java
new file mode 100644
index 0000000..f97ca55
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/config/ListCapabilitiesTest.java
@@ -0,0 +1,39 @@
+// 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.server.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.server.config.ListCapabilities.CapabilityInfo;
+
+import org.junit.Test;
+
+import java.util.Map;
+
+public class ListCapabilitiesTest {
+ @Test
+ public void testList() throws Exception {
+ Map<String, CapabilityInfo> m =
+ new ListCapabilities().apply(new ConfigResource());
+ for (String id : GlobalCapability.getAllNames()) {
+ assertTrue("contains " + id, m.containsKey(id));
+ assertEquals(id, m.get(id).id);
+ assertNotNull(id + " has name", m.get(id).name);
+ }
+ }
+}