create new Endpoints and Resources for Plugins

This commit is contained in:
Eduard Heimbuch
2019-07-09 17:04:29 +02:00
parent 9b1867862f
commit 64d3153347
7 changed files with 272 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.HalRepresentation;
import de.otto.edison.hal.Links;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
public class PluginDto extends HalRepresentation {
private String name;
private String type;
private String version;
private String author;
private String description;
@Override
protected HalRepresentation add(Links links) {
return super.add(links);
}
}

View File

@@ -0,0 +1,45 @@
package sonia.scm.api.v2.resources;
import com.google.inject.Inject;
import de.otto.edison.hal.Embedded;
import de.otto.edison.hal.HalRepresentation;
import de.otto.edison.hal.Links;
import sonia.scm.plugin.PluginWrapper;
import java.util.Collection;
import java.util.List;
import static de.otto.edison.hal.Embedded.embeddedBuilder;
import static de.otto.edison.hal.Links.linkingTo;
import static java.util.stream.Collectors.toList;
public class PluginDtoCollectionMapper {
private final ResourceLinks resourceLinks;
private final PluginDtoMapper mapper;
@Inject
public PluginDtoCollectionMapper(ResourceLinks resourceLinks, PluginDtoMapper mapper) {
this.resourceLinks = resourceLinks;
this.mapper = mapper;
}
public HalRepresentation map(Collection<PluginWrapper> plugins) {
List<PluginDto> dtos = plugins.stream().map(mapper::map).collect(toList());
return new HalRepresentation(createLinks(), embedDtos(dtos));
}
private Links createLinks() {
String baseUrl = resourceLinks.pluginCollection().self();
Links.Builder linksBuilder = linkingTo()
.with(Links.linkingTo().self(baseUrl).build());
return linksBuilder.build();
}
private Embedded embedDtos(List<PluginDto> dtos) {
return embeddedBuilder()
.with("plugins", dtos)
.build();
}
}

View File

@@ -0,0 +1,62 @@
package sonia.scm.api.v2.resources;
import com.google.common.base.Strings;
import de.otto.edison.hal.Links;
import sonia.scm.plugin.PluginWrapper;
import sonia.scm.util.HttpUtil;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import static de.otto.edison.hal.Links.linkingTo;
public class PluginDtoMapper {
private final ResourceLinks resourceLinks;
private final HttpServletRequest request;
@Inject
public PluginDtoMapper(ResourceLinks resourceLinks, HttpServletRequest request) {
this.resourceLinks = resourceLinks;
this.request = request;
}
public PluginDto map(PluginWrapper plugin) {
PluginDto pluginDto = new PluginDto();
pluginDto.setName(plugin.getPlugin().getInformation().getName());
pluginDto.setType(plugin.getPlugin().getInformation().getCategory() != null ? plugin.getPlugin().getInformation().getCategory() : "Sonstige/Miscellaneous");
pluginDto.setVersion(plugin.getPlugin().getInformation().getVersion());
pluginDto.setAuthor(plugin.getPlugin().getInformation().getAuthor());
pluginDto.setDescription(plugin.getPlugin().getInformation().getDescription());
Links.Builder linksBuilder = linkingTo()
.self(resourceLinks.uiPlugin()
.self(plugin.getId()));
pluginDto.add(linksBuilder.build());
return pluginDto;
}
private Set<String> getScriptResources(PluginWrapper wrapper) {
Set<String> scriptResources = wrapper.getPlugin().getResources().getScriptResources();
if (scriptResources != null) {
return scriptResources.stream()
.map(this::addContextPath)
.collect(Collectors.toSet());
}
return Collections.emptySet();
}
private String addContextPath(String resource) {
String ctxPath = request.getContextPath();
if (Strings.isNullOrEmpty(ctxPath)) {
return resource;
}
return HttpUtil.append(ctxPath, resource);
}
}

View File

@@ -0,0 +1,84 @@
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.PluginLoader;
import sonia.scm.plugin.PluginWrapper;
import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class PluginResource {
private final PluginLoader pluginLoader;
private final PluginDtoCollectionMapper collectionMapper;
private final PluginDtoMapper mapper;
@Inject
public PluginResource(PluginLoader pluginLoader, PluginDtoCollectionMapper collectionMapper, PluginDtoMapper mapper) {
this.pluginLoader = pluginLoader;
this.collectionMapper = collectionMapper;
this.mapper = mapper;
}
/**
* Returns a collection of installed plugins.
*
* @return collection of installed 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 getInstalledPlugins() {
List<PluginWrapper> plugins = pluginLoader.getInstalledPlugins()
.stream()
.collect(Collectors.toList());
return Response.ok(collectionMapper.map(plugins)).build();
}
/**
* Returns the installed plugin with the given id.
*
* @param id id of plugin
*
* @return installed plugin with specified id
*/
@GET
@Path("{id}")
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 404, condition = "not found"),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(PluginDto.class)
@Produces(VndMediaType.PLUGIN)
public Response getInstalledPlugin(@PathParam("id") String id) {
Optional<PluginDto> pluginDto = pluginLoader.getInstalledPlugins()
.stream()
.filter(plugin -> id.equals(plugin.getId()))
.map(mapper::map)
.findFirst();
if (pluginDto.isPresent()) {
return Response.ok(pluginDto.get()).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
}

View File

@@ -0,0 +1,21 @@
package sonia.scm.api.v2.resources;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.ws.rs.Path;
@Path("v2/")
public class PluginRootResource {
private Provider<PluginResource> pluginResourceProvider;
@Inject
public PluginRootResource(Provider<PluginResource> pluginResourceProvider) {
this.pluginResourceProvider = pluginResourceProvider;
}
@Path("plugins")
public PluginResource plugins() {
return pluginResourceProvider.get();
}
}

View File

@@ -651,6 +651,38 @@ class ResourceLinks {
}
}
public PluginLinks plugin() {
return new PluginLinks(scmPathInfoStore.get());
}
static class PluginLinks {
private final LinkBuilder pluginLinkBuilder;
PluginLinks(ScmPathInfo pathInfo) {
pluginLinkBuilder = new LinkBuilder(pathInfo, PluginRootResource.class, PluginResource.class);
}
String self(String id) {
return pluginLinkBuilder.method("plugins").parameters().method("getInstalledPlugin").parameters(id).href();
}
}
public PluginCollectionLinks pluginCollection() {
return new PluginCollectionLinks(scmPathInfoStore.get());
}
static class PluginCollectionLinks {
private final LinkBuilder pluginCollectionLinkBuilder;
PluginCollectionLinks(ScmPathInfo pathInfo) {
pluginCollectionLinkBuilder = new LinkBuilder(pathInfo, UIRootResource.class, UIPluginResource.class);
}
String self() {
return pluginCollectionLinkBuilder.method("plugins").parameters().method("getInstalledPlugins").parameters().href();
}
}
public AuthenticationLinks authentication() {
return new AuthenticationLinks(scmPathInfoStore.get());
}