From 8a8858407d4832405f6e66710affbe79cdd38268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 15 Jun 2018 08:46:21 +0200 Subject: [PATCH] Use request scoped store to transfer UriInfo --- scm-webapp/pom.xml | 14 +++++++++++ .../sonia/scm/api/rest/UriInfoFilter.java | 24 +++++++++++++++++++ .../v2/resources/GroupCollectionResource.java | 6 +++-- .../resources/GroupCollectionToDtoMapper.java | 17 ++++++------- .../scm/api/v2/resources/MapperModule.java | 7 +++++- .../scm/api/v2/resources/UriInfoStore.java | 19 +++++++++++++++ .../GroupCollectionToDtoMapperTest.java | 18 +++++++------- .../api/v2/resources/GroupV2ResourceTest.java | 6 ++++- 8 files changed, 91 insertions(+), 20 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java create mode 100644 scm-webapp/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 26b0919d7b..226593e298 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -403,6 +403,20 @@ ${org.mapstruct.version} provided + + + + + javax.validation + validation-api + 2.0.1.Final + + + + org.hibernate + hibernate-validator + 6.0.10.Final + diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java b/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java new file mode 100644 index 0000000000..de0f1dd626 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java @@ -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 storeProvider; + + @Inject + public UriInfoFilter(javax.inject.Provider storeProvider) { + this.storeProvider = storeProvider; + } + + @Override + public void filter(ContainerRequestContext requestContext) { + storeProvider.get().set(requestContext.getUriInfo()); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionResource.java index d38de35dcf..930641d4ce 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionResource.java @@ -35,12 +35,14 @@ public class GroupCollectionResource extends AbstractManagerResource 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 diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapper.java index 547d05ce08..c4ff5c1949 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapper.java @@ -9,7 +9,6 @@ import sonia.scm.group.Group; import sonia.scm.group.GroupPermissions; import javax.inject.Inject; -import javax.ws.rs.core.UriInfo; import java.util.EnumSet; import java.util.List; import java.util.stream.Collectors; @@ -24,33 +23,35 @@ import static sonia.scm.api.v2.resources.ResourceLinks.groupCollection; public class GroupCollectionToDtoMapper { private final GroupToGroupDtoMapper groupToDtoMapper; + private final UriInfoStore uriInfoStore; @Inject - public GroupCollectionToDtoMapper(GroupToGroupDtoMapper groupToDtoMapper) { + public GroupCollectionToDtoMapper(GroupToGroupDtoMapper groupToDtoMapper, UriInfoStore uriInfoStore) { this.groupToDtoMapper = groupToDtoMapper; + this.uriInfoStore = uriInfoStore; } - public GroupCollectionDto map(UriInfo uriInfo, int pageNumber, int pageSize, PageResult pageResult) { + public GroupCollectionDto map(int pageNumber, int pageSize, PageResult pageResult) { NumberedPaging paging = zeroBasedNumberedPaging(pageNumber, pageSize, pageResult.hasMore()); - List dtos = pageResult.getEntities().stream().map(user -> groupToDtoMapper.map(user, uriInfo)).collect(Collectors.toList()); + List dtos = pageResult.getEntities().stream().map(user -> groupToDtoMapper.map(user, uriInfoStore.get())).collect(Collectors.toList()); GroupCollectionDto groupCollectionDto = new GroupCollectionDto( - createLinks(uriInfo, paging), + createLinks(paging), embedDtos(dtos) ); groupCollectionDto.setPage(pageNumber); return groupCollectionDto; } - private static Links createLinks(UriInfo uriInfo, NumberedPaging page) { - String baseUrl = groupCollection(uriInfo).self(); + private Links createLinks(NumberedPaging page) { + String baseUrl = groupCollection(uriInfoStore.get()).self(); Links.Builder linksBuilder = linkingTo() .with(page.links( fromTemplate(baseUrl + "{?page,pageSize}"), EnumSet.allOf(PagingRel.class))); if (GroupPermissions.create().isPermitted()) { - linksBuilder.single(link("create", groupCollection(uriInfo).create())); + linksBuilder.single(link("create", groupCollection(uriInfoStore.get()).create())); } return linksBuilder.build(); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java index 3642d3508e..fec2a677b5 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java @@ -1,6 +1,7 @@ package sonia.scm.api.v2.resources; import com.google.inject.AbstractModule; +import com.google.inject.servlet.ServletScopes; import org.mapstruct.factory.Mappers; public class MapperModule extends AbstractModule { @@ -8,8 +9,12 @@ public class MapperModule extends AbstractModule { protected void configure() { bind(UserDtoToUserMapper.class).to(Mappers.getMapper(UserDtoToUserMapper.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(GroupToGroupDtoMapper.class).to(Mappers.getMapper(GroupToGroupDtoMapper.class).getClass()); + bind(GroupCollectionToDtoMapper.class); + + bind(UriInfoStore.class).in(ServletScopes.REQUEST); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java new file mode 100644 index 0000000000..2f61383cfd --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java @@ -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; + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapperTest.java index 6a1c2246b3..d6560de8bb 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapperTest.java @@ -28,16 +28,18 @@ import static org.mockito.Mockito.when; public class GroupCollectionToDtoMapperTest { private final UriInfo uriInfo = mock(UriInfo.class); + private final UriInfoStore uriInfoStore = new UriInfoStore(); private final GroupToGroupDtoMapper groupToDtoMapper = mock(GroupToGroupDtoMapper.class); private final Subject subject = mock(Subject.class); 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; @Before public void init() throws URISyntaxException { +// uriInfoStore.set(uriInfo); URI baseUri = new URI("http://example.com/base/"); expectedBaseUri = baseUri.resolve(GroupV2Resource.GROUPS_PATH_V2 + "/"); when(uriInfo.getBaseUri()).thenReturn(baseUri); @@ -53,28 +55,28 @@ public class GroupCollectionToDtoMapperTest { @Test public void shouldSetPageNumber() { PageResult pageResult = mockPageResult(true, "nobodies"); - GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult); + GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult); assertEquals(1, groupCollectionDto.getPage()); } @Test public void shouldHaveSelfLink() { PageResult 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())); } @Test public void shouldCreateNextPageLink_whenHasMore() { PageResult 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")); } @Test public void shouldNotCreateNextPageLink_whenNoMore() { PageResult 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"))); } @@ -83,7 +85,7 @@ public class GroupCollectionToDtoMapperTest { PageResult pageResult = mockPageResult(false, "nobodies"); 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()); } @@ -93,7 +95,7 @@ public class GroupCollectionToDtoMapperTest { PageResult pageResult = mockPageResult(false, "nobodies"); 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()); } @@ -101,7 +103,7 @@ public class GroupCollectionToDtoMapperTest { @Test public void shouldMapGroups() { PageResult pageResult = mockPageResult(false, "nobodies", "bosses"); - GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 2, pageResult); + GroupCollectionDto groupCollectionDto = mapper.map(1, 2, pageResult); List groups = groupCollectionDto.getEmbedded().getItemsBy("groups"); assertEquals(2, groups.size()); assertEquals("nobodies", ((GroupDto) groups.get(0)).getName()); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupV2ResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupV2ResourceTest.java index 9ce5181f74..219941e655 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupV2ResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupV2ResourceTest.java @@ -45,10 +45,14 @@ public class GroupV2ResourceTest { @Mock private GroupManager groupManager; + private final UriInfoStore uriInfoStore = new UriInfoStore(); @InjectMocks GroupDtoToGroupMapperImpl dtoToGroupMapper; @InjectMocks GroupToGroupDtoMapperImpl groupToDtoMapper; + @InjectMocks + GroupCollectionToDtoMapper groupCollectionToDtoMapper; + ArgumentCaptor groupCaptor = ArgumentCaptor.forClass(Group.class); @@ -63,7 +67,7 @@ public class GroupV2ResourceTest { group.setMembers(Collections.singletonList("user")); 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); GroupV2Resource groupV2Resource = new GroupV2Resource(groupCollectionResource, groupSubResource);