refactor plugin endpoints

This commit is contained in:
Eduard Heimbuch
2019-07-31 10:27:52 +02:00
parent 598a4e6f32
commit a9744d8df1
12 changed files with 210 additions and 107 deletions

View File

@@ -282,16 +282,6 @@ public class PluginInformation
return version;
}
/**
* Method description
*
*
* @return
*/
public Map<String, Object> getLinks() {
return links;
}
/**
* Method description
*
@@ -384,17 +374,6 @@ public class PluginInformation
this.version = version;
}
/**
* Method description
*
*
* @param links
*/
public void setLinks(Map<String, Object> links) {
this.links = links;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@@ -418,7 +397,4 @@ public class PluginInformation
/** Field description */
private String version;
/** Field description */
private Map<String, Object> links;
}

View File

@@ -0,0 +1,106 @@
package sonia.scm.api.v2.resources;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
import sonia.scm.plugin.Plugin;
import sonia.scm.plugin.PluginInformation;
import sonia.scm.plugin.PluginLoader;
import sonia.scm.plugin.PluginManager;
import sonia.scm.plugin.PluginPermissions;
import sonia.scm.plugin.PluginState;
import sonia.scm.plugin.PluginWrapper;
import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
import static sonia.scm.NotFoundException.notFound;
public class AvailablePluginResource {
private final PluginDtoCollectionMapper collectionMapper;
private PluginDtoMapper dtoMapper;
private final PluginManager pluginManager;
@Inject
public AvailablePluginResource(PluginDtoCollectionMapper collectionMapper, PluginDtoMapper dtoMapper, PluginManager pluginManager) {
this.collectionMapper = collectionMapper;
this.dtoMapper = dtoMapper;
this.pluginManager = pluginManager;
}
/**
* Returns a collection of available plugins.
*
* @return collection of available plugins.
*/
@GET
@Path("")
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(CollectionDto.class)
@Produces(VndMediaType.PLUGIN_COLLECTION)
public Response getAvailablePlugins() {
PluginPermissions.read().check();
Collection<PluginInformation> plugins = pluginManager.getAvailable()
.stream()
.filter(plugin -> plugin.getState().equals(PluginState.AVAILABLE))
.collect(Collectors.toList());
return Response.ok(collectionMapper.map(plugins)).build();
}
/**
* Returns available plugin.
*
* @return available plugin.
*/
@GET
@Path("/{name}/{version}")
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(CollectionDto.class)
@Produces(VndMediaType.PLUGIN)
public Response getAvailablePlugin(@PathParam("name") String name, @PathParam("version") String version) {
PluginPermissions.read().check();
Optional<PluginInformation> plugin = pluginManager.getAvailable()
.stream()
.filter(p -> p.getId().equals(name + ":" + version))
.findFirst();
return Response.ok(dtoMapper.map(plugin.get())).build();
}
/**
* Returns 200 when plugin installation is successful triggered.
*
* @return HTTP Status.
*/
@POST
@Path("/{name}/{version}/install")
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(CollectionDto.class)
@Produces(VndMediaType.PLUGIN)
public Response installPlugin(@PathParam("name") String name, @PathParam("version") String version) {
PluginPermissions.manage().check();
pluginManager.install(name + ":" + version);
return Response.ok().build();
}
}

View File

