Use request scoped store to transfer UriInfo

This commit is contained in:
René Pfeuffer
2018-06-15 08:46:21 +02:00
parent 06bbeeb636
commit 8a8858407d
8 changed files with 91 additions and 20 deletions

View File

@@ -403,6 +403,20 @@
<version>${org.mapstruct.version}</version> <version>${org.mapstruct.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- Validation -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.10.Final</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@@ -0,0 +1,24 @@
package sonia.scm.api.rest;
import sonia.scm.api.v2.resources.UriInfoStore;
import javax.inject.Inject;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.ext.Provider;
@Provider
public class UriInfoFilter implements ContainerRequestFilter {
private final javax.inject.Provider<UriInfoStore> storeProvider;
@Inject
public UriInfoFilter(javax.inject.Provider<UriInfoStore> storeProvider) {
this.storeProvider = storeProvider;
}
@Override
public void filter(ContainerRequestContext requestContext) {
storeProvider.get().set(requestContext.getUriInfo());
}
}

View File

@@ -35,12 +35,14 @@ public class GroupCollectionResource extends AbstractManagerResource<Group, Grou
public static final int DEFAULT_PAGE_SIZE = 10; public static final int DEFAULT_PAGE_SIZE = 10;
private final GroupDtoToGroupMapper dtoToGroupMapper; private final GroupDtoToGroupMapper dtoToGroupMapper;
private final GroupToGroupDtoMapper groupToDtoMapper; private final GroupToGroupDtoMapper groupToDtoMapper;
private final GroupCollectionToDtoMapper groupCollectionToDtoMapper;
@Inject @Inject
public GroupCollectionResource(GroupManager manager, GroupDtoToGroupMapper dtoToGroupMapper, GroupToGroupDtoMapper groupToDtoMapper) { public GroupCollectionResource(GroupManager manager, GroupDtoToGroupMapper dtoToGroupMapper, GroupToGroupDtoMapper groupToDtoMapper, GroupCollectionToDtoMapper groupCollectionToDtoMapper) {
super(manager); super(manager);
this.dtoToGroupMapper = dtoToGroupMapper; this.dtoToGroupMapper = dtoToGroupMapper;
this.groupToDtoMapper = groupToDtoMapper; this.groupToDtoMapper = groupToDtoMapper;
this.groupCollectionToDtoMapper = groupCollectionToDtoMapper;
} }
/** /**
@@ -92,7 +94,7 @@ public class GroupCollectionResource extends AbstractManagerResource<Group, Grou
@QueryParam("desc") boolean desc) { @QueryParam("desc") boolean desc) {
PageResult<Group> pageResult = fetchPage(sortby, desc, page, pageSize); PageResult<Group> pageResult = fetchPage(sortby, desc, page, pageSize);
return Response.ok(new GroupCollectionToDtoMapper(groupToDtoMapper).map(uriInfo, page, pageSize, pageResult)).build(); return Response.ok(groupCollectionToDtoMapper.map(page, pageSize, pageResult)).build();
} }
@Override @Override

View File

@@ -9,7 +9,6 @@ import sonia.scm.group.Group;
import sonia.scm.group.GroupPermissions; import sonia.scm.group.GroupPermissions;
import javax.inject.Inject; import javax.inject.Inject;
import javax.ws.rs.core.UriInfo;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -24,33 +23,35 @@ import static sonia.scm.api.v2.resources.ResourceLinks.groupCollection;
public class GroupCollectionToDtoMapper { public class GroupCollectionToDtoMapper {
private final GroupToGroupDtoMapper groupToDtoMapper; private final GroupToGroupDtoMapper groupToDtoMapper;
private final UriInfoStore uriInfoStore;
@Inject @Inject
public GroupCollectionToDtoMapper(GroupToGroupDtoMapper groupToDtoMapper) { public GroupCollectionToDtoMapper(GroupToGroupDtoMapper groupToDtoMapper, UriInfoStore uriInfoStore) {
this.groupToDtoMapper = groupToDtoMapper; this.groupToDtoMapper = groupToDtoMapper;
this.uriInfoStore = uriInfoStore;
} }
public GroupCollectionDto map(UriInfo uriInfo, int pageNumber, int pageSize, PageResult<Group> pageResult) { public GroupCollectionDto map(int pageNumber, int pageSize, PageResult<Group> pageResult) {
NumberedPaging paging = zeroBasedNumberedPaging(pageNumber, pageSize, pageResult.hasMore()); NumberedPaging paging = zeroBasedNumberedPaging(pageNumber, pageSize, pageResult.hasMore());
List<GroupDto> dtos = pageResult.getEntities().stream().map(user -> groupToDtoMapper.map(user, uriInfo)).collect(Collectors.toList()); List<GroupDto> dtos = pageResult.getEntities().stream().map(user -> groupToDtoMapper.map(user, uriInfoStore.get())).collect(Collectors.toList());
GroupCollectionDto groupCollectionDto = new GroupCollectionDto( GroupCollectionDto groupCollectionDto = new GroupCollectionDto(
createLinks(uriInfo, paging), createLinks(paging),
embedDtos(dtos) embedDtos(dtos)
); );
groupCollectionDto.setPage(pageNumber); groupCollectionDto.setPage(pageNumber);
return groupCollectionDto; return groupCollectionDto;
} }
private static Links createLinks(UriInfo uriInfo, NumberedPaging page) { private Links createLinks(NumberedPaging page) {
String baseUrl = groupCollection(uriInfo).self(); String baseUrl = groupCollection(uriInfoStore.get()).self();
Links.Builder linksBuilder = linkingTo() Links.Builder linksBuilder = linkingTo()
.with(page.links( .with(page.links(
fromTemplate(baseUrl + "{?page,pageSize}"), fromTemplate(baseUrl + "{?page,pageSize}"),
EnumSet.allOf(PagingRel.class))); EnumSet.allOf(PagingRel.class)));
if (GroupPermissions.create().isPermitted()) { if (GroupPermissions.create().isPermitted()) {
linksBuilder.single(link("create", groupCollection(uriInfo).create())); linksBuilder.single(link("create", groupCollection(uriInfoStore.get()).create()));
} }
return linksBuilder.build(); return linksBuilder.build();
} }

View File

@@ -1,6 +1,7 @@
package sonia.scm.api.v2.resources; package sonia.scm.api.v2.resources;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.servlet.ServletScopes;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
public class MapperModule extends AbstractModule { public class MapperModule extends AbstractModule {
@@ -8,8 +9,12 @@ public class MapperModule extends AbstractModule {
protected void configure() { protected void configure() {
bind(UserDtoToUserMapper.class).to(Mappers.getMapper(UserDtoToUserMapper.class).getClass()); bind(UserDtoToUserMapper.class).to(Mappers.getMapper(UserDtoToUserMapper.class).getClass());
bind(UserToUserDtoMapper.class).to(Mappers.getMapper(UserToUserDtoMapper.class).getClass()); bind(UserToUserDtoMapper.class).to(Mappers.getMapper(UserToUserDtoMapper.class).getClass());
bind(UserCollectionToDtoMapper.class);
bind(GroupToGroupDtoMapper.class).to(Mappers.getMapper(GroupToGroupDtoMapper.class).getClass());
bind(GroupDtoToGroupMapper.class).to(Mappers.getMapper(GroupDtoToGroupMapper.class).getClass()); bind(GroupDtoToGroupMapper.class).to(Mappers.getMapper(GroupDtoToGroupMapper.class).getClass());
bind(GroupToGroupDtoMapper.class).to(Mappers.getMapper(GroupToGroupDtoMapper.class).getClass());
bind(GroupCollectionToDtoMapper.class);
bind(UriInfoStore.class).in(ServletScopes.REQUEST);
} }
} }

View File

@@ -0,0 +1,19 @@
package sonia.scm.api.v2.resources;
import javax.ws.rs.core.UriInfo;
public class UriInfoStore {
private UriInfo uriInfo;
public UriInfo get() {
return uriInfo;
}
public void set(UriInfo uriInfo) {
if (this.uriInfo != null) {
throw new IllegalStateException("UriInfo already set");
}
this.uriInfo = uriInfo;
}
}

View File

@@ -28,16 +28,18 @@ import static org.mockito.Mockito.when;
public class GroupCollectionToDtoMapperTest { public class GroupCollectionToDtoMapperTest {
private final UriInfo uriInfo = mock(UriInfo.class); private final UriInfo uriInfo = mock(UriInfo.class);
private final UriInfoStore uriInfoStore = new UriInfoStore();
private final GroupToGroupDtoMapper groupToDtoMapper = mock(GroupToGroupDtoMapper.class); private final GroupToGroupDtoMapper groupToDtoMapper = mock(GroupToGroupDtoMapper.class);
private final Subject subject = mock(Subject.class); private final Subject subject = mock(Subject.class);
private final ThreadState subjectThreadState = new SubjectThreadState(subject); private final ThreadState subjectThreadState = new SubjectThreadState(subject);
private final GroupCollectionToDtoMapper mapper = new GroupCollectionToDtoMapper(groupToDtoMapper); private final GroupCollectionToDtoMapper mapper = new GroupCollectionToDtoMapper(groupToDtoMapper, uriInfoStore);
private URI expectedBaseUri; private URI expectedBaseUri;
@Before @Before
public void init() throws URISyntaxException { public void init() throws URISyntaxException {
// uriInfoStore.set(uriInfo);
URI baseUri = new URI("http://example.com/base/"); URI baseUri = new URI("http://example.com/base/");
expectedBaseUri = baseUri.resolve(GroupV2Resource.GROUPS_PATH_V2 + "/"); expectedBaseUri = baseUri.resolve(GroupV2Resource.GROUPS_PATH_V2 + "/");
when(uriInfo.getBaseUri()).thenReturn(baseUri); when(uriInfo.getBaseUri()).thenReturn(baseUri);
@@ -53,28 +55,28 @@ public class GroupCollectionToDtoMapperTest {
@Test @Test
public void shouldSetPageNumber() { public void shouldSetPageNumber() {
PageResult<Group> pageResult = mockPageResult(true, "nobodies"); PageResult<Group> pageResult = mockPageResult(true, "nobodies");
GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult); GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertEquals(1, groupCollectionDto.getPage()); assertEquals(1, groupCollectionDto.getPage());
} }
@Test @Test
public void shouldHaveSelfLink() { public void shouldHaveSelfLink() {
PageResult<Group> pageResult = mockPageResult(true, "nobodies"); PageResult<Group> pageResult = mockPageResult(true, "nobodies");
GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult); GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertTrue(groupCollectionDto.getLinks().getLinkBy("self").get().getHref().startsWith(expectedBaseUri.toString())); assertTrue(groupCollectionDto.getLinks().getLinkBy("self").get().getHref().startsWith(expectedBaseUri.toString()));
} }
@Test @Test
public void shouldCreateNextPageLink_whenHasMore() { public void shouldCreateNextPageLink_whenHasMore() {
PageResult<Group> pageResult = mockPageResult(true, "nobodies"); PageResult<Group> pageResult = mockPageResult(true, "nobodies");
GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult); GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertTrue(groupCollectionDto.getLinks().getLinkBy("next").get().getHref().contains("page=2")); assertTrue(groupCollectionDto.getLinks().getLinkBy("next").get().getHref().contains("page=2"));
} }
@Test @Test
public void shouldNotCreateNextPageLink_whenNoMore() { public void shouldNotCreateNextPageLink_whenNoMore() {
PageResult<Group> pageResult = mockPageResult(false, "nobodies"); PageResult<Group> pageResult = mockPageResult(false, "nobodies");
GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult); GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertFalse(groupCollectionDto.getLinks().stream().anyMatch(link -> link.getHref().contains("page=2"))); assertFalse(groupCollectionDto.getLinks().stream().anyMatch(link -> link.getHref().contains("page=2")));
} }
@@ -83,7 +85,7 @@ public class GroupCollectionToDtoMapperTest {
PageResult<Group> pageResult = mockPageResult(false, "nobodies"); PageResult<Group> pageResult = mockPageResult(false, "nobodies");
when(subject.isPermitted("group:create")).thenReturn(true); when(subject.isPermitted("group:create")).thenReturn(true);
GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult); GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertTrue(groupCollectionDto.getLinks().getLinkBy("create").isPresent()); assertTrue(groupCollectionDto.getLinks().getLinkBy("create").isPresent());
} }
@@ -93,7 +95,7 @@ public class GroupCollectionToDtoMapperTest {
PageResult<Group> pageResult = mockPageResult(false, "nobodies"); PageResult<Group> pageResult = mockPageResult(false, "nobodies");
when(subject.isPermitted("group:create")).thenReturn(false); when(subject.isPermitted("group:create")).thenReturn(false);
GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult); GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertFalse(groupCollectionDto.getLinks().getLinkBy("create").isPresent()); assertFalse(groupCollectionDto.getLinks().getLinkBy("create").isPresent());
} }
@@ -101,7 +103,7 @@ public class GroupCollectionToDtoMapperTest {
@Test @Test
public void shouldMapGroups() { public void shouldMapGroups() {
PageResult<Group> pageResult = mockPageResult(false, "nobodies", "bosses"); PageResult<Group> pageResult = mockPageResult(false, "nobodies", "bosses");
GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 2, pageResult); GroupCollectionDto groupCollectionDto = mapper.map(1, 2, pageResult);
List<HalRepresentation> groups = groupCollectionDto.getEmbedded().getItemsBy("groups"); List<HalRepresentation> groups = groupCollectionDto.getEmbedded().getItemsBy("groups");
assertEquals(2, groups.size()); assertEquals(2, groups.size());
assertEquals("nobodies", ((GroupDto) groups.get(0)).getName()); assertEquals("nobodies", ((GroupDto) groups.get(0)).getName());

View File

@@ -45,10 +45,14 @@ public class GroupV2ResourceTest {
@Mock @Mock
private GroupManager groupManager; private GroupManager groupManager;
private final UriInfoStore uriInfoStore = new UriInfoStore();
@InjectMocks @InjectMocks
GroupDtoToGroupMapperImpl dtoToGroupMapper; GroupDtoToGroupMapperImpl dtoToGroupMapper;
@InjectMocks @InjectMocks
GroupToGroupDtoMapperImpl groupToDtoMapper; GroupToGroupDtoMapperImpl groupToDtoMapper;
@InjectMocks
GroupCollectionToDtoMapper groupCollectionToDtoMapper;
ArgumentCaptor<Group> groupCaptor = ArgumentCaptor.forClass(Group.class); ArgumentCaptor<Group> groupCaptor = ArgumentCaptor.forClass(Group.class);
@@ -63,7 +67,7 @@ public class GroupV2ResourceTest {
group.setMembers(Collections.singletonList("user")); group.setMembers(Collections.singletonList("user"));
when(groupManager.get("admin")).thenReturn(group); when(groupManager.get("admin")).thenReturn(group);
GroupCollectionResource groupCollectionResource = new GroupCollectionResource(groupManager, dtoToGroupMapper, groupToDtoMapper); GroupCollectionResource groupCollectionResource = new GroupCollectionResource(groupManager, dtoToGroupMapper, groupToDtoMapper, groupCollectionToDtoMapper);
GroupSubResource groupSubResource = new GroupSubResource(groupManager, groupToDtoMapper); GroupSubResource groupSubResource = new GroupSubResource(groupManager, groupToDtoMapper);
GroupV2Resource groupV2Resource = new GroupV2Resource(groupCollectionResource, groupSubResource); GroupV2Resource groupV2Resource = new GroupV2Resource(groupCollectionResource, groupSubResource);