Add REST endpoint to get a cache

Change-Id: I09bfa7c052f2b8411b218c77683cda45a0afe844
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
Edwin Kempin 2014-05-23 10:24:41 +02:00
parent 42c9cf61c8
commit 57a4682aa0
7 changed files with 222 additions and 11 deletions

View File

@ -247,6 +247,44 @@ The entries in the map are sorted by cache name.
}
----
[[get-cache]]
=== Get Cache
--
'GET /config/server/caches/link:#cache-name[\{cache-name\}]'
--
Retrieves information about a cache.
The caller must be a member of a group that is granted the
link:access-control.html#capability_viewCaches[View Caches] capability
or the link:access-control.html#capability_administrateServer[
Administrate Server] capability.
As result a link:#cache-info[CacheInfo] entity is returned.
.Request
----
GET /config/server/caches/projects HTTP/1.0
----
.Response
----
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
)]}'
{
"name": "projects",
"entries": {
"mem": 35
},
"average_get": " 8.6ms",
"hit_ratio": {
"mem": 99
}
}
----
[[list-capabilities]]
=== List Capabilities
--
@ -393,6 +431,20 @@ link:#top-menu-entry-info[TopMenuEntryInfo] entities is returned.
----
[[ids]]
== IDs
[[cache-name]]
=== \{cache-name\}
The name of the cache.
If the cache is defined by a plugin the cache name must include the
plugin name: "<plugin-name>-<cache-name>".
Gerrit core caches can optionally be prefixed with "gerrit":
"gerrit-<cache-name>".
[[json-entities]]
== JSON Entities

View File

@ -0,0 +1,74 @@
// Copyright (C) 2014 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.acceptance.rest.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.server.config.ListCaches.CacheInfo;
import org.apache.http.HttpStatus;
import org.junit.Test;
import java.io.IOException;
public class GetCacheIT extends AbstractDaemonTest {
@Test
public void getCache() throws IOException {
RestResponse r = adminSession.get("/config/server/caches/accounts");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
CacheInfo result = newGson().fromJson(r.getReader(), CacheInfo.class);
assertEquals("accounts", result.name);
assertNull(result.type);
assertEquals(1, result.entries.mem.longValue());
assertNotNull(result.averageGet);
assertTrue(result.averageGet.endsWith("s"));
assertNull(result.entries.disk);
assertNull(result.entries.space);
assertTrue(result.hitRatio.mem >= 0);
assertTrue(result.hitRatio.mem <= 100);
assertNull(result.hitRatio.disk);
userSession.get("/config/server/version").consume();
r = adminSession.get("/config/server/caches/accounts");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
result = newGson().fromJson(r.getReader(), CacheInfo.class);
assertEquals(2, result.entries.mem.longValue());
}
@Test
public void getCache_Forbidden() throws IOException {
RestResponse r = userSession.get("/config/server/caches/accounts");
assertEquals(HttpStatus.SC_FORBIDDEN, r.getStatusCode());
}
@Test
public void getCache_NotFound() throws IOException {
RestResponse r = adminSession.get("/config/server/caches/nonExisting");
assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode());
}
@Test
public void getCacheWithGerritPrefix() throws IOException {
RestResponse r = adminSession.get("/config/server/caches/gerrit-accounts");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
}
}

View File

@ -14,10 +14,36 @@
package com.google.gerrit.server.config;
import com.google.common.cache.Cache;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
public class CacheResource extends ConfigResource {
public static final TypeLiteral<RestView<CacheResource>> CACHE_KIND =
new TypeLiteral<RestView<CacheResource>>() {};
private final String name;
private final Provider<Cache<?, ?>> cacheProvider;
public CacheResource(String pluginName, String cacheName, Provider<Cache<?, ?>> cacheProvider) {
this.name = cacheNameOf(pluginName, cacheName);
this.cacheProvider = cacheProvider;
}
public String getName() {
return name;
}
public Cache<?, ?> getCache() {
return cacheProvider.get();
}
public static String cacheNameOf(String plugin, String name) {
if ("gerrit".equals(plugin)) {
return name;
} else {
return plugin + "-" + name;
}
}
}