@@ -42,7 +42,8 @@ public class IndexDtoGenerator extends HalAppenderMapper {
link("logout", resourceLinks.authentication().logout())
);
if (PluginPermissions.read().isPermitted()) {
builder.single(link("plugins", resourceLinks.pluginCollection().self()));
builder.single(link("installedPlugins", resourceLinks.installedPluginCollection().self()));
builder.single(link("availablePlugins", resourceLinks.availablePluginCollection().self()));
}
if (UserPermissions.list().isPermitted()) {
builder.single(link("users", resourceLinks.userCollection().self()));

View File

@@ -15,6 +15,7 @@ import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
@@ -28,7 +29,7 @@ import java.util.stream.Collectors;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
import static sonia.scm.NotFoundException.notFound;
public class PluginResource {
public class InstalledPluginResource {
private final PluginLoader pluginLoader;
private final PluginDtoCollectionMapper collectionMapper;
@@ -36,7 +37,7 @@ public class PluginResource {
private final PluginManager pluginManager;
@Inject
public PluginResource(PluginLoader pluginLoader, PluginDtoCollectionMapper collectionMapper, PluginDtoMapper mapper, PluginManager pluginManager) {
public InstalledPluginResource(PluginLoader pluginLoader, PluginDtoCollectionMapper collectionMapper, PluginDtoMapper mapper, PluginManager pluginManager) {
this.pluginLoader = pluginLoader;
this.collectionMapper = collectionMapper;
this.mapper = mapper;
@@ -70,7 +71,7 @@ public class PluginResource {
* @return installed plugin with specified id
*/
@GET
@Path("{id}")
@Path("/{id}")
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 404, condition = "not found"),
@@ -91,27 +92,4 @@ public class PluginResource {
throw notFound(entity(Plugin.class, id));
}
}
/**
* Returns a collection of available plugins.
*
* @return collection of available plugins.
*/
@GET
@Path("/available")
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(CollectionDto.class)
@Produces(VndMediaType.PLUGIN_COLLECTION)
public Response getAvailablePlugins() {
PluginPermissions.read().check();
Collection<PluginInformation> plugins = pluginManager.getAvailable()
.stream()
.filter(plugin -> plugin.getState().equals(PluginState.AVAILABLE))
.collect(Collectors.toList());
return Response.ok(collectionMapper.map(plugins)).build();
}
}

View File

@@ -27,16 +27,24 @@ public class PluginDtoCollectionMapper {
public HalRepresentation map(List<PluginWrapper> plugins) {
List<PluginDto> dtos = plugins.stream().map(mapper::map).collect(toList());
return new HalRepresentation(createLinks(), embedDtos(dtos));
return new HalRepresentation(createInstalledPluginsLinks(), embedDtos(dtos));
}
public HalRepresentation map(Collection<PluginInformation> plugins) {
List<PluginDto> dtos = plugins.stream().map(mapper::map).collect(toList());
return new HalRepresentation(createLinks(), embedDtos(dtos));
return new HalRepresentation(createAvailablePluginsLinks(), embedDtos(dtos));
}
private Links createLinks() {
String baseUrl = resourceLinks.pluginCollection().self();
private Links createInstalledPluginsLinks() {
String baseUrl = resourceLinks.installedPluginCollection().self();
Links.Builder linksBuilder = linkingTo()
.with(Links.linkingTo().self(baseUrl).build());
return linksBuilder.build();
}
private Links createAvailablePluginsLinks() {
String baseUrl = resourceLinks.availablePluginCollection().self();
Links.Builder linksBuilder = linkingTo()
.with(Links.linkingTo().self(baseUrl).build());

View File

@@ -2,11 +2,11 @@ package sonia.scm.api.v2.resources;
import de.otto.edison.hal.Links;
import sonia.scm.plugin.PluginInformation;
import sonia.scm.plugin.PluginState;
import sonia.scm.plugin.PluginWrapper;
import javax.inject.Inject;
import java.util.Map;
import static de.otto.edison.hal.Link.*;
import static de.otto.edison.hal.Links.linkingTo;
public class PluginDtoMapper {
@@ -23,13 +23,18 @@ public class PluginDtoMapper {
}
public PluginDto map(PluginInformation pluginInformation) {
Links.Builder linksBuilder = linkingTo()
.self(resourceLinks.plugin()
.self(pluginInformation.getName()));
Links.Builder linksBuilder;
if (pluginInformation.getState() != null && pluginInformation.getState().equals(PluginState.AVAILABLE)) {
linksBuilder = linkingTo()
.self(resourceLinks.availablePlugin()
.self(pluginInformation.getName(), pluginInformation.getVersion()));
for (Object link : pluginInformation.getLinks().values()) {
System.out.println("Link is = " + link.toString());
linksBuilder.item(((Map<String, Object>) link).values().iterator().next().toString());
linksBuilder.single(link("install", resourceLinks.availablePlugin().install(pluginInformation.getName(), pluginInformation.getVersion())));
}
else {
linksBuilder = linkingTo()
.self(resourceLinks.installedPlugin()
.self(pluginInformation.getName()));
}
PluginDto pluginDto = new PluginDto(linksBuilder.build());

View File

@@ -4,18 +4,23 @@ import javax.inject.Inject;
import javax.inject.Provider;
import javax.ws.rs.Path;
@Path("v2/")
@Path("v2/plugins")
public class PluginRootResource {
private Provider<PluginResource> pluginResourceProvider;
private Provider<InstalledPluginResource> installedPluginResourceProvider;
private Provider<AvailablePluginResource> availablePluginResourceProvider;
@Inject
public PluginRootResource(Provider<PluginResource> pluginResourceProvider) {
this.pluginResourceProvider = pluginResourceProvider;
public PluginRootResource(Provider<InstalledPluginResource> installedPluginResourceProvider, Provider<AvailablePluginResource> availablePluginResourceProvider) {
this.installedPluginResourceProvider = installedPluginResourceProvider;
this.availablePluginResourceProvider = availablePluginResourceProvider;
}
@Path("plugins")
public PluginResource plugins() {
return pluginResourceProvider.get();
@Path("/installed")
public InstalledPluginResource installedPlugins() {
return installedPluginResourceProvider.get();
}
@Path("/available")
public AvailablePluginResource availablePlugins() { return availablePluginResourceProvider.get(); }
}

View File

@@ -651,35 +651,71 @@ class ResourceLinks {
}
}
public PluginLinks plugin() {
return new PluginLinks(scmPathInfoStore.get());
public InstalledPluginLinks installedPlugin() {
return new InstalledPluginLinks(scmPathInfoStore.get());
}
static class PluginLinks {
private final LinkBuilder pluginLinkBuilder;
static class InstalledPluginLinks {
private final LinkBuilder installedPluginLinkBuilder;
PluginLinks(ScmPathInfo pathInfo) {
pluginLinkBuilder = new LinkBuilder(pathInfo, PluginRootResource.class, PluginResource.class);
InstalledPluginLinks(ScmPathInfo pathInfo) {
installedPluginLinkBuilder = new LinkBuilder(pathInfo, PluginRootResource.class, InstalledPluginResource.class);
}
String self(String id) {
return pluginLinkBuilder.method("plugins").parameters().method("getInstalledPlugin").parameters(id).href();
return installedPluginLinkBuilder.method("installedPlugins").parameters().method("getInstalledPlugin").parameters(id).href();
}
}
public PluginCollectionLinks pluginCollection() {
return new PluginCollectionLinks(scmPathInfoStore.get());
public InstalledPluginCollectionLinks installedPluginCollection() {
return new InstalledPluginCollectionLinks(scmPathInfoStore.get());
}
static class PluginCollectionLinks {
private final LinkBuilder pluginCollectionLinkBuilder;
static class InstalledPluginCollectionLinks {
private final LinkBuilder installedPluginCollectionLinkBuilder;
PluginCollectionLinks(ScmPathInfo pathInfo) {
pluginCollectionLinkBuilder = new LinkBuilder(pathInfo, PluginRootResource.class, PluginResource.class);
InstalledPluginCollectionLinks(ScmPathInfo pathInfo) {
installedPluginCollectionLinkBuilder = new LinkBuilder(pathInfo, PluginRootResource.class, InstalledPluginResource.class);
}
String self() {
return pluginCollectionLinkBuilder.method("plugins").parameters().method("getInstalledPlugins").parameters().href();
return installedPluginCollectionLinkBuilder.method("installedPlugins").parameters().method("getInstalledPlugins").parameters().href();
}
}
public AvailablePluginLinks availablePlugin() {
return new AvailablePluginLinks(scmPathInfoStore.get());
}
static class AvailablePluginLinks {
private final LinkBuilder availablePluginLinkBuilder;
AvailablePluginLinks(ScmPathInfo pathInfo) {
availablePluginLinkBuilder = new LinkBuilder(pathInfo, PluginRootResource.class, AvailablePluginResource.class);
}
String self(String name, String version) {
return availablePluginLinkBuilder.method("availablePlugins").parameters().method("getAvailablePlugin").parameters(name, version).href();
}
String install(String name, String version) {
return availablePluginLinkBuilder.method("availablePlugins").parameters().method("installPlugin").parameters(name, version).href();
}
}
public AvailablePluginCollectionLinks availablePluginCollection() {
return new AvailablePluginCollectionLinks(scmPathInfoStore.get());
}
static class AvailablePluginCollectionLinks {
private final LinkBuilder availablePluginCollectionLinkBuilder;
AvailablePluginCollectionLinks(ScmPathInfo pathInfo) {
availablePluginCollectionLinkBuilder = new LinkBuilder(pathInfo, PluginRootResource.class, AvailablePluginResource.class);
}
String self() {
return availablePluginCollectionLinkBuilder.method("availablePlugins").parameters().method("getAvailablePlugins").parameters().href();
}
}

View File

@@ -186,8 +186,6 @@ public class DefaultPluginManager implements PluginManager
PluginCenter center = getPluginCenter();
// pluginHandler.install(id);
for (PluginInformation plugin : center.getPlugins())
{
String pluginId = plugin.getId();
@@ -593,10 +591,10 @@ public class DefaultPluginManager implements PluginManager
*/
private PluginCenter getPluginCenter()
{
PluginCenter center = null; // cache.get(PluginCenter.class.getName());
PluginCenter center = cache.get(PluginCenter.class.getName());
// if (center == null)
// {
if (center == null)
{
synchronized (DefaultPluginManager.class)
{
String pluginUrl = configuration.getPluginUrl();
@@ -636,7 +634,7 @@ public class DefaultPluginManager implements PluginManager
}
}
}
// }
}
return center;
}

View File

@@ -57,7 +57,7 @@ public final class PluginCenterDto implements Serializable {
private Dependency dependencies;
@XmlElement(name = "_links")
private Map<String, Object> links;
private Map<String, Link> links;
}
@XmlAccessorType(XmlAccessType.FIELD)
@@ -77,18 +77,10 @@ public final class PluginCenterDto implements Serializable {
private String name;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "_links")
@Getter
static class Links {
private Link link;
private boolean templated;
}
@XmlAccessorType(XmlAccessType.FIELD)
@Getter
static class Link {
private String url;
private String href;
private boolean templated;
}
}

View File

@@ -24,10 +24,6 @@ public class PluginCenterDtoMapper {
pluginInformation.setCondition(new PluginCondition(condition.getMinVersion(), Collections.singletonList(condition.getOs()), condition.getArch()));
}
if (plugin.getLinks() != null) {
pluginInformation.setLinks(plugin.getLinks());
}
pluginInformationSet.add(pluginInformation);
}
return pluginInformationSet;

View File

@@ -36,8 +36,10 @@ public class ResourceLinksMock {
when(resourceLinks.modifications()).thenReturn(new ResourceLinks.ModificationsLinks(uriInfo));
when(resourceLinks.repositoryType()).thenReturn(new ResourceLinks.RepositoryTypeLinks(uriInfo));
when(resourceLinks.repositoryTypeCollection()).thenReturn(new ResourceLinks.RepositoryTypeCollectionLinks(uriInfo));
when(resourceLinks.pluginCollection()).thenReturn(new ResourceLinks.PluginCollectionLinks(uriInfo));
when(resourceLinks.plugin()).thenReturn(new ResourceLinks.PluginLinks(uriInfo));
when(resourceLinks.installedPluginCollection()).thenReturn(new ResourceLinks.InstalledPluginCollectionLinks(uriInfo));
when(resourceLinks.availablePluginCollection()).thenReturn(new ResourceLinks.AvailablePluginCollectionLinks(uriInfo));
when(resourceLinks.installedPlugin()).thenReturn(new ResourceLinks.InstalledPluginLinks(uriInfo));
when(resourceLinks.availablePlugin()).thenReturn(new ResourceLinks.AvailablePluginLinks(uriInfo));
when(resourceLinks.uiPluginCollection()).thenReturn(new ResourceLinks.UIPluginCollectionLinks(uriInfo));
when(resourceLinks.uiPlugin()).thenReturn(new ResourceLinks.UIPluginLinks(uriInfo));
when(resourceLinks.authentication()).thenReturn(new ResourceLinks.AuthenticationLinks(uriInfo));