mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-11 16:05:44 +01:00
Simplify link building
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
package sonia.scm.api.rest.resources;
|
||||
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
class LinkBuilder {
|
||||
private final UriInfo uriInfo;
|
||||
private final Class[] classes;
|
||||
private final List<Call> calls;
|
||||
|
||||
LinkBuilder(UriInfo uriInfo, Class... classes) {
|
||||
this(uriInfo, classes, Collections.emptyList());
|
||||
}
|
||||
|
||||
private LinkBuilder(UriInfo uriInfo, Class[] classes, List<Call> calls) {
|
||||
this.uriInfo = uriInfo;
|
||||
this.classes = classes;
|
||||
this.calls = calls;
|
||||
}
|
||||
|
||||
|
||||
public Parameters method(String method) {
|
||||
if (calls.size() >= classes.length) {
|
||||
throw new IllegalStateException("no more classes for methods");
|
||||
}
|
||||
return new Parameters(method);
|
||||
}
|
||||
|
||||
class Parameters {
|
||||
|
||||
private final String method;
|
||||
|
||||
private Parameters(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public LinkBuilder parameters(String... parameters) {
|
||||
return LinkBuilder.this.add(method, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
private LinkBuilder add(String method, String[] parameters) {
|
||||
List<Call> newCalls = new ArrayList<>(this.calls);
|
||||
newCalls.add(new Call(LinkBuilder.this.classes[calls.size()], method, parameters));
|
||||
return new LinkBuilder(uriInfo, classes, newCalls);
|
||||
}
|
||||
|
||||
public Link create() {
|
||||
if (calls.size() < classes.length) {
|
||||
throw new IllegalStateException("not enough methods for all classes");
|
||||
}
|
||||
|
||||
URI baseUri = uriInfo.getBaseUri();
|
||||
URI relativeUri = createRelativeUri();
|
||||
URI absoluteUri = baseUri.resolve(relativeUri);
|
||||
return new Link(absoluteUri);
|
||||
}
|
||||
|
||||
private URI createRelativeUri() {
|
||||
UriBuilder uriBuilder = userUriBuilder();
|
||||
calls.forEach(call -> uriBuilder.path(call.clazz, call.method));
|
||||
String[] concatenatedParameters = calls
|
||||
.stream()
|
||||
.map(call -> call.parameters)
|
||||
.flatMap(Arrays::stream)
|
||||
.toArray(String[]::new);
|
||||
return uriBuilder.build(concatenatedParameters);
|
||||
}
|
||||
|
||||
private UriBuilder userUriBuilder() {
|
||||
return UriBuilder.fromResource(classes[0]);
|
||||
}
|
||||
|
||||
private static class Call {
|
||||
private final Class clazz;
|
||||
private final String method;
|
||||
private final String[] parameters;
|
||||
|
||||
private Call(Class clazz, String method, String[] parameters) {
|
||||
this.clazz = clazz;
|
||||
this.method = method;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package sonia.scm.api.rest.resources;
|
||||
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.net.URI;
|
||||
import java.util.*;
|
||||
|
||||
class LinkMapBuilder {
|
||||
private final UriInfo uriInfo;
|
||||
private final Class[] classes;
|
||||
private final Map<String, Link> links = new LinkedHashMap<>();
|
||||
|
||||
LinkMapBuilder(UriInfo uriInfo, Class... classes) {
|
||||
this.uriInfo = uriInfo;
|
||||
this.classes = classes;
|
||||
}
|
||||
|
||||
Builder add(String linkName) {
|
||||
return new ConcreteBuilder(linkName);
|
||||
}
|
||||
|
||||
interface Builder {
|
||||
Parameters method(String method);
|
||||
}
|
||||
|
||||
interface Parameters {
|
||||
Builder parameters(String... parameters);
|
||||
}
|
||||
|
||||
private class ConcreteBuilder implements Builder {
|
||||
|
||||
private final String linkName;
|
||||
private final List<Call> calls = new LinkedList<>();
|
||||
|
||||
private int callCount = 0;
|
||||
|
||||
ConcreteBuilder(String linkName) {
|
||||
this.linkName = linkName;
|
||||
}
|
||||
|
||||
public Parameters method(String method) {
|
||||
return new ParametersImpl(method);
|
||||
}
|
||||
|
||||
private class ParametersImpl implements Parameters {
|
||||
|
||||
private final String method;
|
||||
|
||||
ParametersImpl(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public Builder parameters(String... parameters) {
|
||||
return ConcreteBuilder.this.add(method, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
private Builder add(String method, String[] parameters) {
|
||||
this.calls.add(new Call(LinkMapBuilder.this.classes[callCount], method, parameters));
|
||||
++callCount;
|
||||
if (callCount >= classes.length) {
|
||||
links.put(linkName, createLink());
|
||||
return x -> {
|
||||
throw new IllegalStateException("no more classes for methods");
|
||||
};
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private Link createLink() {
|
||||
URI baseUri = uriInfo.getBaseUri();
|
||||
URI relativeUri = createRelativeUri();
|
||||
URI absoluteUri = baseUri.resolve(relativeUri);
|
||||
return new Link(absoluteUri);
|
||||
}
|
||||
|
||||
private URI createRelativeUri() {
|
||||
UriBuilder uriBuilder = userUriBuilder();
|
||||
calls.forEach(call -> uriBuilder.path(call.clazz, call.method));
|
||||
String[] concatenatedParameters = calls
|
||||
.stream()
|
||||
.map(call -> call.parameters)
|
||||
.flatMap(Arrays::stream)
|
||||
.toArray(String[]::new);
|
||||
return uriBuilder.build(concatenatedParameters);
|
||||
}
|
||||
|
||||
private UriBuilder userUriBuilder() {
|
||||
return UriBuilder.fromResource(classes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Link> getLinkMap() {
|
||||
return Collections.unmodifiableMap(links);
|
||||
}
|
||||
|
||||
private static class Call {
|
||||
private final Class clazz;
|
||||
private final String method;
|
||||
private final String[] parameters;
|
||||
|
||||
private Call(Class clazz, String method, String[] parameters) {
|
||||
this.clazz = clazz;
|
||||
this.method = method;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,17 +24,15 @@ public abstract class User2UserDtoMapper {
|
||||
|
||||
@AfterMapping
|
||||
void appendLinks(@MappingTarget UserDto target, @Context UriInfo uriInfo) {
|
||||
LinkMapBuilder userLinkBuilder = new LinkMapBuilder(uriInfo, UserNewResource.class, UserSubResource.class);
|
||||
LinkMapBuilder collectionLinkBuilder = new LinkMapBuilder(uriInfo, UserNewResource.class, UserCollectionResource.class);
|
||||
userLinkBuilder.add("self").method("getUserSubResource").parameters(target.getName()).method("get").parameters();
|
||||
LinkBuilder userLinkBuilder = new LinkBuilder(uriInfo, UserNewResource.class, UserSubResource.class);
|
||||
LinkBuilder collectionLinkBuilder = new LinkBuilder(uriInfo, UserNewResource.class, UserCollectionResource.class);
|
||||
Map<String, Link> links = new HashMap<>();
|
||||
links.put("self", userLinkBuilder.method("getUserSubResource").parameters(target.getName()).method("get").parameters().create());
|
||||
if (SecurityUtils.getSubject().hasRole(Role.ADMIN)) {
|
||||
userLinkBuilder.add("delete").method("getUserSubResource").parameters(target.getName()).method("delete").parameters();
|
||||
userLinkBuilder.add("update").method("getUserSubResource").parameters(target.getName()).method("update").parameters();
|
||||
collectionLinkBuilder.add("create").method("getUserCollectionResource").parameters().method("create").parameters();
|
||||
links.put("delete", userLinkBuilder.method("getUserSubResource").parameters(target.getName()).method("delete").parameters().create());
|
||||
links.put("update", userLinkBuilder.method("getUserSubResource").parameters(target.getName()).method("update").parameters().create());
|
||||
links.put("create", collectionLinkBuilder.method("getUserCollectionResource").parameters().method("create").parameters().create());
|
||||
}
|
||||
Map<String, Link> join = new HashMap<>();
|
||||
join.putAll(userLinkBuilder.getLinkMap());
|
||||
join.putAll(collectionLinkBuilder.getLinkMap());
|
||||
target.setLinks(join);
|
||||
target.setLinks(links);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,9 +73,8 @@ public class UserCollectionResource extends AbstractManagerResource<User, UserEx
|
||||
User user = dtoToUserMapper.userDtoToUser(userDto, "");
|
||||
manager.create(user);
|
||||
|
||||
LinkMapBuilder builder = new LinkMapBuilder(uriInfo, UserNewResource.class, UserSubResource.class);
|
||||
builder.add("self").method("getUserSubResource").parameters(user.getName()).method("get").parameters();
|
||||
return Response.created(builder.getLinkMap().get("self").getHref()).build();
|
||||
LinkBuilder builder = new LinkBuilder(uriInfo, UserNewResource.class, UserSubResource.class);
|
||||
return Response.created(builder.method("getUserSubResource").parameters(user.getName()).method("get").parameters().create().getHref()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,7 +12,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class LinkMapBuilderTest {
|
||||
public class LinkBuilderTest {
|
||||
|
||||
@Path("base")
|
||||
public static class Main {
|
||||
@@ -41,52 +41,60 @@ public class LinkMapBuilderTest {
|
||||
|
||||
@Test
|
||||
public void shouldBuildSimplePath() {
|
||||
LinkMapBuilder builder = new LinkMapBuilder(uriInfo, Main.class);
|
||||
builder
|
||||
.add("link")
|
||||
.method("sub")
|
||||
.parameters("param_x");
|
||||
LinkBuilder builder = new LinkBuilder(uriInfo, Main.class);
|
||||
|
||||
URI actual = builder.getLinkMap().get("link").getHref();
|
||||
URI actual = builder
|
||||
.method("sub")
|
||||
.parameters("param_x")
|
||||
.create()
|
||||
.getHref();
|
||||
assertEquals("http://example.com/base/main/param_x", actual.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBuildPathOverSubResources() {
|
||||
LinkMapBuilder builder = new LinkMapBuilder(uriInfo, Main.class, Sub.class);
|
||||
builder
|
||||
.add("link")
|
||||
LinkBuilder builder = new LinkBuilder(uriInfo, Main.class, Sub.class);
|
||||
|
||||
URI actual = builder
|
||||
.method("sub")
|
||||
.parameters("param_x")
|
||||
.method("x")
|
||||
.parameters("param_y", "param_z");
|
||||
|
||||
URI actual = builder.getLinkMap().get("link").getHref();
|
||||
.parameters("param_y", "param_z")
|
||||
.create()
|
||||
.getHref();
|
||||
assertEquals("http://example.com/base/main/param_x/sub/param_y/param_z", actual.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBuildPathWithoutParameters() {
|
||||
LinkMapBuilder builder = new LinkMapBuilder(uriInfo, NoParam.class);
|
||||
builder
|
||||
.add("link")
|
||||
.method("get")
|
||||
.parameters();
|
||||
LinkBuilder builder = new LinkBuilder(uriInfo, NoParam.class);
|
||||
|
||||
URI actual = builder.getLinkMap().get("link").getHref();
|
||||
URI actual = builder
|
||||
.method("get")
|
||||
.parameters()
|
||||
.create()
|
||||
.getHref();
|
||||
assertEquals("http://example.com/base", actual.toString());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void shouldFailForTooManyMethods() {
|
||||
LinkMapBuilder builder = new LinkMapBuilder(uriInfo, Main.class);
|
||||
LinkBuilder builder = new LinkBuilder(uriInfo, Main.class);
|
||||
builder
|
||||
.add("link")
|
||||
.method("sub")
|
||||
.parameters("param_x")
|
||||
.method("x");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void shouldFailForTooFewMethods() {
|
||||
LinkBuilder builder = new LinkBuilder(uriInfo, Main.class, Sub.class);
|
||||
builder
|
||||
.method("sub")
|
||||
.parameters("param_x")
|
||||
.create();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setBaseUri() throws URISyntaxException {
|
||||
when(uriInfo.getBaseUri()).thenReturn(new URI("http://example.com/"));
|
||||
Reference in New Issue
Block a user