View File

@ -14,13 +14,17 @@
package com.google.gerrit.server.config;
import com.google.common.cache.Cache;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
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.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@ -32,12 +36,17 @@ public class CachesCollection implements
private final DynamicMap<RestView<CacheResource>> views;
private final Provider<ListCaches> list;
private final Provider<CurrentUser> self;
private final DynamicMap<Cache<?, ?>> cacheMap;
@Inject
CachesCollection(DynamicMap<RestView<CacheResource>> views,
Provider<ListCaches> list) {
Provider<ListCaches> list, Provider<CurrentUser> self,
DynamicMap<Cache<?, ?>> cacheMap) {
this.views = views;
this.list = list;
this.self = self;
this.cacheMap = cacheMap;
}
@Override
@ -47,8 +56,29 @@ public class CachesCollection implements
@Override
public CacheResource parse(ConfigResource parent, IdString id)
throws ResourceNotFoundException {
throw new ResourceNotFoundException(id);
throws AuthException, ResourceNotFoundException {
CurrentUser user = self.get();
if (user instanceof AnonymousUser) {
throw new AuthException("Authentication required");
} else if (!user.isIdentifiedUser()) {
throw new ResourceNotFoundException();
} else if (!user.getCapabilities().canViewCaches()) {
throw new AuthException("not allowed to view caches");
}
String cacheName = id.get();
String pluginName = "gerrit";
int i = cacheName.lastIndexOf('-');
if (i != -1) {
pluginName = cacheName.substring(0, i);
cacheName = cacheName.length() > i + 1 ? cacheName.substring(i + 1) : "";
}
Provider<Cache<?, ?>> cacheProvider = cacheMap.byPlugin(pluginName).get(cacheName);
if (cacheProvider == null) {
throw new ResourceNotFoundException(id);
}
return new CacheResource(pluginName, cacheName, cacheProvider);
}
@Override

View File

@ -0,0 +1,28 @@
// Copyright (C) 2014 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.RestReadView;
import com.google.gerrit.server.config.ListCaches.CacheInfo;
import com.google.inject.Singleton;
@Singleton
public class GetCache implements RestReadView<CacheResource> {
@Override
public CacheInfo apply(CacheResource rsrc) {
return new CacheInfo(rsrc.getName(), rsrc.getCache());
}
}

View File

@ -14,6 +14,8 @@
package com.google.gerrit.server.config;
import static com.google.gerrit.server.config.CacheResource.cacheNameOf;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheStats;
import com.google.gerrit.common.data.GlobalCapability;
@ -47,14 +49,6 @@ public class ListCaches implements RestReadView<ConfigResource> {
return cacheInfos;
}
private static String cacheNameOf(String plugin, String name) {
if ("gerrit".equals(plugin)) {
return name;
} else {
return plugin + "-" + name;
}
}
public enum CacheType {
MEM, DISK;
}
@ -67,6 +61,12 @@ public class ListCaches implements RestReadView<ConfigResource> {
public HitRatioInfo hitRatio;
public CacheInfo(Cache<?,?> cache) {
this(null, cache);
}
public CacheInfo(String name, Cache<?,?> cache) {
this.name = name;
CacheStats stat = cache.stats();
entries = new EntriesInfo();

View File

@ -30,6 +30,7 @@ public class Module extends RestApiModule {
DynamicMap.mapOf(binder(), CONFIG_KIND);
DynamicMap.mapOf(binder(), TOP_MENU_KIND);
child(CONFIG_KIND, "caches").to(CachesCollection.class);
get(CACHE_KIND).to(GetCache.class);
child(CONFIG_KIND, "capabilities").to(CapabilitiesCollection.class);
child(CONFIG_KIND, "top-menus").to(TopMenuCollection.class);
get(CONFIG_KIND, "version").to(GetVersion.class);