From b55955f27360defb675870768bfbe688cd0e7adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 3 Sep 2018 15:52:59 +0200 Subject: [PATCH 01/58] Add basic concept for scm protocol --- .../scm/repository/api/RepositoryService.java | 13 ++++ .../sonia/scm/repository/api/ScmProtocol.java | 19 ++++++ .../scm/repository/spi/HttpScmProtocol.java | 15 +++++ .../spi/RepositoryServiceProvider.java | 8 ++- .../repository/api/RepositoryServiceTest.java | 65 +++++++++++++++++++ .../spi/GitRepositoryServiceProvider.java | 14 ++-- .../spi/HgRepositoryServiceProvider.java | 14 ++-- .../spi/SvnRepositoryServiceProvider.java | 14 ++-- 8 files changed, 147 insertions(+), 15 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java create mode 100644 scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java create mode 100644 scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java index 27eed6becd..926caad530 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java @@ -42,6 +42,7 @@ import sonia.scm.repository.spi.RepositoryServiceProvider; import java.io.Closeable; import java.io.IOException; +import java.util.Set; /** * From the {@link RepositoryService} it is possible to access all commands for @@ -358,4 +359,16 @@ public final class RepositoryService implements Closeable { } + public Set getSupportedProtocols() { + return provider.getSupportedProtocols(); + } + + public T getProtocol(Class clazz) { + for (ScmProtocol scmProtocol : getSupportedProtocols()) { + if (clazz.isAssignableFrom(scmProtocol.getClass())) { + return (T) scmProtocol; + } + } + throw new IllegalArgumentException("no implementation for " + clazz.getName() + " and repository type " + getRepository().getType()); + } } diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java new file mode 100644 index 0000000000..c987510491 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java @@ -0,0 +1,19 @@ +package sonia.scm.repository.api; + +/** + * An ScmProtocol represents a concrete protocol provided by the SCM-Manager instance + * to interact with a repository depending on its type. There may be multiple protocols + * available for a repository type (eg. http and ssh). + */ +public interface ScmProtocol { + + /** + * The type of the concrete protocol, eg. "http" or "ssh". + */ + String getType(); + + /** + * The URL to access the repository providing this protocol. + */ + String getUrl(); +} diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java new file mode 100644 index 0000000000..76241808fb --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java @@ -0,0 +1,15 @@ +package sonia.scm.repository.spi; + +import sonia.scm.repository.api.ScmProtocol; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public interface HttpScmProtocol extends ScmProtocol { + @Override + default String getType() { + return "http"; + } + + void serve(HttpServletRequest request, HttpServletResponse response); +} diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java index 976f38fffb..d44db74f7c 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java @@ -38,15 +38,15 @@ package sonia.scm.repository.spi; import sonia.scm.repository.Feature; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.CommandNotSupportedException; - -//~--- JDK imports ------------------------------------------------------------ +import sonia.scm.repository.api.ScmProtocol; import java.io.Closeable; import java.io.IOException; - import java.util.Collections; import java.util.Set; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -244,4 +244,6 @@ public abstract class RepositoryServiceProvider implements Closeable { throw new CommandNotSupportedException(Command.UNBUNDLE); } + + public abstract Set getSupportedProtocols(); } diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java new file mode 100644 index 0000000000..f70e5a66a4 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java @@ -0,0 +1,65 @@ +package sonia.scm.repository.api; + +import org.junit.Test; +import sonia.scm.repository.Repository; +import sonia.scm.repository.spi.HttpScmProtocol; +import sonia.scm.repository.spi.RepositoryServiceProvider; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Collections; +import java.util.Set; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.util.IterableUtil.sizeOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class RepositoryServiceTest { + + private final RepositoryServiceProvider provider = mock(RepositoryServiceProvider.class); + private final Repository repository = mock(Repository.class); + + @Test + public void shouldReturnProtocolsFromProvider() { + when(provider.getSupportedProtocols()).thenReturn(Collections.singleton(new DummyHttpProtocol())); + + RepositoryService repositoryService = new RepositoryService(null, provider, repository, null); + Set supportedProtocols = repositoryService.getSupportedProtocols(); + + assertThat(sizeOf(supportedProtocols)).isEqualTo(1); + } + + @Test + public void shouldFindProtocolFromProvider() { + when(provider.getSupportedProtocols()).thenReturn(Collections.singleton(new DummyHttpProtocol())); + + RepositoryService repositoryService = new RepositoryService(null, provider, repository, null); + HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class); + + assertThat(protocol.getUrl()).isEqualTo("dummy"); + } + + @Test + public void shouldFailForUnknownProtocol() { + when(provider.getSupportedProtocols()).thenReturn(Collections.emptySet()); + + RepositoryService repositoryService = new RepositoryService(null, provider, repository, null); + + assertThrows(IllegalArgumentException.class, () -> { + repositoryService.getProtocol(HttpScmProtocol.class); + }); + } + + private static class DummyHttpProtocol implements HttpScmProtocol { + @Override + public String getUrl() { + return "dummy"; + } + + @Override + public void serve(HttpServletRequest request, HttpServletResponse response) { + } + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java index 7ea26de83f..2fbbf3b029 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java @@ -36,17 +36,17 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.collect.ImmutableSet; - import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; - -//~--- JDK imports ------------------------------------------------------------ +import sonia.scm.repository.api.ScmProtocol; import java.io.IOException; - +import java.util.Collections; import java.util.Set; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -248,6 +248,12 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider return new GitTagsCommand(context, repository); } + @Override + public Set getSupportedProtocols() { + // TODO #9246 + return Collections.emptySet(); + } + //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java index 4295bf45e4..11697ecea6 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java @@ -36,21 +36,21 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.io.Closeables; - import sonia.scm.repository.Feature; import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; - -//~--- JDK imports ------------------------------------------------------------ +import sonia.scm.repository.api.ScmProtocol; import java.io.File; import java.io.IOException; - +import java.util.Collections; import java.util.EnumSet; import java.util.Set; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -273,6 +273,12 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider return new HgTagsCommand(context, repository); } + @Override + public Set getSupportedProtocols() { + // TODO #9248 + return Collections.emptySet(); + } + //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java index 24180bfe9e..3b246cff2e 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java @@ -37,17 +37,17 @@ package sonia.scm.repository.spi; import com.google.common.collect.ImmutableSet; import com.google.common.io.Closeables; - import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; import sonia.scm.repository.api.Command; - -//~--- JDK imports ------------------------------------------------------------ +import sonia.scm.repository.api.ScmProtocol; import java.io.IOException; - +import java.util.Collections; import java.util.Set; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -191,6 +191,12 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider return new SvnUnbundleCommand(context, repository); } + @Override + public Set getSupportedProtocols() { + // TODO #9247 + return Collections.emptySet(); + } + //~--- fields --------------------------------------------------------------- /** Field description */ From 3f772b3688e789a5c96a0f04889f85fcc5be0468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 4 Sep 2018 12:40:41 +0200 Subject: [PATCH 02/58] Use links from protocols instead of resource links Add links only for requests with according permissions --- .../scm/repository/api/RepositoryService.java | 4 +- .../sonia/scm/repository/api/ScmProtocol.java | 4 +- .../repository/api/RepositoryServiceTest.java | 9 +-- .../RepositoryToRepositoryDtoMapper.java | 21 ++++++- .../scm/api/v2/resources/ResourceLinks.java | 5 -- .../scm/api/v2/resources/MockScmProtocol.java | 25 ++++++++ .../resources/RepositoryRootResourceTest.java | 24 +++++++- .../RepositoryToRepositoryDtoMapperTest.java | 58 +++++++++++++++++-- .../resources/sonia/scm/repository/shiro.ini | 2 + 9 files changed, 132 insertions(+), 20 deletions(-) create mode 100644 scm-webapp/src/test/java/sonia/scm/api/v2/resources/MockScmProtocol.java diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java index 926caad530..61c3ce5d87 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java @@ -42,7 +42,7 @@ import sonia.scm.repository.spi.RepositoryServiceProvider; import java.io.Closeable; import java.io.IOException; -import java.util.Set; +import java.util.Collection; /** * From the {@link RepositoryService} it is possible to access all commands for @@ -359,7 +359,7 @@ public final class RepositoryService implements Closeable { } - public Set getSupportedProtocols() { + public Collection getSupportedProtocols() { return provider.getSupportedProtocols(); } diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java index c987510491..0bd1ed77ef 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java @@ -1,5 +1,7 @@ package sonia.scm.repository.api; +import javax.ws.rs.core.UriInfo; + /** * An ScmProtocol represents a concrete protocol provided by the SCM-Manager instance * to interact with a repository depending on its type. There may be multiple protocols @@ -15,5 +17,5 @@ public interface ScmProtocol { /** * The URL to access the repository providing this protocol. */ - String getUrl(); + String getUrl(UriInfo uriInfo); } diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java index f70e5a66a4..c5e38908ec 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java @@ -7,8 +7,9 @@ import sonia.scm.repository.spi.RepositoryServiceProvider; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.UriInfo; +import java.util.Collection; import java.util.Collections; -import java.util.Set; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.util.IterableUtil.sizeOf; @@ -26,7 +27,7 @@ public class RepositoryServiceTest { when(provider.getSupportedProtocols()).thenReturn(Collections.singleton(new DummyHttpProtocol())); RepositoryService repositoryService = new RepositoryService(null, provider, repository, null); - Set supportedProtocols = repositoryService.getSupportedProtocols(); + Collection supportedProtocols = repositoryService.getSupportedProtocols(); assertThat(sizeOf(supportedProtocols)).isEqualTo(1); } @@ -38,7 +39,7 @@ public class RepositoryServiceTest { RepositoryService repositoryService = new RepositoryService(null, provider, repository, null); HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class); - assertThat(protocol.getUrl()).isEqualTo("dummy"); + assertThat(protocol.getUrl(null)).isEqualTo("dummy"); } @Test @@ -54,7 +55,7 @@ public class RepositoryServiceTest { private static class DummyHttpProtocol implements HttpScmProtocol { @Override - public String getUrl() { + public String getUrl(UriInfo uriInfo) { return "dummy"; } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java index f76669fbb9..0bc9b7af48 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java @@ -1,6 +1,7 @@ package sonia.scm.api.v2.resources; import com.google.inject.Inject; +import de.otto.edison.hal.Link; import de.otto.edison.hal.Links; import org.mapstruct.AfterMapping; import org.mapstruct.Mapper; @@ -11,9 +12,14 @@ import sonia.scm.repository.RepositoryPermissions; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.repository.api.ScmProtocol; + +import java.util.Collection; +import java.util.List; import static de.otto.edison.hal.Link.link; import static de.otto.edison.hal.Links.linkingTo; +import static java.util.stream.Collectors.toList; // Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection. @SuppressWarnings("squid:S3306") @@ -24,13 +30,14 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper supportedProtocols = repositoryService.getSupportedProtocols(); + List protocolLinks = supportedProtocols + .stream() + .map(this::createProtocolLink) + .collect(toList()); + linksBuilder.array(protocolLinks); + } if (repositoryService.isSupported(Command.TAGS)) { linksBuilder.single(link("tags", resourceLinks.tag().all(target.getNamespace(), target.getName()))); } @@ -50,4 +65,8 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper createSingletonPageResult(Repository repository) { return new PageResult<>(singletonList(repository), 0); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java index 0c77d40023..9fe2700e4a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java @@ -7,7 +7,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.mockito.Answers; import org.mockito.InjectMocks; import org.mockito.Mock; import sonia.scm.repository.HealthCheckFailure; @@ -15,13 +14,18 @@ import sonia.scm.repository.Permission; import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; +import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.repository.api.ScmProtocol; import java.net.URI; +import static java.util.Arrays.asList; +import static java.util.Collections.emptySet; import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; @@ -39,8 +43,12 @@ public class RepositoryToRepositoryDtoMapperTest { private final URI baseUri = URI.create("http://example.com/base/"); @SuppressWarnings("unused") // Is injected private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); - @Mock(answer = Answers.RETURNS_DEEP_STUBS) + @Mock//(answer = Answers.RETURNS_DEEP_STUBS) private RepositoryServiceFactory serviceFactory; + @Mock + private RepositoryService repositoryService; + @Mock + private UriInfoStore uriInfoStore; @InjectMocks private RepositoryToRepositoryDtoMapperImpl mapper; @@ -48,7 +56,9 @@ public class RepositoryToRepositoryDtoMapperTest { @Before public void init() { initMocks(this); - when(serviceFactory.create(any(Repository.class)).isSupported(any(Command.class))).thenReturn(true); + when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService); + when(repositoryService.isSupported(any(Command.class))).thenReturn(true); + when(repositoryService.getSupportedProtocols()).thenReturn(emptySet()); } @After @@ -129,14 +139,14 @@ public class RepositoryToRepositoryDtoMapperTest { @Test public void shouldNotCreateTagsLink_ifNotSupported() { - when(serviceFactory.create(any(Repository.class)).isSupported(Command.TAGS)).thenReturn(false); + when(repositoryService.isSupported(Command.TAGS)).thenReturn(false); RepositoryDto dto = mapper.map(createTestRepository()); assertFalse(dto.getLinks().getLinkBy("tags").isPresent()); } @Test public void shouldNotCreateBranchesLink_ifNotSupported() { - when(serviceFactory.create(any(Repository.class)).isSupported(Command.BRANCHES)).thenReturn(false); + when(repositoryService.isSupported(Command.BRANCHES)).thenReturn(false); RepositoryDto dto = mapper.map(createTestRepository()); assertFalse(dto.getLinks().getLinkBy("branches").isPresent()); } @@ -165,6 +175,43 @@ public class RepositoryToRepositoryDtoMapperTest { dto.getLinks().getLinkBy("permissions").get().getHref()); } + @Test + public void shouldCreateCorrectProtocolLinks() { + when(repositoryService.getSupportedProtocols()).thenReturn( + asList(mockProtocol("http", "http://scm"), mockProtocol("other", "some://protocol")) + ); + + RepositoryDto dto = mapper.map(createTestRepository()); + assertTrue("should contain http link", dto.getLinks().stream().anyMatch(l -> l.getName().equals("http") && l.getHref().equals("http://scm"))); + assertTrue("should contain other link", dto.getLinks().stream().anyMatch(l -> l.getName().equals("other") && l.getHref().equals("some://protocol"))); + } + + @Test + @SubjectAware(username = "community") + public void shouldCreateProtocolLinksForPullPermission() { + when(repositoryService.getSupportedProtocols()).thenReturn( + asList(mockProtocol("http", "http://scm"), mockProtocol("other", "some://protocol")) + ); + + RepositoryDto dto = mapper.map(createTestRepository()); + assertEquals(2, dto.getLinks().getLinksBy("protocol").size()); + } + + @Test + @SubjectAware(username = "unpriv") + public void shouldNotCreateProtocolLinksWithoutPullPermission() { + when(repositoryService.getSupportedProtocols()).thenReturn( + asList(mockProtocol("http", "http://scm"), mockProtocol("other", "some://protocol")) + ); + + RepositoryDto dto = mapper.map(createTestRepository()); + assertTrue(dto.getLinks().getLinksBy("protocol").isEmpty()); + } + + private ScmProtocol mockProtocol(String type, String protocol) { + return new MockScmProtocol(type, protocol); + } + private Repository createTestRepository() { Repository repository = new Repository(); repository.setNamespace("testspace"); @@ -179,4 +226,5 @@ public class RepositoryToRepositoryDtoMapperTest { return repository; } + } diff --git a/scm-webapp/src/test/resources/sonia/scm/repository/shiro.ini b/scm-webapp/src/test/resources/sonia/scm/repository/shiro.ini index 5073bf398d..9a39a2d46c 100644 --- a/scm-webapp/src/test/resources/sonia/scm/repository/shiro.ini +++ b/scm-webapp/src/test/resources/sonia/scm/repository/shiro.ini @@ -3,9 +3,11 @@ trillian = secret, admin dent = secret, creator, heartOfGold, puzzle42 unpriv = secret crato = secret, creator +community = secret, oss [roles] admin = * creator = repository:create heartOfGold = "repository:read,modify,delete:hof" puzzle42 = "repository:read,write:p42" +oss = "repository:pull" From c4b34752b495078225e83ccd013504b808b1a5fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 4 Sep 2018 20:29:17 +0200 Subject: [PATCH 03/58] Fix integration tests by delegating to existing servlets --- .../java/sonia/scm/repository/Repository.java | 12 ---- .../sonia/scm/repository/api/ScmProtocol.java | 4 +- .../spi/DefaultHttpScmProtocol.java | 20 +++++++ .../scm/repository/spi/HttpScmProtocol.java | 4 +- .../sonia/scm/repository/RepositoryTest.java | 60 ------------------- .../repository/api/RepositoryServiceTest.java | 4 +- .../java/sonia/scm/it/RepositoryUtil.java | 2 +- .../spi/GitRepositoryServiceProvider.java | 4 +- .../java/sonia/scm/web/ScmGitServlet.java | 16 ++++- .../spi/HgRepositoryServiceProvider.java | 4 +- .../main/java/sonia/scm/web/HgCGIServlet.java | 15 ++++- .../spi/SvnRepositoryServiceProvider.java | 4 +- .../java/sonia/scm/web/SvnDAVServlet.java | 15 ++++- .../resources/RepositoryRootResource.java | 31 +++------- .../RepositoryToRepositoryDtoMapper.java | 6 +- .../scm/api/v2/resources/MockScmProtocol.java | 3 +- 16 files changed, 90 insertions(+), 114 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java delete mode 100644 scm-core/src/test/java/sonia/scm/repository/RepositoryTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/Repository.java b/scm-core/src/main/java/sonia/scm/repository/Repository.java index 0d8c6a6af8..cad36f2d88 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Repository.java +++ b/scm-core/src/main/java/sonia/scm/repository/Repository.java @@ -40,7 +40,6 @@ import com.google.common.base.Objects; import com.google.common.collect.Lists; import sonia.scm.BasicPropertiesAware; import sonia.scm.ModelObject; -import sonia.scm.util.HttpUtil; import sonia.scm.util.Util; import sonia.scm.util.ValidationUtil; @@ -349,17 +348,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per // do not copy health check results } - /** - * Creates the url of the repository. - * - * @param baseUrl base url of the server including the context path - * @return url of the repository - * @since 1.17 - */ - public String createUrl(String baseUrl) { - return HttpUtil.concatenate(baseUrl, type, namespace, name); - } - /** * Returns true if the {@link Repository} is the same as the obj argument. * diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java index 0bd1ed77ef..8d44ec19ad 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java @@ -1,5 +1,7 @@ package sonia.scm.repository.api; +import sonia.scm.repository.Repository; + import javax.ws.rs.core.UriInfo; /** @@ -17,5 +19,5 @@ public interface ScmProtocol { /** * The URL to access the repository providing this protocol. */ - String getUrl(UriInfo uriInfo); + String getUrl(Repository repository, UriInfo uriInfo); } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java new file mode 100644 index 0000000000..223be7aca8 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java @@ -0,0 +1,20 @@ +package sonia.scm.repository.spi; + +import sonia.scm.repository.Repository; + +import javax.ws.rs.core.UriInfo; +import java.net.URI; + +public abstract class DefaultHttpScmProtocol implements HttpScmProtocol { + + private final Repository repository; + + protected DefaultHttpScmProtocol(Repository repository) { + this.repository = repository; + } + + @Override + public String getUrl(Repository repository, UriInfo uriInfo) { + return uriInfo.getBaseUri().resolve(URI.create("../../" + this.repository.getType() + "/" + this.repository.getNamespace() + "/" + this.repository.getName())).toASCIIString(); + } +} diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java index 76241808fb..2bf46c384d 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java @@ -2,8 +2,10 @@ package sonia.scm.repository.spi; import sonia.scm.repository.api.ScmProtocol; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; public interface HttpScmProtocol extends ScmProtocol { @Override @@ -11,5 +13,5 @@ public interface HttpScmProtocol extends ScmProtocol { return "http"; } - void serve(HttpServletRequest request, HttpServletResponse response); + void serve(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException; } diff --git a/scm-core/src/test/java/sonia/scm/repository/RepositoryTest.java b/scm-core/src/test/java/sonia/scm/repository/RepositoryTest.java deleted file mode 100644 index f13f4cbc67..0000000000 --- a/scm-core/src/test/java/sonia/scm/repository/RepositoryTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2010, Sebastian Sdorra - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ - - -package sonia.scm.repository; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * - * @author Sebastian Sdorra - */ -public class RepositoryTest -{ - - /** - * Method description - * - */ - @Test - public void testCreateUrl() - { - Repository repository = new Repository("123", "hg", "test", "repo"); - - assertEquals("http://localhost:8080/scm/hg/test/repo", - repository.createUrl("http://localhost:8080/scm")); - assertEquals("http://localhost:8080/scm/hg/test/repo", - repository.createUrl("http://localhost:8080/scm/")); - } -} diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java index c5e38908ec..7addb448f6 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java @@ -39,7 +39,7 @@ public class RepositoryServiceTest { RepositoryService repositoryService = new RepositoryService(null, provider, repository, null); HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class); - assertThat(protocol.getUrl(null)).isEqualTo("dummy"); + assertThat(protocol.getUrl(repository, null)).isEqualTo("dummy"); } @Test @@ -55,7 +55,7 @@ public class RepositoryServiceTest { private static class DummyHttpProtocol implements HttpScmProtocol { @Override - public String getUrl(UriInfo uriInfo) { + public String getUrl(Repository repository, UriInfo uriInfo) { return "dummy"; } diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java b/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java index ef2332074b..b4690768fc 100644 --- a/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java +++ b/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java @@ -24,7 +24,7 @@ public class RepositoryUtil { static RepositoryClient createRepositoryClient(String repositoryType, File folder, String username, String password) throws IOException { String httpProtocolUrl = TestData.callRepository(username, password, repositoryType, HttpStatus.SC_OK) .extract() - .path("_links.httpProtocol.href"); + .path("_links.protocol.find{it.name=='http'}.href"); return REPOSITORY_CLIENT_FACTORY.create(repositoryType, httpProtocolUrl, username, password, folder); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java index 2fbbf3b029..56ceb59de0 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java @@ -40,6 +40,7 @@ import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.ScmProtocol; +import sonia.scm.web.ScmGitServlet; import java.io.IOException; import java.util.Collections; @@ -250,8 +251,7 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider @Override public Set getSupportedProtocols() { - // TODO #9246 - return Collections.emptySet(); + return Collections.singleton(new ScmGitServlet(null, null, null, null, null, null)); } //~--- fields --------------------------------------------------------------- diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java index 5612a64652..5efffec523 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java @@ -44,6 +44,7 @@ import org.slf4j.Logger; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryRequestListenerUtil; +import sonia.scm.repository.spi.HttpScmProtocol; import sonia.scm.util.HttpUtil; import sonia.scm.web.lfs.servlet.LfsServletFactory; @@ -51,7 +52,9 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.UriInfo; import java.io.IOException; +import java.net.URI; import java.util.regex.Pattern; import static org.eclipse.jgit.lfs.lib.Constants.CONTENT_TYPE_GIT_LFS_JSON; @@ -64,7 +67,7 @@ import static org.slf4j.LoggerFactory.getLogger; * @author Sebastian Sdorra */ @Singleton -public class ScmGitServlet extends GitServlet +public class ScmGitServlet extends GitServlet implements HttpScmProtocol { /** Field description */ @@ -284,6 +287,16 @@ public class ScmGitServlet extends GitServlet return false; } + @Override + public void serve(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + service(request, response); + } + + @Override + public String getUrl(Repository repository, UriInfo uriInfo) { + return uriInfo.getBaseUri().resolve(URI.create("../../git/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); + } + //~--- fields --------------------------------------------------------------- @@ -299,5 +312,4 @@ public class ScmGitServlet extends GitServlet private final GitRepositoryViewer repositoryViewer; private final LfsServletFactory lfsServletFactory; - } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java index 11697ecea6..882c5a1c6b 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java @@ -42,6 +42,7 @@ import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.ScmProtocol; +import sonia.scm.web.HgCGIServlet; import java.io.File; import java.io.IOException; @@ -275,8 +276,7 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider @Override public Set getSupportedProtocols() { - // TODO #9248 - return Collections.emptySet(); + return Collections.singleton(new HgCGIServlet(null, null, null, null, null, null)); } //~--- fields --------------------------------------------------------------- diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index 6cb4d523f0..a8fbf0431e 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -51,6 +51,7 @@ import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryRequestListenerUtil; +import sonia.scm.repository.spi.HttpScmProtocol; import sonia.scm.security.CipherUtil; import sonia.scm.util.AssertUtil; import sonia.scm.util.HttpUtil; @@ -63,8 +64,10 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javax.ws.rs.core.UriInfo; import java.io.File; import java.io.IOException; +import java.net.URI; import java.util.Base64; import java.util.Enumeration; @@ -75,7 +78,7 @@ import java.util.Enumeration; * @author Sebastian Sdorra */ @Singleton -public class HgCGIServlet extends HttpServlet +public class HgCGIServlet extends HttpServlet implements HttpScmProtocol { /** Field description */ @@ -359,6 +362,16 @@ public class HgCGIServlet extends HttpServlet return python; } + @Override + public void serve(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + service(request, response); + } + + @Override + public String getUrl(Repository repository, UriInfo uriInfo) { + return uriInfo.getBaseUri().resolve(URI.create("../../hg/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); + } + //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java index 3b246cff2e..cbd303a9c6 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java @@ -41,6 +41,7 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.ScmProtocol; +import sonia.scm.web.SvnDAVServlet; import java.io.IOException; import java.util.Collections; @@ -193,8 +194,7 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider @Override public Set getSupportedProtocols() { - // TODO #9247 - return Collections.emptySet(); + return Collections.singleton(new SvnDAVServlet(null, null, null, null)); } //~--- fields --------------------------------------------------------------- diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java index c811179255..c968763955 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java @@ -45,6 +45,7 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryRequestListenerUtil; import sonia.scm.repository.SvnRepositoryHandler; +import sonia.scm.repository.spi.HttpScmProtocol; import sonia.scm.util.AssertUtil; import sonia.scm.util.HttpUtil; @@ -52,7 +53,9 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.UriInfo; import java.io.IOException; +import java.net.URI; //~--- JDK imports ------------------------------------------------------------ @@ -61,7 +64,7 @@ import java.io.IOException; * @author Sebastian Sdorra */ @Singleton -public class SvnDAVServlet extends DAVServlet +public class SvnDAVServlet extends DAVServlet implements HttpScmProtocol { /** Field description */ @@ -283,6 +286,16 @@ public class SvnDAVServlet extends DAVServlet private final RepositoryProvider repositoryProvider; } + @Override + public void serve(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + service(request, response); + } + + @Override + public String getUrl(Repository repository, UriInfo uriInfo) { + return uriInfo.getBaseUri().resolve(URI.create("../../svn/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); + } + //~--- fields --------------------------------------------------------------- diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java index cec1894764..59ffbe560b 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java @@ -40,30 +40,26 @@ import com.google.common.collect.Collections2; import com.google.common.collect.Maps; import com.google.common.collect.Ordering; import com.google.inject.Inject; - import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryTypePredicate; +import sonia.scm.template.Viewable; import sonia.scm.util.HttpUtil; -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - -import java.util.Collection; -import java.util.Comparator; -import java.util.List; -import java.util.Map; - import javax.servlet.http.HttpServletRequest; - 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.Context; import javax.ws.rs.core.MediaType; -import sonia.scm.template.Viewable; +import java.io.IOException; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +//~--- JDK imports ------------------------------------------------------------ /** * @@ -175,17 +171,6 @@ public class RepositoryRootResource return repository; } - /** - * Method description - * - * - * @return - */ - public String getUrl() - { - return repository.createUrl(baseUrl); - } - //~--- fields ------------------------------------------------------------- /** Field description */ diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java index 0bc9b7af48..bc0073506e 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java @@ -50,7 +50,7 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper supportedProtocols = repositoryService.getSupportedProtocols(); List protocolLinks = supportedProtocols .stream() - .map(this::createProtocolLink) + .map(protocol -> createProtocolLink(protocol, repository)) .collect(toList()); linksBuilder.array(protocolLinks); } @@ -66,7 +66,7 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper Date: Thu, 6 Sep 2018 10:58:09 +0200 Subject: [PATCH 04/58] Add POC protocol servlet with delegate to git --- .../scm/repository/RepositoryProvider.java | 28 ++---- .../spi/GitRepositoryServiceProvider.java | 17 ++-- .../spi/GitRepositoryServiceResolver.java | 18 ++-- .../java/sonia/scm/web/GitServletModule.java | 3 - .../java/sonia/scm/ScmContextListener.java | 2 +- .../main/java/sonia/scm/ScmServletModule.java | 56 ++++++++---- .../java/sonia/scm/WebResourceServlet.java | 2 +- .../repository/DefaultRepositoryManager.java | 48 +---------- .../repository/DefaultRepositoryProvider.java | 70 +++------------ .../scm/web/protocol/HttpProtocolServlet.java | 86 +++++++++++++++++++ 10 files changed, 163 insertions(+), 167 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryProvider.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryProvider.java index 1a5300ad21..cea8574d14 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryProvider.java @@ -6,13 +6,13 @@ * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,35 +26,21 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * http://bitbucket.org/sdorra/scm-manager - * */ - package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- import com.google.inject.throwingproviders.CheckedProvider; -import sonia.scm.security.ScmSecurityException; - /** * * @author Sebastian Sdorra * @since 1.10 */ -public interface RepositoryProvider extends CheckedProvider -{ - - /** - * Method description - * - * - * @return - * - * @throws ScmSecurityException - */ +public interface RepositoryProvider extends CheckedProvider { @Override - public Repository get() throws ScmSecurityException; + Repository get(); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java index 56ceb59de0..45a0ad5347 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java @@ -42,6 +42,7 @@ import sonia.scm.repository.api.Command; import sonia.scm.repository.api.ScmProtocol; import sonia.scm.web.ScmGitServlet; +import javax.inject.Provider; import java.io.IOException; import java.util.Collections; import java.util.Set; @@ -74,19 +75,13 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider //~--- constructors --------------------------------------------------------- - /** - * Constructs ... - * - * - * @param handler - * @param repository - */ public GitRepositoryServiceProvider(GitRepositoryHandler handler, - Repository repository) + Repository repository, Provider servletProvider) { this.handler = handler; this.repository = repository; - context = new GitContext(handler.getDirectory(repository)); + this.servletProvider = servletProvider; + this.context = new GitContext(handler.getDirectory(repository)); } //~--- methods -------------------------------------------------------------- @@ -251,7 +246,7 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider @Override public Set getSupportedProtocols() { - return Collections.singleton(new ScmGitServlet(null, null, null, null, null, null)); + return Collections.singleton(servletProvider.get()); } //~--- fields --------------------------------------------------------------- @@ -264,4 +259,6 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider /** Field description */ private Repository repository; + + private final Provider servletProvider; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java index 52c5171627..2cecb964fe 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java @@ -35,10 +35,12 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import com.google.inject.Inject; - import sonia.scm.plugin.Extension; import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; +import sonia.scm.web.ScmGitServlet; + +import javax.inject.Provider; /** * @@ -53,16 +55,11 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver //~--- constructors --------------------------------------------------------- - /** - * Constructs ... - * - * - * @param handler - */ @Inject - public GitRepositoryServiceResolver(GitRepositoryHandler handler) + public GitRepositoryServiceResolver(GitRepositoryHandler handler, Provider servletProvider) { this.handler = handler; + this.servletProvider = servletProvider; } //~--- methods -------------------------------------------------------------- @@ -82,7 +79,7 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver if (TYPE.equalsIgnoreCase(repository.getType())) { - provider = new GitRepositoryServiceProvider(handler, repository); + provider = new GitRepositoryServiceProvider(handler, repository, servletProvider); } return provider; @@ -91,5 +88,6 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver //~--- fields --------------------------------------------------------------- /** Field description */ - private GitRepositoryHandler handler; + private final GitRepositoryHandler handler; + private final Provider servletProvider; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java index bdad103c15..94e772123e 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java @@ -75,8 +75,5 @@ public class GitServletModule extends ServletModule bind(GitConfigDtoToGitConfigMapper.class).to(Mappers.getMapper(GitConfigDtoToGitConfigMapper.class).getClass()); bind(GitConfigToGitConfigDtoMapper.class).to(Mappers.getMapper(GitConfigToGitConfigDtoMapper.class).getClass()); - - // serlvelts and filters - serve(PATTERN_GIT).with(ScmGitServlet.class); } } diff --git a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java index 1eaef333a1..cb272de38f 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java @@ -135,7 +135,7 @@ public class ScmContextListener extends GuiceResteasyBootstrapServletContextList moduleList.add(new EagerSingletonModule()); moduleList.add(ShiroWebModule.guiceFilterModule()); moduleList.add(new WebElementModule(pluginLoader)); - moduleList.add(new ScmServletModule(context, pluginLoader, overrides, pluginLoader.getExtensionProcessor())); + moduleList.add(new ScmServletModule(context, pluginLoader, overrides)); moduleList.add( new ScmSecurityModule(context, pluginLoader.getExtensionProcessor()) ); diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java index 1d627de8ed..2ea17e9da3 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java @@ -56,17 +56,48 @@ import sonia.scm.group.xml.XmlGroupDAO; import sonia.scm.io.DefaultFileSystem; import sonia.scm.io.FileSystem; import sonia.scm.net.SSLContextProvider; -import sonia.scm.net.ahc.*; -import sonia.scm.plugin.*; -import sonia.scm.repository.*; +import sonia.scm.net.ahc.AdvancedHttpClient; +import sonia.scm.net.ahc.ContentTransformer; +import sonia.scm.net.ahc.DefaultAdvancedHttpClient; +import sonia.scm.net.ahc.JsonContentTransformer; +import sonia.scm.net.ahc.XmlContentTransformer; +import sonia.scm.plugin.DefaultPluginLoader; +import sonia.scm.plugin.DefaultPluginManager; +import sonia.scm.plugin.PluginLoader; +import sonia.scm.plugin.PluginManager; +import sonia.scm.repository.DefaultRepositoryManager; +import sonia.scm.repository.DefaultRepositoryProvider; +import sonia.scm.repository.HealthCheckContextListener; +import sonia.scm.repository.NamespaceStrategy; +import sonia.scm.repository.NamespaceStrategyProvider; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryDAO; +import sonia.scm.repository.RepositoryManager; +import sonia.scm.repository.RepositoryManagerProvider; +import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.api.HookContextFactory; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.repository.spi.HookEventFacade; import sonia.scm.repository.xml.XmlRepositoryDAO; import sonia.scm.schedule.QuartzScheduler; import sonia.scm.schedule.Scheduler; -import sonia.scm.security.*; -import sonia.scm.store.*; +import sonia.scm.security.AuthorizationChangedEventProducer; +import sonia.scm.security.CipherHandler; +import sonia.scm.security.CipherUtil; +import sonia.scm.security.ConfigurableLoginAttemptHandler; +import sonia.scm.security.DefaultKeyGenerator; +import sonia.scm.security.DefaultSecuritySystem; +import sonia.scm.security.KeyGenerator; +import sonia.scm.security.LoginAttemptHandler; +import sonia.scm.security.SecuritySystem; +import sonia.scm.store.BlobStoreFactory; +import sonia.scm.store.ConfigurationEntryStoreFactory; +import sonia.scm.store.ConfigurationStoreFactory; +import sonia.scm.store.DataStoreFactory; +import sonia.scm.store.FileBlobStoreFactory; +import sonia.scm.store.JAXBConfigurationEntryStoreFactory; +import sonia.scm.store.JAXBConfigurationStoreFactory; +import sonia.scm.store.JAXBDataStoreFactory; import sonia.scm.template.MustacheTemplateEngine; import sonia.scm.template.TemplateEngine; import sonia.scm.template.TemplateEngineFactory; @@ -81,6 +112,7 @@ import sonia.scm.util.ScmConfigurationUtil; import sonia.scm.web.UserAgentParser; import sonia.scm.web.cgi.CGIExecutorFactory; import sonia.scm.web.cgi.DefaultCGIExecutorFactory; +import sonia.scm.web.filter.AuthenticationFilter; import sonia.scm.web.filter.LoggingFilter; import sonia.scm.web.security.AdministrationContext; import sonia.scm.web.security.DefaultAdministrationContext; @@ -162,15 +194,12 @@ public class ScmServletModule extends ServletModule * @param servletContext * @param pluginLoader * @param overrides - * @param extensionProcessor */ - ScmServletModule(ServletContext servletContext, - DefaultPluginLoader pluginLoader, ClassOverrides overrides, ExtensionProcessor extensionProcessor) + ScmServletModule(ServletContext servletContext, DefaultPluginLoader pluginLoader, ClassOverrides overrides) { this.servletContext = servletContext; this.pluginLoader = pluginLoader; this.overrides = overrides; - this.extensionProcessor = extensionProcessor; } //~--- methods -------------------------------------------------------------- @@ -293,6 +322,8 @@ public class ScmServletModule extends ServletModule bind(TemplateEngineFactory.class); bind(ObjectMapper.class).toProvider(ObjectMapperProvider.class); + filter("/repo/*").through(AuthenticationFilter.class); + // bind events // bind(LastModifiedUpdateListener.class); @@ -389,11 +420,6 @@ public class ScmServletModule extends ServletModule /** * Load ScmConfiguration with JAXB - * - * - * @param context - * - * @return */ private ScmConfiguration getScmConfiguration() { @@ -414,6 +440,4 @@ public class ScmServletModule extends ServletModule /** Field description */ private final ServletContext servletContext; - - private final ExtensionProcessor extensionProcessor; } diff --git a/scm-webapp/src/main/java/sonia/scm/WebResourceServlet.java b/scm-webapp/src/main/java/sonia/scm/WebResourceServlet.java index 764e4f18d2..ce3e3fa4e1 100644 --- a/scm-webapp/src/main/java/sonia/scm/WebResourceServlet.java +++ b/scm-webapp/src/main/java/sonia/scm/WebResourceServlet.java @@ -33,7 +33,7 @@ public class WebResourceServlet extends HttpServlet { * TODO remove old protocol servlets and hook. Move /hook/hg to api? */ @VisibleForTesting - static final String PATTERN = "/(?!api/|git/|hg/|svn/|hook/).*"; + static final String PATTERN = "/(?!api/|git/|hg/|svn/|hook/|repo/).*"; private static final Logger LOG = LoggerFactory.getLogger(WebResourceServlet.class); diff --git a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java index 02ae67719b..06f92f7bec 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java @@ -34,7 +34,6 @@ package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- import com.github.sdorra.ssp.PermissionActionCheck; -import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.inject.Inject; @@ -43,7 +42,6 @@ import org.apache.shiro.concurrent.SubjectAwareExecutorService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.AlreadyExistsException; -import sonia.scm.ArgumentIsInvalidException; import sonia.scm.ConfigurationException; import sonia.scm.HandlerEventType; import sonia.scm.ManagerDaoAdapter; @@ -332,52 +330,12 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager { uri = uri.substring(1); } - int typeSeparator = uri.indexOf(HttpUtil.SEPARATOR_PATH); Repository repository = null; - if (typeSeparator > 0) { - String type = uri.substring(0, typeSeparator); + String namespace = uri.substring(0, uri.indexOf(HttpUtil.SEPARATOR_PATH)); + String name = uri.substring(uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1, uri.indexOf(HttpUtil.SEPARATOR_PATH, uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1)); - uri = uri.substring(typeSeparator + 1); - repository = getFromTypeAndUri(type, uri); - } - - return repository; - } - - private Repository getFromTypeAndUri(String type, String uri) { - if (Strings.isNullOrEmpty(type)) { - throw new ArgumentIsInvalidException("argument type is required"); - } - - if (Strings.isNullOrEmpty(uri)) { - throw new ArgumentIsInvalidException("argument uri is required"); - } - - // remove ;jsessionid, jetty bug? - uri = HttpUtil.removeMatrixParameter(uri); - - Repository repository = null; - - if (handlerMap.containsKey(type)) { - Collection repositories = repositoryDAO.getAll(); - - PermissionActionCheck check = RepositoryPermissions.read(); - - for (Repository r : repositories) { - if (repositoryMatcher.matches(r, type, uri)) { - check.check(r); - repository = r.clone(); - - break; - } - } - } - - if ((repository == null) && logger.isDebugEnabled()) { - logger.debug("could not find repository with type {} and uri {}", type, - uri); - } + repository = get(new NamespaceAndName(namespace, name)); return repository; } diff --git a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryProvider.java b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryProvider.java index c3341bbd22..3f061ff46d 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryProvider.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryProvider.java @@ -38,81 +38,31 @@ package sonia.scm.repository; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.servlet.RequestScoped; - import sonia.scm.security.ScmSecurityException; -//~--- JDK imports ------------------------------------------------------------ - import javax.servlet.http.HttpServletRequest; -/** - * - * @author Sebastian Sdorra - */ -@RequestScoped -public class DefaultRepositoryProvider implements RepositoryProvider -{ +//~--- JDK imports ------------------------------------------------------------ + +@RequestScoped +public class DefaultRepositoryProvider implements RepositoryProvider { - /** Field description */ public static final String ATTRIBUTE_NAME = "scm.request.repository"; - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param requestProvider - * @param manager - */ + private final Provider requestProvider; @Inject - public DefaultRepositoryProvider( - Provider requestProvider, - RepositoryManager manager) - { + public DefaultRepositoryProvider(Provider requestProvider) { this.requestProvider = requestProvider; - this.manager = manager; } - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @return - * - * @throws ScmSecurityException - */ @Override - public Repository get() throws ScmSecurityException - { - Repository repository = null; + public Repository get() throws ScmSecurityException { HttpServletRequest request = requestProvider.get(); - if (request != null) - { - repository = (Repository) request.getAttribute(ATTRIBUTE_NAME); - - if (repository == null) - { - repository = manager.getFromRequest(request); - - if (repository != null) - { - request.setAttribute(ATTRIBUTE_NAME, repository); - } - } + if (request != null) { + return (Repository) request.getAttribute(ATTRIBUTE_NAME); } - return repository; + throw new IllegalStateException("request not found"); } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private final RepositoryManager manager; - - /** Field description */ - private final Provider requestProvider; } diff --git a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java new file mode 100644 index 0000000000..7991cbb596 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java @@ -0,0 +1,86 @@ +package sonia.scm.web.protocol; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.subject.Subject; +import sonia.scm.PushStateDispatcher; +import sonia.scm.filter.WebElement; +import sonia.scm.repository.DefaultRepositoryProvider; +import sonia.scm.repository.NamespaceAndName; +import sonia.scm.repository.RepositoryNotFoundException; +import sonia.scm.repository.RepositoryProvider; +import sonia.scm.repository.api.RepositoryService; +import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.repository.spi.HttpScmProtocol; +import sonia.scm.util.HttpUtil; +import sonia.scm.web.UserAgent; +import sonia.scm.web.UserAgentParser; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Singleton +@WebElement(value = HttpProtocolServlet.PATTERN) +@Slf4j +public class HttpProtocolServlet extends HttpServlet { + + public static final String PATTERN = "/repo/*"; + + private final RepositoryProvider repositoryProvider; + private final RepositoryServiceFactory serviceFactory; + + private final Provider requestProvider; + + private final PushStateDispatcher dispatcher; + private final UserAgentParser userAgentParser; + + @Inject + public HttpProtocolServlet(RepositoryProvider repositoryProvider, RepositoryServiceFactory serviceFactory, Provider requestProvider, PushStateDispatcher dispatcher, UserAgentParser userAgentParser) { + this.repositoryProvider = repositoryProvider; + this.serviceFactory = serviceFactory; + this.requestProvider = requestProvider; + this.dispatcher = dispatcher; + this.userAgentParser = userAgentParser; + } + + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + Subject subject = SecurityUtils.getSubject(); + + + UserAgent userAgent = userAgentParser.parse(req); + if (userAgent.isBrowser()) { + log.trace("dispatch browser request for user agent {}", userAgent); + dispatcher.dispatch(req, resp, req.getRequestURI()); + } else { + + + String pathInfo = req.getPathInfo(); + NamespaceAndName namespaceAndName = fromUri(pathInfo); + try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) { + requestProvider.get().setAttribute(DefaultRepositoryProvider.ATTRIBUTE_NAME, repositoryService.getRepository()); + HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class); + protocol.serve(req, resp); + } catch (RepositoryNotFoundException e) { + resp.setStatus(404); + } + } + } + + private NamespaceAndName fromUri(String uri) { + if (uri.startsWith(HttpUtil.SEPARATOR_PATH)) { + uri = uri.substring(1); + } + + String namespace = uri.substring(0, uri.indexOf(HttpUtil.SEPARATOR_PATH)); + String name = uri.substring(uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1, uri.indexOf(HttpUtil.SEPARATOR_PATH, uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1)); + + return new NamespaceAndName(namespace, name); + } +} From 4eb75bc621bf0769236256b1727ae6d5f85e19ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 6 Sep 2018 15:33:24 +0200 Subject: [PATCH 05/58] Initialize servlet and fix paths --- .../scm/repository/spi/HttpScmProtocol.java | 3 +- .../InitializingHttpScmProtocolWrapper.java | 44 ++++++++++++ .../repository/api/RepositoryServiceTest.java | 3 +- .../spi/GitRepositoryServiceProvider.java | 10 ++- .../spi/GitRepositoryServiceResolver.java | 8 +-- .../scm/web/GitBasicAuthenticationFilter.java | 69 ------------------- .../sonia/scm/web/GitPermissionFilter.java | 17 ++--- .../sonia/scm/web/GitRepositoryResolver.java | 3 +- .../web/GitScmProtocolProviderWrapper.java | 15 ++++ .../java/sonia/scm/web/GitServletModule.java | 2 +- .../java/sonia/scm/web/ScmGitServlet.java | 18 +---- .../web/lfs/servlet/LfsServletFactory.java | 2 +- .../main/java/sonia/scm/web/HgCGIServlet.java | 3 +- .../java/sonia/scm/web/SvnDAVServlet.java | 3 +- .../scm/web/protocol/HttpProtocolServlet.java | 2 +- 15 files changed, 87 insertions(+), 115 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java delete mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitBasicAuthenticationFilter.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java index 2bf46c384d..c19205c1e7 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java @@ -2,6 +2,7 @@ package sonia.scm.repository.spi; import sonia.scm.repository.api.ScmProtocol; +import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -13,5 +14,5 @@ public interface HttpScmProtocol extends ScmProtocol { return "http"; } - void serve(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException; + void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException; } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java new file mode 100644 index 0000000000..ad0e7cb513 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -0,0 +1,44 @@ +package sonia.scm.repository.spi; + +import sonia.scm.repository.Repository; + +import javax.inject.Provider; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.UriInfo; +import java.io.IOException; +import java.net.URI; + +public abstract class InitializingHttpScmProtocolWrapper implements HttpScmProtocol { + + private final Provider delegateProvider; + + private volatile boolean isInitialized = false; + + + protected InitializingHttpScmProtocolWrapper(Provider delegateProvider) { + this.delegateProvider = delegateProvider; + } + + @Override + public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException { + if (!isInitialized) { + synchronized (this) { + if (!isInitialized) { + delegateProvider.get().init(config); + isInitialized = true; + } + } + } + delegateProvider.get().service(request, response); + } + + + @Override + public String getUrl(Repository repository, UriInfo uriInfo) { + return uriInfo.getBaseUri().resolve(URI.create("../../repo/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); + } +} diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java index 7addb448f6..8d37c0e187 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java @@ -5,6 +5,7 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.spi.HttpScmProtocol; import sonia.scm.repository.spi.RepositoryServiceProvider; +import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.UriInfo; @@ -60,7 +61,7 @@ public class RepositoryServiceTest { } @Override - public void serve(HttpServletRequest request, HttpServletResponse response) { + public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) { } } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java index 45a0ad5347..4874247785 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java @@ -40,9 +40,7 @@ import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.ScmProtocol; -import sonia.scm.web.ScmGitServlet; -import javax.inject.Provider; import java.io.IOException; import java.util.Collections; import java.util.Set; @@ -76,11 +74,11 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider //~--- constructors --------------------------------------------------------- public GitRepositoryServiceProvider(GitRepositoryHandler handler, - Repository repository, Provider servletProvider) + Repository repository, HttpScmProtocol httpScmProtocol) { this.handler = handler; this.repository = repository; - this.servletProvider = servletProvider; + this.httpScmProtocol = httpScmProtocol; this.context = new GitContext(handler.getDirectory(repository)); } @@ -246,7 +244,7 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider @Override public Set getSupportedProtocols() { - return Collections.singleton(servletProvider.get()); + return Collections.singleton(httpScmProtocol); } //~--- fields --------------------------------------------------------------- @@ -260,5 +258,5 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider /** Field description */ private Repository repository; - private final Provider servletProvider; + private final HttpScmProtocol httpScmProtocol; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java index 2cecb964fe..39ea4f761a 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java @@ -38,9 +38,7 @@ import com.google.inject.Inject; import sonia.scm.plugin.Extension; import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; -import sonia.scm.web.ScmGitServlet; - -import javax.inject.Provider; +import sonia.scm.web.GitScmProtocolProviderWrapper; /** * @@ -56,7 +54,7 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver //~--- constructors --------------------------------------------------------- @Inject - public GitRepositoryServiceResolver(GitRepositoryHandler handler, Provider servletProvider) + public GitRepositoryServiceResolver(GitRepositoryHandler handler, GitScmProtocolProviderWrapper servletProvider) { this.handler = handler; this.servletProvider = servletProvider; @@ -89,5 +87,5 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver /** Field description */ private final GitRepositoryHandler handler; - private final Provider servletProvider; + private final HttpScmProtocol servletProvider; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitBasicAuthenticationFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitBasicAuthenticationFilter.java deleted file mode 100644 index f06fcfcd39..0000000000 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitBasicAuthenticationFilter.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2010, Sebastian Sdorra All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. 2. Redistributions in - * binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. 3. Neither the name of SCM-Manager; - * nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ - - - -package sonia.scm.web; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.Inject; - -import sonia.scm.Priority; -import sonia.scm.config.ScmConfiguration; -import sonia.scm.filter.Filters; -import sonia.scm.filter.WebElement; -import sonia.scm.web.filter.AuthenticationFilter; - -import java.util.Set; - - -/** - * Handles git specific basic authentication. - * - * @author Sebastian Sdorra - */ -@Priority(Filters.PRIORITY_AUTHENTICATION) -@WebElement(value = GitServletModule.PATTERN_GIT) -public class GitBasicAuthenticationFilter extends AuthenticationFilter -{ - - /** - * Constructs a new instance. - * - * @param configuration scm-manager main configuration - * @param webTokenGenerators web token generators - */ - @Inject - public GitBasicAuthenticationFilter(ScmConfiguration configuration, - Set webTokenGenerators) - { - super(configuration, webTokenGenerators); - } -} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java index 1f07753f1e..068284188d 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java @@ -37,25 +37,20 @@ package sonia.scm.web; import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; -import com.google.inject.Singleton; - import org.eclipse.jgit.http.server.GitSmartHttpTools; - import sonia.scm.ClientMessages; +import sonia.scm.Priority; import sonia.scm.config.ScmConfiguration; +import sonia.scm.filter.Filters; import sonia.scm.repository.GitUtil; import sonia.scm.repository.RepositoryProvider; import sonia.scm.web.filter.ProviderPermissionFilter; -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import sonia.scm.Priority; -import sonia.scm.filter.Filters; -import sonia.scm.filter.WebElement; +import java.io.IOException; + +//~--- JDK imports ------------------------------------------------------------ /** * GitPermissionFilter decides if a git request requires write or read privileges. @@ -63,7 +58,7 @@ import sonia.scm.filter.WebElement; * @author Sebastian Sdorra */ @Priority(Filters.PRIORITY_AUTHORIZATION) -@WebElement(value = GitServletModule.PATTERN_GIT) +//@WebElement(value = GitServletModule.PATTERN_GIT) public class GitPermissionFilter extends ProviderPermissionFilter { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryResolver.java index 76e742a71a..7f04bb3a54 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryResolver.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitRepositoryResolver.java @@ -125,8 +125,9 @@ public class GitRepositoryResolver implements RepositoryResolver servletProvider) { + super(servletProvider); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java index 94e772123e..9b8d53caf2 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java @@ -51,7 +51,7 @@ import sonia.scm.web.lfs.LfsBlobStoreFactory; public class GitServletModule extends ServletModule { - public static final String GIT_PATH = "/git"; + public static final String GIT_PATH = "/repo"; /** Field description */ public static final String PATTERN_GIT = GIT_PATH + "/*"; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java index 5efffec523..261e67c185 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java @@ -44,7 +44,6 @@ import org.slf4j.Logger; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryRequestListenerUtil; -import sonia.scm.repository.spi.HttpScmProtocol; import sonia.scm.util.HttpUtil; import sonia.scm.web.lfs.servlet.LfsServletFactory; @@ -52,9 +51,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.UriInfo; import java.io.IOException; -import java.net.URI; import java.util.regex.Pattern; import static org.eclipse.jgit.lfs.lib.Constants.CONTENT_TYPE_GIT_LFS_JSON; @@ -67,12 +64,12 @@ import static org.slf4j.LoggerFactory.getLogger; * @author Sebastian Sdorra */ @Singleton -public class ScmGitServlet extends GitServlet implements HttpScmProtocol +public class ScmGitServlet extends GitServlet { /** Field description */ public static final Pattern REGEX_GITHTTPBACKEND = Pattern.compile( - "(?x)^/git/(.*/(HEAD|info/refs|objects/(info/[^/]+|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\\.(pack|idx))|git-(upload|receive)-pack))$" + "(?x)^/repo/(.*/(HEAD|info/refs|objects/(info/[^/]+|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\\.(pack|idx))|git-(upload|receive)-pack))$" ); /** Field description */ @@ -287,17 +284,6 @@ public class ScmGitServlet extends GitServlet implements HttpScmProtocol return false; } - @Override - public void serve(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - service(request, response); - } - - @Override - public String getUrl(Repository repository, UriInfo uriInfo) { - return uriInfo.getBaseUri().resolve(URI.create("../../git/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); - } - - //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/servlet/LfsServletFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/servlet/LfsServletFactory.java index 58bdb2fcf1..f4eed34678 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/servlet/LfsServletFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/servlet/LfsServletFactory.java @@ -70,7 +70,7 @@ public class LfsServletFactory { */ @VisibleForTesting static String buildBaseUri(Repository repository, HttpServletRequest request) { - return String.format("%s/git/%s/%s.git/info/lfs/objects/", HttpUtil.getCompleteUrl(request), repository.getNamespace(), repository.getName()); + return String.format("%s/repo/%s/%s.git/info/lfs/objects/", HttpUtil.getCompleteUrl(request), repository.getNamespace(), repository.getName()); } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index a8fbf0431e..ae0f259f97 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -59,6 +59,7 @@ import sonia.scm.web.cgi.CGIExecutor; import sonia.scm.web.cgi.CGIExecutorFactory; import sonia.scm.web.cgi.EnvList; +import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -363,7 +364,7 @@ public class HgCGIServlet extends HttpServlet implements HttpScmProtocol } @Override - public void serve(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException { service(request, response); } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java index c968763955..44c544bd68 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java @@ -49,6 +49,7 @@ import sonia.scm.repository.spi.HttpScmProtocol; import sonia.scm.util.AssertUtil; import sonia.scm.util.HttpUtil; +import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; @@ -287,7 +288,7 @@ public class SvnDAVServlet extends DAVServlet implements HttpScmProtocol } @Override - public void serve(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException { service(request, response); } diff --git a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java index 7991cbb596..15536db19a 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java +++ b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java @@ -66,7 +66,7 @@ public class HttpProtocolServlet extends HttpServlet { try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) { requestProvider.get().setAttribute(DefaultRepositoryProvider.ATTRIBUTE_NAME, repositoryService.getRepository()); HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class); - protocol.serve(req, resp); + protocol.serve(req, resp, getServletConfig()); } catch (RepositoryNotFoundException e) { resp.setStatus(404); } From 5b5bfd342a4bf4b71dc99f80146772525f77d784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 6 Sep 2018 17:39:47 +0200 Subject: [PATCH 06/58] Add POC protocol servlet with delegate to svn and hg --- .../InitializingHttpScmProtocolWrapper.java | 3 ++- .../spi/HgRepositoryServiceProvider.java | 12 +++++++----- .../spi/HgRepositoryServiceResolver.java | 9 ++++++--- .../main/java/sonia/scm/web/HgCGIServlet.java | 13 ------------- .../java/sonia/scm/web/HgPermissionFilter.java | 13 ++++--------- .../scm/web/HgScmProtocolProviderWrapper.java | 15 +++++++++++++++ .../java/sonia/scm/web/HgServletModule.java | 3 --- .../spi/SvnRepositoryServiceProvider.java | 12 +++++++----- .../spi/SvnRepositoryServiceResolver.java | 10 +++++++--- .../scm/web/SvnBasicAuthenticationFilter.java | 18 ++++++------------ .../sonia/scm/web/SvnPermissionFilter.java | 18 ++++++------------ .../scm/web/SvnScmProtocolProviderWrapper.java | 15 +++++++++++++++ .../java/sonia/scm/web/SvnServletModule.java | 5 ++--- .../scm/web/protocol/HttpProtocolServlet.java | 5 ++++- 14 files changed, 81 insertions(+), 70 deletions(-) create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index ad0e7cb513..b06420d9c0 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -28,7 +28,8 @@ public abstract class InitializingHttpScmProtocolWrapper implements HttpScmProto if (!isInitialized) { synchronized (this) { if (!isInitialized) { - delegateProvider.get().init(config); + HttpServlet httpServlet = delegateProvider.get(); + httpServlet.init(config); isInitialized = true; } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java index 882c5a1c6b..b0499fac9f 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java @@ -42,7 +42,6 @@ import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.ScmProtocol; -import sonia.scm.web.HgCGIServlet; import java.io.File; import java.io.IOException; @@ -87,16 +86,17 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider * * * - * + * @param handler * @param hookManager - * @param handler * @param repository + * @param httpScmProtocol */ HgRepositoryServiceProvider(HgRepositoryHandler handler, - HgHookManager hookManager, Repository repository) + HgHookManager hookManager, Repository repository, HttpScmProtocol httpScmProtocol) { this.repository = repository; this.handler = handler; + this.httpScmProtocol = httpScmProtocol; this.repositoryDirectory = handler.getDirectory(repository); this.context = new HgCommandContext(hookManager, handler, repository, repositoryDirectory); @@ -276,7 +276,7 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider @Override public Set getSupportedProtocols() { - return Collections.singleton(new HgCGIServlet(null, null, null, null, null, null)); + return Collections.singleton(httpScmProtocol); } //~--- fields --------------------------------------------------------------- @@ -292,4 +292,6 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider /** Field description */ private File repositoryDirectory; + + private final HttpScmProtocol httpScmProtocol; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java index d322cb8e9f..d32d2f862f 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java @@ -36,11 +36,11 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import com.google.inject.Inject; - import sonia.scm.plugin.Extension; import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; +import sonia.scm.web.HgScmProtocolProviderWrapper; /** * @@ -65,10 +65,11 @@ public class HgRepositoryServiceResolver implements RepositoryServiceResolver */ @Inject public HgRepositoryServiceResolver(HgRepositoryHandler handler, - HgHookManager hookManager) + HgHookManager hookManager, HgScmProtocolProviderWrapper httpScmProtocol) { this.handler = handler; this.hookManager = hookManager; + this.httpScmProtocol = httpScmProtocol; } //~--- methods -------------------------------------------------------------- @@ -89,7 +90,7 @@ public class HgRepositoryServiceResolver implements RepositoryServiceResolver if (TYPE.equalsIgnoreCase(repository.getType())) { provider = new HgRepositoryServiceProvider(handler, hookManager, - repository); + repository, httpScmProtocol); } return provider; @@ -102,4 +103,6 @@ public class HgRepositoryServiceResolver implements RepositoryServiceResolver /** Field description */ private HgHookManager hookManager; + + private final HttpScmProtocol httpScmProtocol; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index ae0f259f97..3ceb129f3f 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -135,19 +135,6 @@ public class HgCGIServlet extends HttpServlet implements HttpScmProtocol //~--- methods -------------------------------------------------------------- - /** - * Method description - * - * - * @throws ServletException - */ - @Override - public void init() throws ServletException - { - - super.init(); - } - /** * Method description * diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java index de2835dd8f..c05f03dc4e 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java @@ -37,27 +37,22 @@ package sonia.scm.web; import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; - -import sonia.scm.Priority; import sonia.scm.config.ScmConfiguration; -import sonia.scm.filter.Filters; -import sonia.scm.filter.WebElement; import sonia.scm.repository.RepositoryProvider; import sonia.scm.web.filter.ProviderPermissionFilter; -//~--- JDK imports ------------------------------------------------------------ - +import javax.servlet.http.HttpServletRequest; import java.util.Set; -import javax.servlet.http.HttpServletRequest; +//~--- JDK imports ------------------------------------------------------------ /** * Permission filter for mercurial repositories. * * @author Sebastian Sdorra */ -@Priority(Filters.PRIORITY_AUTHORIZATION) -@WebElement(value = HgServletModule.MAPPING_HG) +//@Priority(Filters.PRIORITY_AUTHORIZATION) +//@WebElement(value = HgServletModule.MAPPING_HG) public class HgPermissionFilter extends ProviderPermissionFilter { diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java new file mode 100644 index 0000000000..c67c68024e --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java @@ -0,0 +1,15 @@ +package sonia.scm.web; + +import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; + +import javax.inject.Inject; +import javax.inject.Provider; +import javax.inject.Singleton; + +@Singleton +public class HgScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { + @Inject + public HgScmProtocolProviderWrapper(Provider servletProvider) { + super(servletProvider); + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java index 357995483d..ba9ae3a0b9 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java @@ -81,8 +81,5 @@ public class HgServletModule extends ServletModule // bind servlets serve(MAPPING_HOOK).with(HgHookCallbackServlet.class); - - // register hg cgi servlet - serve(MAPPING_HG).with(HgCGIServlet.class); } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java index cbd303a9c6..21d1659bec 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java @@ -41,7 +41,6 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.ScmProtocol; -import sonia.scm.web.SvnDAVServlet; import java.io.IOException; import java.util.Collections; @@ -69,14 +68,15 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider /** * Constructs ... * - * - * @param handler + * @param handler * @param repository + * @param httpScmProtocol */ SvnRepositoryServiceProvider(SvnRepositoryHandler handler, - Repository repository) + Repository repository, HttpScmProtocol httpScmProtocol) { this.repository = repository; + this.httpScmProtocol = httpScmProtocol; this.context = new SvnContext(handler.getDirectory(repository)); } @@ -194,7 +194,7 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider @Override public Set getSupportedProtocols() { - return Collections.singleton(new SvnDAVServlet(null, null, null, null)); + return Collections.singleton(httpScmProtocol); } //~--- fields --------------------------------------------------------------- @@ -204,4 +204,6 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider /** Field description */ private final Repository repository; + + private final HttpScmProtocol httpScmProtocol; } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java index d56398083e..48233156c6 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java @@ -35,10 +35,10 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import com.google.inject.Inject; - import sonia.scm.plugin.Extension; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; +import sonia.scm.web.SvnScmProtocolProviderWrapper; /** * @@ -58,11 +58,13 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver * * * @param handler + * @param httpScmProtocol */ @Inject - public SvnRepositoryServiceResolver(SvnRepositoryHandler handler) + public SvnRepositoryServiceResolver(SvnRepositoryHandler handler, SvnScmProtocolProviderWrapper httpScmProtocol) { this.handler = handler; + this.httpScmProtocol = httpScmProtocol; } //~--- methods -------------------------------------------------------------- @@ -82,7 +84,7 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver if (TYPE.equalsIgnoreCase(repository.getType())) { - provider = new SvnRepositoryServiceProvider(handler, repository); + provider = new SvnRepositoryServiceProvider(handler, repository, httpScmProtocol); } return provider; @@ -92,4 +94,6 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver /** Field description */ private SvnRepositoryHandler handler; + + private final HttpScmProtocol httpScmProtocol; } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnBasicAuthenticationFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnBasicAuthenticationFilter.java index 1d9581f7c1..b5db32a449 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnBasicAuthenticationFilter.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnBasicAuthenticationFilter.java @@ -34,30 +34,24 @@ package sonia.scm.web; //~--- non-JDK imports -------------------------------------------------------- import com.google.inject.Inject; - -import sonia.scm.Priority; import sonia.scm.config.ScmConfiguration; -import sonia.scm.filter.Filters; -import sonia.scm.filter.WebElement; import sonia.scm.repository.SvnUtil; import sonia.scm.util.HttpUtil; import sonia.scm.web.filter.AuthenticationFilter; -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - -import java.util.Set; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +//~--- JDK imports ------------------------------------------------------------ /** * * @author Sebastian Sdorra */ -@Priority(Filters.PRIORITY_AUTHENTICATION) -@WebElement(value = SvnServletModule.PATTERN_SVN) +//@Priority(Filters.PRIORITY_AUTHENTICATION) +//@WebElement(value = SvnServletModule.PATTERN_SVN) public class SvnBasicAuthenticationFilter extends AuthenticationFilter { diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java index 30ef3e94c0..857e3d6d71 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java @@ -37,32 +37,26 @@ package sonia.scm.web; import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; - import sonia.scm.ClientMessages; -import sonia.scm.Priority; import sonia.scm.config.ScmConfiguration; -import sonia.scm.filter.Filters; -import sonia.scm.filter.WebElement; import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.ScmSvnErrorCode; import sonia.scm.repository.SvnUtil; import sonia.scm.web.filter.ProviderPermissionFilter; -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - -import java.util.Set; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +//~--- JDK imports ------------------------------------------------------------ /** * * @author Sebastian Sdorra */ -@Priority(Filters.PRIORITY_AUTHORIZATION) -@WebElement(value = SvnServletModule.PATTERN_SVN) +//@Priority(Filters.PRIORITY_AUTHORIZATION) +//@WebElement(value = SvnServletModule.PATTERN_SVN) public class SvnPermissionFilter extends ProviderPermissionFilter { diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java new file mode 100644 index 0000000000..2f54f57bc8 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -0,0 +1,15 @@ +package sonia.scm.web; + +import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; + +import javax.inject.Inject; +import javax.inject.Provider; +import javax.inject.Singleton; + +@Singleton +public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { + @Inject + public SvnScmProtocolProviderWrapper(Provider servletProvider) { + super(servletProvider); + } +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java index 9b5c8ae556..4dab556c8f 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java @@ -70,8 +70,8 @@ public class SvnServletModule extends ServletModule protected void configureServlets() { filter(PATTERN_SVN).through(SvnGZipFilter.class); - filter(PATTERN_SVN).through(SvnBasicAuthenticationFilter.class); - filter(PATTERN_SVN).through(SvnPermissionFilter.class); +// filter(PATTERN_SVN).through(SvnBasicAuthenticationFilter.class); +// filter(PATTERN_SVN).through(SvnPermissionFilter.class); bind(SvnConfigDtoToSvnConfigMapper.class).to(Mappers.getMapper(SvnConfigDtoToSvnConfigMapper.class).getClass()); bind(SvnConfigToSvnConfigDtoMapper.class).to(Mappers.getMapper(SvnConfigToSvnConfigDtoMapper.class).getClass()); @@ -80,6 +80,5 @@ public class SvnServletModule extends ServletModule parameters.put(PARAMETER_SVN_PARENTPATH, System.getProperty("java.io.tmpdir")); - serve(PATTERN_SVN).with(SvnDAVServlet.class, parameters); } } diff --git a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java index 15536db19a..dc25875d5b 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java +++ b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java @@ -25,6 +25,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import static java.lang.Math.max; + @Singleton @WebElement(value = HttpProtocolServlet.PATTERN) @Slf4j @@ -79,7 +81,8 @@ public class HttpProtocolServlet extends HttpServlet { } String namespace = uri.substring(0, uri.indexOf(HttpUtil.SEPARATOR_PATH)); - String name = uri.substring(uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1, uri.indexOf(HttpUtil.SEPARATOR_PATH, uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1)); + int endIndex = uri.indexOf(HttpUtil.SEPARATOR_PATH, uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1); + String name = uri.substring(uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1, max(endIndex, uri.length())); return new NamespaceAndName(namespace, name); } From 40b9b0da69c2c465013afeea5ca04b7252e3c2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 7 Sep 2018 09:51:23 +0200 Subject: [PATCH 07/58] Initialize svn parent directory for servlet --- .../InitializingHttpScmProtocolWrapper.java | 6 ++- .../java/sonia/scm/web/SvnDAVServlet.java | 2 +- .../web/SvnScmProtocolProviderWrapper.java | 45 +++++++++++++++++++ .../java/sonia/scm/web/SvnServletModule.java | 8 ---- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index b06420d9c0..0e0e32dbf1 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -29,7 +29,7 @@ public abstract class InitializingHttpScmProtocolWrapper implements HttpScmProto synchronized (this) { if (!isInitialized) { HttpServlet httpServlet = delegateProvider.get(); - httpServlet.init(config); + initializeServlet(config, httpServlet); isInitialized = true; } } @@ -37,6 +37,10 @@ public abstract class InitializingHttpScmProtocolWrapper implements HttpScmProto delegateProvider.get().service(request, response); } + protected void initializeServlet(ServletConfig config, HttpServlet httpServlet) throws ServletException { + httpServlet.init(config); + } + @Override public String getUrl(Repository repository, UriInfo uriInfo) { diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java index 44c544bd68..0a2a63da46 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java @@ -294,7 +294,7 @@ public class SvnDAVServlet extends DAVServlet implements HttpScmProtocol @Override public String getUrl(Repository repository, UriInfo uriInfo) { - return uriInfo.getBaseUri().resolve(URI.create("../../svn/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); + return uriInfo.getBaseUri().resolve(URI.create("../../repo/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java index 2f54f57bc8..5544bf796e 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -5,6 +5,13 @@ import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import javax.inject.Inject; import javax.inject.Provider; import javax.inject.Singleton; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import java.util.Enumeration; + +import static sonia.scm.web.SvnServletModule.PARAMETER_SVN_PARENTPATH; @Singleton public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @@ -12,4 +19,42 @@ public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWr public SvnScmProtocolProviderWrapper(Provider servletProvider) { super(servletProvider); } + + @Override + protected void initializeServlet(ServletConfig config, HttpServlet httpServlet) throws ServletException { + + super.initializeServlet(new X(config), httpServlet); + } + + private static class X implements ServletConfig { + + private final ServletConfig originalConfig; + + private X(ServletConfig originalConfig) { + this.originalConfig = originalConfig; + } + + @Override + public String getServletName() { + return originalConfig.getServletName(); + } + + @Override + public ServletContext getServletContext() { + return originalConfig.getServletContext(); + } + + @Override + public String getInitParameter(String key) { + if (PARAMETER_SVN_PARENTPATH.equals(key)) { + return System.getProperty("java.io.tmpdir"); + } + return originalConfig.getInitParameter(key); + } + + @Override + public Enumeration getInitParameterNames() { + return originalConfig.getInitParameterNames(); + } + } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java index 4dab556c8f..9b9dc0bcb0 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java @@ -41,9 +41,6 @@ import sonia.scm.api.v2.resources.SvnConfigDtoToSvnConfigMapper; import sonia.scm.api.v2.resources.SvnConfigToSvnConfigDtoMapper; import sonia.scm.plugin.Extension; -import java.util.HashMap; -import java.util.Map; - //~--- JDK imports ------------------------------------------------------------ /** @@ -75,10 +72,5 @@ public class SvnServletModule extends ServletModule bind(SvnConfigDtoToSvnConfigMapper.class).to(Mappers.getMapper(SvnConfigDtoToSvnConfigMapper.class).getClass()); bind(SvnConfigToSvnConfigDtoMapper.class).to(Mappers.getMapper(SvnConfigToSvnConfigDtoMapper.class).getClass()); - - Map parameters = new HashMap(); - - parameters.put(PARAMETER_SVN_PARENTPATH, - System.getProperty("java.io.tmpdir")); } } From eff51c3b378182e698eeef8c9998257fa7b649e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 10 Sep 2018 08:34:47 +0200 Subject: [PATCH 08/58] Remove not thrown exceptions from declaration --- .../src/main/java/sonia/scm/web/HgCGIServlet.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index 3ceb129f3f..03acc3bc29 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -148,7 +148,6 @@ public class HgCGIServlet extends HttpServlet implements HttpScmProtocol @Override protected void service(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { Repository repository = repositoryProvider.get(); @@ -351,7 +350,7 @@ public class HgCGIServlet extends HttpServlet implements HttpScmProtocol } @Override - public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException { + public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) { service(request, response); } From 9198cac0a554853ed4607d474d6ea08a47bed3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 10 Sep 2018 08:36:05 +0200 Subject: [PATCH 09/58] Correct usage of RepositoryNotFoundException --- .../sonia/scm/repository/RepositoryNotFoundException.java | 4 ++++ .../sonia/scm/repository/api/RepositoryServiceFactory.java | 4 +--- .../sonia/scm/api/v2/resources/PermissionRootResource.java | 5 +++-- .../src/main/java/sonia/scm/repository/HealthChecker.java | 3 +-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryNotFoundException.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryNotFoundException.java index 070221117a..1208596348 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryNotFoundException.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryNotFoundException.java @@ -61,4 +61,8 @@ public class RepositoryNotFoundException extends NotFoundException public RepositoryNotFoundException(String repositoryId) { super("repository", repositoryId); } + + public RepositoryNotFoundException(NamespaceAndName namespaceAndName) { + super("repository", namespaceAndName.toString()); + } } diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java index 627e57a797..33f57d4524 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java @@ -208,9 +208,7 @@ public final class RepositoryServiceFactory if (repository == null) { - String msg = "could not find a repository with namespace/name " + namespaceAndName; - - throw new RepositoryNotFoundException(msg); + throw new RepositoryNotFoundException(namespaceAndName); } return create(repository); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionRootResource.java index 2b53192542..7f15120357 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PermissionRootResource.java @@ -210,8 +210,9 @@ public class PermissionRootResource { * @throws RepositoryNotFoundException if the repository does not exists */ private Repository load(String namespace, String name) throws RepositoryNotFoundException { - return Optional.ofNullable(manager.get(new NamespaceAndName(namespace, name))) - .orElseThrow(() -> new RepositoryNotFoundException(name)); + NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name); + return Optional.ofNullable(manager.get(namespaceAndName)) + .orElseThrow(() -> new RepositoryNotFoundException(namespaceAndName)); } /** diff --git a/scm-webapp/src/main/java/sonia/scm/repository/HealthChecker.java b/scm-webapp/src/main/java/sonia/scm/repository/HealthChecker.java index 0d27c6d250..52dea4223b 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/HealthChecker.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/HealthChecker.java @@ -61,8 +61,7 @@ public final class HealthChecker { Repository repository = repositoryManager.get(id); if (repository == null) { - throw new RepositoryNotFoundException( - "could not find repository with id ".concat(id)); + throw new RepositoryNotFoundException(id); } doCheck(repository); From 6d659b8ac104740df4dce2a0c773ddabaa6ef307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 10 Sep 2018 08:37:31 +0200 Subject: [PATCH 10/58] Correct extraction of namespace and name from path --- .../scm/web/protocol/HttpProtocolServlet.java | 60 ++++----- .../NamespaceAndNameFromPathExtractor.java | 33 +++++ .../web/protocol/HttpProtocolServletTest.java | 124 ++++++++++++++++++ ...NamespaceAndNameFromPathExtractorTest.java | 59 +++++++++ 4 files changed, 241 insertions(+), 35 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java create mode 100644 scm-webapp/src/test/java/sonia/scm/web/protocol/HttpProtocolServletTest.java create mode 100644 scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java diff --git a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java index dc25875d5b..d314628438 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java +++ b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java @@ -1,31 +1,27 @@ package sonia.scm.web.protocol; import com.google.inject.Inject; -import com.google.inject.Provider; import com.google.inject.Singleton; import lombok.extern.slf4j.Slf4j; -import org.apache.shiro.SecurityUtils; -import org.apache.shiro.subject.Subject; +import org.apache.http.HttpStatus; import sonia.scm.PushStateDispatcher; import sonia.scm.filter.WebElement; import sonia.scm.repository.DefaultRepositoryProvider; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.RepositoryNotFoundException; -import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.repository.spi.HttpScmProtocol; -import sonia.scm.util.HttpUtil; import sonia.scm.web.UserAgent; import sonia.scm.web.UserAgentParser; +import javax.inject.Provider; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; - -import static java.lang.Math.max; +import java.util.Optional; @Singleton @WebElement(value = HttpProtocolServlet.PATTERN) @@ -34,7 +30,6 @@ public class HttpProtocolServlet extends HttpServlet { public static final String PATTERN = "/repo/*"; - private final RepositoryProvider repositoryProvider; private final RepositoryServiceFactory serviceFactory; private final Provider requestProvider; @@ -42,48 +37,43 @@ public class HttpProtocolServlet extends HttpServlet { private final PushStateDispatcher dispatcher; private final UserAgentParser userAgentParser; + private final NamespaceAndNameFromPathExtractor namespaceAndNameFromPathExtractor; + @Inject - public HttpProtocolServlet(RepositoryProvider repositoryProvider, RepositoryServiceFactory serviceFactory, Provider requestProvider, PushStateDispatcher dispatcher, UserAgentParser userAgentParser) { - this.repositoryProvider = repositoryProvider; + public HttpProtocolServlet(RepositoryServiceFactory serviceFactory, Provider requestProvider, PushStateDispatcher dispatcher, UserAgentParser userAgentParser, NamespaceAndNameFromPathExtractor namespaceAndNameFromPathExtractor) { this.serviceFactory = serviceFactory; this.requestProvider = requestProvider; this.dispatcher = dispatcher; this.userAgentParser = userAgentParser; + this.namespaceAndNameFromPathExtractor = namespaceAndNameFromPathExtractor; } @Override - protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - Subject subject = SecurityUtils.getSubject(); - - - UserAgent userAgent = userAgentParser.parse(req); + protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + UserAgent userAgent = userAgentParser.parse(request); if (userAgent.isBrowser()) { log.trace("dispatch browser request for user agent {}", userAgent); - dispatcher.dispatch(req, resp, req.getRequestURI()); + dispatcher.dispatch(request, response, request.getRequestURI()); } else { - - - String pathInfo = req.getPathInfo(); - NamespaceAndName namespaceAndName = fromUri(pathInfo); - try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) { - requestProvider.get().setAttribute(DefaultRepositoryProvider.ATTRIBUTE_NAME, repositoryService.getRepository()); - HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class); - protocol.serve(req, resp, getServletConfig()); - } catch (RepositoryNotFoundException e) { - resp.setStatus(404); + String pathInfo = request.getPathInfo(); + Optional namespaceAndName = namespaceAndNameFromPathExtractor.fromUri(pathInfo); + if (namespaceAndName.isPresent()) { + service(request, response, namespaceAndName.get()); + } else { + log.debug("namespace and name not found in request path {}", pathInfo); + response.setStatus(HttpStatus.SC_BAD_REQUEST); } } } - private NamespaceAndName fromUri(String uri) { - if (uri.startsWith(HttpUtil.SEPARATOR_PATH)) { - uri = uri.substring(1); + private void service(HttpServletRequest req, HttpServletResponse resp, NamespaceAndName namespaceAndName) throws IOException, ServletException { + try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) { + requestProvider.get().setAttribute(DefaultRepositoryProvider.ATTRIBUTE_NAME, repositoryService.getRepository()); + HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class); + protocol.serve(req, resp, getServletConfig()); + } catch (RepositoryNotFoundException e) { + log.debug("Repository not found for namespace and name {}", namespaceAndName, e); + resp.setStatus(HttpStatus.SC_NOT_FOUND); } - - String namespace = uri.substring(0, uri.indexOf(HttpUtil.SEPARATOR_PATH)); - int endIndex = uri.indexOf(HttpUtil.SEPARATOR_PATH, uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1); - String name = uri.substring(uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1, max(endIndex, uri.length())); - - return new NamespaceAndName(namespace, name); } } diff --git a/scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java b/scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java new file mode 100644 index 0000000000..b4315bc6ac --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java @@ -0,0 +1,33 @@ +package sonia.scm.web.protocol; + +import sonia.scm.repository.NamespaceAndName; +import sonia.scm.util.HttpUtil; + +import java.util.Optional; + +import static java.util.Optional.empty; +import static java.util.Optional.of; + +class NamespaceAndNameFromPathExtractor { + Optional fromUri(String uri) { + if (uri.startsWith(HttpUtil.SEPARATOR_PATH)) { + uri = uri.substring(1); + } + + int endOfNamespace = uri.indexOf(HttpUtil.SEPARATOR_PATH); + if (endOfNamespace < 1) { + return empty(); + } + + String namespace = uri.substring(0, endOfNamespace); + int nameSeparatorIndex = uri.indexOf(HttpUtil.SEPARATOR_PATH, endOfNamespace + 1); + int nameIndex = nameSeparatorIndex > 0 ? nameSeparatorIndex : uri.length(); + if (nameIndex == endOfNamespace + 1) { + return empty(); + } + + String name = uri.substring(endOfNamespace + 1, nameIndex); + + return of(new NamespaceAndName(namespace, name)); + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/web/protocol/HttpProtocolServletTest.java b/scm-webapp/src/test/java/sonia/scm/web/protocol/HttpProtocolServletTest.java new file mode 100644 index 0000000000..2d4f6b639b --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/web/protocol/HttpProtocolServletTest.java @@ -0,0 +1,124 @@ +package sonia.scm.web.protocol; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import sonia.scm.PushStateDispatcher; +import sonia.scm.repository.DefaultRepositoryProvider; +import sonia.scm.repository.NamespaceAndName; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryNotFoundException; +import sonia.scm.repository.api.RepositoryService; +import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.repository.spi.HttpScmProtocol; +import sonia.scm.web.UserAgent; +import sonia.scm.web.UserAgentParser; + +import javax.inject.Provider; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Optional; + +import static java.util.Optional.of; +import static org.mockito.AdditionalMatchers.not; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +public class HttpProtocolServletTest { + + private static final NamespaceAndName EXISTING_REPO = new NamespaceAndName("space", "repo"); + + @Mock + private RepositoryServiceFactory serviceFactory; + @Mock + private HttpServletRequest httpServletRequest; + @Mock + private PushStateDispatcher dispatcher; + @Mock + private UserAgentParser userAgentParser; + @Mock + private NamespaceAndNameFromPathExtractor namespaceAndNameFromPathExtractor; + @Mock + private Provider requestProvider; + + @InjectMocks + private HttpProtocolServlet servlet; + + @Mock + private RepositoryService repositoryService; + @Mock + private UserAgent userAgent; + + @Mock + private HttpServletRequest request; + @Mock + private HttpServletResponse response; + @Mock + private HttpScmProtocol protocol; + + @Before + public void init() throws RepositoryNotFoundException { + initMocks(this); + when(userAgentParser.parse(request)).thenReturn(userAgent); + when(userAgent.isBrowser()).thenReturn(false); + when(serviceFactory.create(not(eq(EXISTING_REPO)))).thenThrow(RepositoryNotFoundException.class); + when(serviceFactory.create(EXISTING_REPO)).thenReturn(repositoryService); + when(requestProvider.get()).thenReturn(httpServletRequest); + } + + @Test + public void shouldDispatchBrowserRequests() throws ServletException, IOException { + when(userAgent.isBrowser()).thenReturn(true); + when(request.getRequestURI()).thenReturn("uri"); + + servlet.service(request, response); + + verify(dispatcher).dispatch(request, response, "uri"); + } + + @Test + public void shouldHandleBadPaths() throws IOException, ServletException { + when(request.getPathInfo()).thenReturn("/space/name"); + when(namespaceAndNameFromPathExtractor.fromUri("/space/name")).thenReturn(Optional.empty()); + + servlet.service(request, response); + + verify(response).setStatus(400); + } + + @Test + public void shouldHandleNotExistingRepository() throws RepositoryNotFoundException, IOException, ServletException { + when(request.getPathInfo()).thenReturn("/space/name"); + NamespaceAndName namespaceAndName = new NamespaceAndName("space", "name"); + when(namespaceAndNameFromPathExtractor.fromUri("/space/name")).thenReturn(of(namespaceAndName)); + doThrow(new RepositoryNotFoundException(namespaceAndName)).when(serviceFactory).create(namespaceAndName); + + servlet.service(request, response); + + verify(response).setStatus(404); + } + + @Test + public void shouldDelegateToProvider() throws RepositoryNotFoundException, IOException, ServletException { + when(request.getPathInfo()).thenReturn("/space/name"); + NamespaceAndName namespaceAndName = new NamespaceAndName("space", "name"); + when(namespaceAndNameFromPathExtractor.fromUri("/space/name")).thenReturn(of(namespaceAndName)); + doReturn(repositoryService).when(serviceFactory).create(namespaceAndName); + Repository repository = new Repository(); + when(repositoryService.getRepository()).thenReturn(repository); + when(repositoryService.getProtocol(HttpScmProtocol.class)).thenReturn(protocol); + + servlet.service(request, response); + + verify(httpServletRequest).setAttribute(DefaultRepositoryProvider.ATTRIBUTE_NAME, repository); + verify(protocol).serve(request, response, null); + verify(repositoryService).close(); + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java b/scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java new file mode 100644 index 0000000000..be26ac89db --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java @@ -0,0 +1,59 @@ +package sonia.scm.web.protocol; + +import org.junit.jupiter.api.DynamicNode; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; +import sonia.scm.repository.NamespaceAndName; + +import java.util.Optional; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.DynamicTest.dynamicTest; + +public class NamespaceAndNameFromPathExtractorTest { + @TestFactory + Stream shouldExtractCorrectNamespaceAndName() { + return Stream.of( + "/space/repo", + "/space/repo/", + "/space/repo/here", + "/space/repo/here/there", + "space/repo", + "space/repo/", + "space/repo/here/there" + ).map(this::createCorrectTest); + } + + private DynamicTest createCorrectTest(String path) { + return dynamicTest( + "should extract correct namespace and name for path " + path, + () -> { + Optional namespaceAndName = new NamespaceAndNameFromPathExtractor().fromUri(path); + + assertThat(namespaceAndName.get()).isEqualTo(new NamespaceAndName("space", "repo")); + } + ); + } + + @TestFactory + Stream shouldHandleMissingParts() { + return Stream.of( + "", + "/", + "/space", + "/space/" + ).map(this::createFailureTest); + } + + private DynamicTest createFailureTest(String path) { + return dynamicTest( + "should not fail for wrong path " + path, + () -> { + Optional namespaceAndName = new NamespaceAndNameFromPathExtractor().fromUri(path); + + assertThat(namespaceAndName.isPresent()).isFalse(); + } + ); + } +} From 50a4133dff68ca2e350ca0ce346f228f3f092813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 10 Sep 2018 10:08:51 +0200 Subject: [PATCH 11/58] Remove old type dependant repo uri functions --- .../scm/repository/RepositoryManager.java | 24 ------- .../RepositoryManagerDecorator.java | 29 --------- .../spi/DefaultHttpScmProtocol.java | 8 --- .../scm/repository/spi/HttpScmProtocol.java | 8 +++ .../InitializingHttpScmProtocolWrapper.java | 10 --- .../repository/api/RepositoryServiceTest.java | 16 ----- .../lfs/servlet/LfsServletFactoryTest.java | 10 ++- .../main/java/sonia/scm/web/HgCGIServlet.java | 7 --- .../java/sonia/scm/web/SvnDAVServlet.java | 8 --- .../scm/api/v2/resources/ResourceLinks.java | 1 + .../repository/DefaultRepositoryManager.java | 27 -------- .../DefaultRepositoryManagerTest.java | 63 ------------------- 12 files changed, 13 insertions(+), 198 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java index 2c4d958d8d..1e2fdccf42 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java @@ -38,7 +38,6 @@ package sonia.scm.repository; import sonia.scm.AlreadyExistsException; import sonia.scm.TypeManager; -import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Collection; @@ -99,29 +98,6 @@ public interface RepositoryManager */ public Collection getConfiguredTypes(); - /** - * Returns the {@link Repository} associated to the request uri. - * - * - * @param request the current http request - * - * @return associated to the request uri - * @since 1.9 - */ - public Repository getFromRequest(HttpServletRequest request); - - /** - * Returns the {@link Repository} associated to the request uri. - * - * - * - * @param uri request uri without context path - * - * @return associated to the request uri - * @since 1.9 - */ - public Repository getFromUri(String uri); - /** * Returns a {@link RepositoryHandler} by the given type (hg, git, svn ...). * diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.java index aa4117af34..87df960da7 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.java @@ -39,7 +39,6 @@ import sonia.scm.AlreadyExistsException; import sonia.scm.ManagerDecorator; import sonia.scm.Type; -import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Collection; @@ -120,34 +119,6 @@ public class RepositoryManagerDecorator return decorated; } - /** - * {@inheritDoc} - * - * - * @param request - * - * @return - */ - @Override - public Repository getFromRequest(HttpServletRequest request) - { - return decorated.getFromRequest(request); - } - - /** - * {@inheritDoc} - * - * - * @param uri - * - * @return - */ - @Override - public Repository getFromUri(String uri) - { - return decorated.getFromUri(uri); - } - /** * {@inheritDoc} * diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java index 223be7aca8..9aaf1dfb4b 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java @@ -2,9 +2,6 @@ package sonia.scm.repository.spi; import sonia.scm.repository.Repository; -import javax.ws.rs.core.UriInfo; -import java.net.URI; - public abstract class DefaultHttpScmProtocol implements HttpScmProtocol { private final Repository repository; @@ -12,9 +9,4 @@ public abstract class DefaultHttpScmProtocol implements HttpScmProtocol { protected DefaultHttpScmProtocol(Repository repository) { this.repository = repository; } - - @Override - public String getUrl(Repository repository, UriInfo uriInfo) { - return uriInfo.getBaseUri().resolve(URI.create("../../" + this.repository.getType() + "/" + this.repository.getNamespace() + "/" + this.repository.getName())).toASCIIString(); - } } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java index c19205c1e7..fed9c00cdc 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java @@ -1,12 +1,15 @@ package sonia.scm.repository.spi; +import sonia.scm.repository.Repository; import sonia.scm.repository.api.ScmProtocol; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.UriInfo; import java.io.IOException; +import java.net.URI; public interface HttpScmProtocol extends ScmProtocol { @Override @@ -14,5 +17,10 @@ public interface HttpScmProtocol extends ScmProtocol { return "http"; } + @Override + default String getUrl(Repository repository, UriInfo uriInfo) { + return uriInfo.getBaseUri().resolve(URI.create("../../repo/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); + } + void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException; } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 0e0e32dbf1..9c26c0905a 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -1,16 +1,12 @@ package sonia.scm.repository.spi; -import sonia.scm.repository.Repository; - import javax.inject.Provider; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.UriInfo; import java.io.IOException; -import java.net.URI; public abstract class InitializingHttpScmProtocolWrapper implements HttpScmProtocol { @@ -40,10 +36,4 @@ public abstract class InitializingHttpScmProtocolWrapper implements HttpScmProto protected void initializeServlet(ServletConfig config, HttpServlet httpServlet) throws ServletException { httpServlet.init(config); } - - - @Override - public String getUrl(Repository repository, UriInfo uriInfo) { - return uriInfo.getBaseUri().resolve(URI.create("../../repo/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); - } } diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java index 8d37c0e187..b363516a67 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java @@ -8,7 +8,6 @@ import sonia.scm.repository.spi.RepositoryServiceProvider; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.UriInfo; import java.util.Collection; import java.util.Collections; @@ -33,16 +32,6 @@ public class RepositoryServiceTest { assertThat(sizeOf(supportedProtocols)).isEqualTo(1); } - @Test - public void shouldFindProtocolFromProvider() { - when(provider.getSupportedProtocols()).thenReturn(Collections.singleton(new DummyHttpProtocol())); - - RepositoryService repositoryService = new RepositoryService(null, provider, repository, null); - HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class); - - assertThat(protocol.getUrl(repository, null)).isEqualTo("dummy"); - } - @Test public void shouldFailForUnknownProtocol() { when(provider.getSupportedProtocols()).thenReturn(Collections.emptySet()); @@ -55,11 +44,6 @@ public class RepositoryServiceTest { } private static class DummyHttpProtocol implements HttpScmProtocol { - @Override - public String getUrl(Repository repository, UriInfo uriInfo) { - return "dummy"; - } - @Override public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) { } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/lfs/servlet/LfsServletFactoryTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/lfs/servlet/LfsServletFactoryTest.java index f6f5803bb7..09a431ea43 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/lfs/servlet/LfsServletFactoryTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/lfs/servlet/LfsServletFactoryTest.java @@ -23,12 +23,12 @@ public class LfsServletFactoryTest { String repositoryName = "git-lfs-demo"; String result = LfsServletFactory.buildBaseUri(new Repository("", "GIT", repositoryNamespace, repositoryName), RequestWithUri(repositoryName, true)); - assertThat(result, is(equalTo("http://localhost:8081/scm/git/space/git-lfs-demo.git/info/lfs/objects/"))); + assertThat(result, is(equalTo("http://localhost:8081/scm/repo/space/git-lfs-demo.git/info/lfs/objects/"))); //result will be with dot-git suffix, ide result = LfsServletFactory.buildBaseUri(new Repository("", "GIT", repositoryNamespace, repositoryName), RequestWithUri(repositoryName, false)); - assertThat(result, is(equalTo("http://localhost:8081/scm/git/space/git-lfs-demo.git/info/lfs/objects/"))); + assertThat(result, is(equalTo("http://localhost:8081/scm/repo/space/git-lfs-demo.git/info/lfs/objects/"))); } private HttpServletRequest RequestWithUri(String repositoryName, boolean withDotGitSuffix) { @@ -44,12 +44,10 @@ public class LfsServletFactoryTest { //build from valid live request data when(mockedRequest.getRequestURL()).thenReturn( - new StringBuffer(String.format("http://localhost:8081/scm/git/%s%s/info/lfs/objects/batch", repositoryName, suffix))); - when(mockedRequest.getRequestURI()).thenReturn(String.format("/scm/git/%s%s/info/lfs/objects/batch", repositoryName, suffix)); + new StringBuffer(String.format("http://localhost:8081/scm/repo/%s%s/info/lfs/objects/batch", repositoryName, suffix))); + when(mockedRequest.getRequestURI()).thenReturn(String.format("/scm/repo/%s%s/info/lfs/objects/batch", repositoryName, suffix)); when(mockedRequest.getContextPath()).thenReturn("/scm"); return mockedRequest; } - - } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index 03acc3bc29..b124c9d3af 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -65,10 +65,8 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import javax.ws.rs.core.UriInfo; import java.io.File; import java.io.IOException; -import java.net.URI; import java.util.Base64; import java.util.Enumeration; @@ -354,11 +352,6 @@ public class HgCGIServlet extends HttpServlet implements HttpScmProtocol service(request, response); } - @Override - public String getUrl(Repository repository, UriInfo uriInfo) { - return uriInfo.getBaseUri().resolve(URI.create("../../hg/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); - } - //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java index 0a2a63da46..0dda4306c6 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java @@ -54,9 +54,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.UriInfo; import java.io.IOException; -import java.net.URI; //~--- JDK imports ------------------------------------------------------------ @@ -292,12 +290,6 @@ public class SvnDAVServlet extends DAVServlet implements HttpScmProtocol service(request, response); } - @Override - public String getUrl(Repository repository, UriInfo uriInfo) { - return uriInfo.getBaseUri().resolve(URI.create("../../repo/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); - } - - //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java index 5fe2a2cfd2..11258745a8 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java @@ -4,6 +4,7 @@ import sonia.scm.repository.NamespaceAndName; import javax.inject.Inject; import javax.ws.rs.core.UriInfo; +import java.net.URI; class ResourceLinks { diff --git a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java index 06f92f7bec..8638c7e4e8 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java @@ -52,11 +52,9 @@ import sonia.scm.config.ScmConfiguration; import sonia.scm.security.KeyGenerator; import sonia.scm.util.AssertUtil; import sonia.scm.util.CollectionAppender; -import sonia.scm.util.HttpUtil; import sonia.scm.util.IOUtil; import sonia.scm.util.Util; -import javax.servlet.http.HttpServletRequest; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -315,31 +313,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager { return validTypes; } - @Override - public Repository getFromRequest(HttpServletRequest request) { - AssertUtil.assertIsNotNull(request); - - return getFromUri(HttpUtil.getStrippedURI(request)); - } - - @Override - public Repository getFromUri(String uri) { - AssertUtil.assertIsNotEmpty(uri); - - if (uri.startsWith(HttpUtil.SEPARATOR_PATH)) { - uri = uri.substring(1); - } - - Repository repository = null; - - String namespace = uri.substring(0, uri.indexOf(HttpUtil.SEPARATOR_PATH)); - String name = uri.substring(uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1, uri.indexOf(HttpUtil.SEPARATOR_PATH, uri.indexOf(HttpUtil.SEPARATOR_PATH) + 1)); - - repository = get(new NamespaceAndName(namespace, name)); - - return repository; - } - @Override public RepositoryHandler getHandler(String type) { return handlerMap.get(type); diff --git a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java index efd3f673b0..d85ce12014 100644 --- a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java @@ -383,69 +383,6 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase { assertEquals("default_namespace", repository.getNamespace()); } - @Test - public void getRepositoryFromRequestUri_withoutLeadingSlash() throws AlreadyExistsException { - RepositoryManager m = createManager(); - m.init(contextProvider); - - createUriTestRepositories(m); - - assertEquals("scm-test", m.getFromUri("hg/namespace/scm-test").getName()); - assertEquals("namespace", m.getFromUri("hg/namespace/scm-test").getNamespace()); - } - - @Test - public void getRepositoryFromRequestUri_withLeadingSlash() throws AlreadyExistsException { - RepositoryManager m = createManager(); - m.init(contextProvider); - - createUriTestRepositories(m); - - assertEquals("scm-test", m.getFromUri("/hg/namespace/scm-test").getName()); - assertEquals("namespace", m.getFromUri("/hg/namespace/scm-test").getNamespace()); - } - - @Test - public void getRepositoryFromRequestUri_withPartialName() throws AlreadyExistsException { - RepositoryManager m = createManager(); - m.init(contextProvider); - - createUriTestRepositories(m); - - assertEquals("scm", m.getFromUri("hg/namespace/scm").getName()); - assertEquals("namespace", m.getFromUri("hg/namespace/scm").getNamespace()); - } - - @Test - public void getRepositoryFromRequestUri_withTrailingFilePath() throws AlreadyExistsException { - RepositoryManager m = createManager(); - m.init(contextProvider); - - createUriTestRepositories(m); - - assertEquals("test-1", m.getFromUri("/git/namespace/test-1/ka/some/path").getName()); - } - - @Test - public void getRepositoryFromRequestUri_forNotExistingRepositoryName() throws AlreadyExistsException { - RepositoryManager m = createManager(); - m.init(contextProvider); - - createUriTestRepositories(m); - - assertNull(m.getFromUri("/git/namespace/test-3/ka/some/path")); - } - - @Test - public void getRepositoryFromRequestUri_forWrongNamespace() throws AlreadyExistsException { - RepositoryManager m = createManager(); - m.init(contextProvider); - - createUriTestRepositories(m); - - assertNull(m.getFromUri("/git/other/other/test-2")); - } - @Test public void shouldSetNamespace() throws AlreadyExistsException { Repository repository = new Repository(null, "hg", null, "scm"); From 6bc41cee0ab3a4e1d0af6e3e344bede9a2622164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 10 Sep 2018 11:03:10 +0200 Subject: [PATCH 12/58] Handle git urls with trailing .git suffix correctly --- .../java/sonia/scm/api/v2/resources/RepositoryDto.java | 2 +- .../web/protocol/NamespaceAndNameFromPathExtractor.java | 7 ++++++- .../protocol/NamespaceAndNameFromPathExtractorTest.java | 9 +++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryDto.java index c597e12d4f..ddfe432d73 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryDto.java @@ -24,7 +24,7 @@ public class RepositoryDto extends HalRepresentation { @JsonInclude(JsonInclude.Include.NON_NULL) private Instant lastModified; private String namespace; - @Pattern(regexp = "(?!^\\.\\.$)(?!^\\.$)(?!.*[\\\\\\[\\]])^[A-z0-9\\.][A-z0-9\\.\\-_/]*$") + @Pattern(regexp = "^[A-z0-9\\-_]+$") private String name; private boolean archived = false; @NotEmpty diff --git a/scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java b/scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java index b4315bc6ac..8cbdadf942 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java +++ b/scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java @@ -28,6 +28,11 @@ class NamespaceAndNameFromPathExtractor { String name = uri.substring(endOfNamespace + 1, nameIndex); - return of(new NamespaceAndName(namespace, name)); + int nameDotIndex = name.indexOf('.'); + if (nameDotIndex >= 0) { + return of(new NamespaceAndName(namespace, name.substring(0, nameDotIndex))); + } else { + return of(new NamespaceAndName(namespace, name)); + } } } diff --git a/scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java b/scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java index be26ac89db..3018870e7d 100644 --- a/scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java +++ b/scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java @@ -25,6 +25,15 @@ public class NamespaceAndNameFromPathExtractorTest { ).map(this::createCorrectTest); } + @TestFactory + Stream shouldHandleTrailingDotSomethings() { + return Stream.of( + "/space/repo.git", + "/space/repo.and.more", + "/space/repo." + ).map(this::createCorrectTest); + } + private DynamicTest createCorrectTest(String path) { return dynamicTest( "should extract correct namespace and name for path " + path, From 8c675f5dd873bc35e45ff9a7a68ed2b8b39d3730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 10 Sep 2018 11:59:21 +0200 Subject: [PATCH 13/58] Compute base url in webapp --- .../src/main/java/sonia/scm/repository/api/ScmProtocol.java | 4 ++-- .../main/java/sonia/scm/repository/spi/HttpScmProtocol.java | 5 ++--- scm-webapp/src/main/java/sonia/scm/ScmServletModule.java | 3 ++- .../api/v2/resources/RepositoryToRepositoryDtoMapper.java | 2 +- .../java/sonia/scm/web/protocol/HttpProtocolServlet.java | 3 ++- .../java/sonia/scm/api/v2/resources/MockScmProtocol.java | 4 ++-- .../scm/api/v2/resources/RepositoryRootResourceTest.java | 5 +++++ .../v2/resources/RepositoryToRepositoryDtoMapperTest.java | 5 +++++ 8 files changed, 21 insertions(+), 10 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java index 8d44ec19ad..0d9e1ae88e 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java @@ -2,7 +2,7 @@ package sonia.scm.repository.api; import sonia.scm.repository.Repository; -import javax.ws.rs.core.UriInfo; +import java.net.URI; /** * An ScmProtocol represents a concrete protocol provided by the SCM-Manager instance @@ -19,5 +19,5 @@ public interface ScmProtocol { /** * The URL to access the repository providing this protocol. */ - String getUrl(Repository repository, UriInfo uriInfo); + String getUrl(Repository repository, URI baseUri); } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java index fed9c00cdc..69952802fd 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java @@ -7,7 +7,6 @@ import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.net.URI; @@ -18,8 +17,8 @@ public interface HttpScmProtocol extends ScmProtocol { } @Override - default String getUrl(Repository repository, UriInfo uriInfo) { - return uriInfo.getBaseUri().resolve(URI.create("../../repo/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); + default String getUrl(Repository repository, URI baseUri) { + return baseUri.resolve(URI.create("/repo" + "/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); } void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException; diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java index 2ea17e9da3..14fb8552f9 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java @@ -114,6 +114,7 @@ import sonia.scm.web.cgi.CGIExecutorFactory; import sonia.scm.web.cgi.DefaultCGIExecutorFactory; import sonia.scm.web.filter.AuthenticationFilter; import sonia.scm.web.filter.LoggingFilter; +import sonia.scm.web.protocol.HttpProtocolServlet; import sonia.scm.web.security.AdministrationContext; import sonia.scm.web.security.DefaultAdministrationContext; @@ -322,7 +323,7 @@ public class ScmServletModule extends ServletModule bind(TemplateEngineFactory.class); bind(ObjectMapper.class).toProvider(ObjectMapperProvider.class); - filter("/repo/*").through(AuthenticationFilter.class); + filter(HttpProtocolServlet.PATTERN).through(AuthenticationFilter.class); // bind events // bind(LastModifiedUpdateListener.class); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java index bc0073506e..62d7abedf7 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java @@ -67,6 +67,6 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper Date: Mon, 10 Sep 2018 14:00:13 +0200 Subject: [PATCH 14/58] Inject repository from service provider --- .../sonia/scm/repository/api/ScmProtocol.java | 4 +- .../spi/DefaultHttpScmProtocol.java | 12 ------ .../scm/repository/spi/HttpScmProtocol.java | 17 +++++--- .../InitializingHttpScmProtocolWrapper.java | 43 ++++++++++++------- .../repository/api/RepositoryServiceTest.java | 8 +++- .../spi/GitRepositoryServiceResolver.java | 8 ++-- .../spi/HgRepositoryServiceProvider.java | 10 ----- .../spi/HgRepositoryServiceResolver.java | 8 ++-- .../main/java/sonia/scm/web/HgCGIServlet.java | 5 +-- .../spi/SvnRepositoryServiceResolver.java | 10 ++--- .../java/sonia/scm/web/SvnDAVServlet.java | 5 +-- .../RepositoryToRepositoryDtoMapper.java | 2 +- .../scm/api/v2/resources/MockScmProtocol.java | 3 +- 13 files changed, 66 insertions(+), 69 deletions(-) delete mode 100644 scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java index 0d9e1ae88e..b865d6e55b 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java @@ -1,7 +1,5 @@ package sonia.scm.repository.api; -import sonia.scm.repository.Repository; - import java.net.URI; /** @@ -19,5 +17,5 @@ public interface ScmProtocol { /** * The URL to access the repository providing this protocol. */ - String getUrl(Repository repository, URI baseUri); + String getUrl(URI baseUri); } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java deleted file mode 100644 index 9aaf1dfb4b..0000000000 --- a/scm-core/src/main/java/sonia/scm/repository/spi/DefaultHttpScmProtocol.java +++ /dev/null @@ -1,12 +0,0 @@ -package sonia.scm.repository.spi; - -import sonia.scm.repository.Repository; - -public abstract class DefaultHttpScmProtocol implements HttpScmProtocol { - - private final Repository repository; - - protected DefaultHttpScmProtocol(Repository repository) { - this.repository = repository; - } -} diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java index 69952802fd..310b663d5d 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java @@ -10,16 +10,23 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URI; -public interface HttpScmProtocol extends ScmProtocol { +public abstract class HttpScmProtocol implements ScmProtocol { + + private final Repository repository; + + public HttpScmProtocol(Repository repository) { + this.repository = repository; + } + @Override - default String getType() { + public String getType() { return "http"; } @Override - default String getUrl(Repository repository, URI baseUri) { - return baseUri.resolve(URI.create("/repo" + "/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); + public String getUrl(URI baseUri) { + return baseUri.resolve(URI.create("repo" + "/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); } - void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException; + public abstract void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException; } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 9c26c0905a..b83386a380 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -1,5 +1,7 @@ package sonia.scm.repository.spi; +import sonia.scm.repository.Repository; + import javax.inject.Provider; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -8,7 +10,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -public abstract class InitializingHttpScmProtocolWrapper implements HttpScmProtocol { +public abstract class InitializingHttpScmProtocolWrapper { private final Provider delegateProvider; @@ -19,21 +21,32 @@ public abstract class InitializingHttpScmProtocolWrapper implements HttpScmProto this.delegateProvider = delegateProvider; } - @Override - public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException { - if (!isInitialized) { - synchronized (this) { - if (!isInitialized) { - HttpServlet httpServlet = delegateProvider.get(); - initializeServlet(config, httpServlet); - isInitialized = true; - } - } - } - delegateProvider.get().service(request, response); - } - protected void initializeServlet(ServletConfig config, HttpServlet httpServlet) throws ServletException { httpServlet.init(config); } + + public HttpScmProtocol get(Repository repository) { + return new ProtocolWrapper(repository); + } + + private class ProtocolWrapper extends HttpScmProtocol { + + public ProtocolWrapper(Repository repository) { + super(repository); + } + + @Override + public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException { + if (!isInitialized) { + synchronized (InitializingHttpScmProtocolWrapper.this) { + if (!isInitialized) { + HttpServlet httpServlet = delegateProvider.get(); + initializeServlet(config, httpServlet); + isInitialized = true; + } + } + } + delegateProvider.get().service(request, response); + } + } } diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java index b363516a67..0f7914b4b0 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java @@ -24,7 +24,7 @@ public class RepositoryServiceTest { @Test public void shouldReturnProtocolsFromProvider() { - when(provider.getSupportedProtocols()).thenReturn(Collections.singleton(new DummyHttpProtocol())); + when(provider.getSupportedProtocols()).thenReturn(Collections.singleton(new DummyHttpProtocol(repository))); RepositoryService repositoryService = new RepositoryService(null, provider, repository, null); Collection supportedProtocols = repositoryService.getSupportedProtocols(); @@ -43,7 +43,11 @@ public class RepositoryServiceTest { }); } - private static class DummyHttpProtocol implements HttpScmProtocol { + private static class DummyHttpProtocol extends HttpScmProtocol { + public DummyHttpProtocol(Repository repository) { + super(repository); + } + @Override public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) { } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java index 39ea4f761a..654b586088 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java @@ -54,10 +54,10 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver //~--- constructors --------------------------------------------------------- @Inject - public GitRepositoryServiceResolver(GitRepositoryHandler handler, GitScmProtocolProviderWrapper servletProvider) + public GitRepositoryServiceResolver(GitRepositoryHandler handler, GitScmProtocolProviderWrapper providerWrapper) { this.handler = handler; - this.servletProvider = servletProvider; + this.providerWrapper = providerWrapper; } //~--- methods -------------------------------------------------------------- @@ -77,7 +77,7 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver if (TYPE.equalsIgnoreCase(repository.getType())) { - provider = new GitRepositoryServiceProvider(handler, repository, servletProvider); + provider = new GitRepositoryServiceProvider(handler, repository, providerWrapper.get(repository)); } return provider; @@ -87,5 +87,5 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver /** Field description */ private final GitRepositoryHandler handler; - private final HttpScmProtocol servletProvider; + private final GitScmProtocolProviderWrapper providerWrapper; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java index b0499fac9f..1fc837029c 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java @@ -81,16 +81,6 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider //~--- constructors --------------------------------------------------------- - /** - * Constructs ... - * - * - * - * @param handler - * @param hookManager - * @param repository - * @param httpScmProtocol - */ HgRepositoryServiceProvider(HgRepositoryHandler handler, HgHookManager hookManager, Repository repository, HttpScmProtocol httpScmProtocol) { diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java index d32d2f862f..08db6d1dbd 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java @@ -65,11 +65,11 @@ public class HgRepositoryServiceResolver implements RepositoryServiceResolver */ @Inject public HgRepositoryServiceResolver(HgRepositoryHandler handler, - HgHookManager hookManager, HgScmProtocolProviderWrapper httpScmProtocol) + HgHookManager hookManager, HgScmProtocolProviderWrapper providerWrapper) { this.handler = handler; this.hookManager = hookManager; - this.httpScmProtocol = httpScmProtocol; + this.providerWrapper = providerWrapper; } //~--- methods -------------------------------------------------------------- @@ -90,7 +90,7 @@ public class HgRepositoryServiceResolver implements RepositoryServiceResolver if (TYPE.equalsIgnoreCase(repository.getType())) { provider = new HgRepositoryServiceProvider(handler, hookManager, - repository, httpScmProtocol); + repository, providerWrapper.get(repository)); } return provider; @@ -104,5 +104,5 @@ public class HgRepositoryServiceResolver implements RepositoryServiceResolver /** Field description */ private HgHookManager hookManager; - private final HttpScmProtocol httpScmProtocol; + private final HgScmProtocolProviderWrapper providerWrapper; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index b124c9d3af..f8fabbc040 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -51,7 +51,6 @@ import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryRequestListenerUtil; -import sonia.scm.repository.spi.HttpScmProtocol; import sonia.scm.security.CipherUtil; import sonia.scm.util.AssertUtil; import sonia.scm.util.HttpUtil; @@ -77,7 +76,7 @@ import java.util.Enumeration; * @author Sebastian Sdorra */ @Singleton -public class HgCGIServlet extends HttpServlet implements HttpScmProtocol +public class HgCGIServlet extends HttpServlet { /** Field description */ @@ -347,7 +346,7 @@ public class HgCGIServlet extends HttpServlet implements HttpScmProtocol return python; } - @Override +// @Override public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) { service(request, response); } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java index 48233156c6..eb52ba55f0 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java @@ -58,13 +58,13 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver * * * @param handler - * @param httpScmProtocol + * @param protocolWrapper */ @Inject - public SvnRepositoryServiceResolver(SvnRepositoryHandler handler, SvnScmProtocolProviderWrapper httpScmProtocol) + public SvnRepositoryServiceResolver(SvnRepositoryHandler handler, SvnScmProtocolProviderWrapper protocolWrapper) { this.handler = handler; - this.httpScmProtocol = httpScmProtocol; + this.protocolWrapper = protocolWrapper; } //~--- methods -------------------------------------------------------------- @@ -84,7 +84,7 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver if (TYPE.equalsIgnoreCase(repository.getType())) { - provider = new SvnRepositoryServiceProvider(handler, repository, httpScmProtocol); + provider = new SvnRepositoryServiceProvider(handler, repository, protocolWrapper.get(repository)); } return provider; @@ -95,5 +95,5 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver /** Field description */ private SvnRepositoryHandler handler; - private final HttpScmProtocol httpScmProtocol; + private final InitializingHttpScmProtocolWrapper protocolWrapper; } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java index 0dda4306c6..96d0dc82c7 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java @@ -45,7 +45,6 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryRequestListenerUtil; import sonia.scm.repository.SvnRepositoryHandler; -import sonia.scm.repository.spi.HttpScmProtocol; import sonia.scm.util.AssertUtil; import sonia.scm.util.HttpUtil; @@ -63,7 +62,7 @@ import java.io.IOException; * @author Sebastian Sdorra */ @Singleton -public class SvnDAVServlet extends DAVServlet implements HttpScmProtocol +public class SvnDAVServlet extends DAVServlet { /** Field description */ @@ -285,7 +284,7 @@ public class SvnDAVServlet extends DAVServlet implements HttpScmProtocol private final RepositoryProvider repositoryProvider; } - @Override +// @Override public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException { service(request, response); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java index 62d7abedf7..5ca5d13219 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java @@ -67,6 +67,6 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper Date: Mon, 10 Sep 2018 14:48:22 +0200 Subject: [PATCH 15/58] Inject uri info for http protocol url computation --- .../main/java/sonia/scm/repository/api/ScmProtocol.java | 4 +--- .../java/sonia/scm/repository/spi/HttpScmProtocol.java | 9 ++++++--- .../spi/InitializingHttpScmProtocolWrapper.java | 7 +++++-- .../sonia/scm/repository/api/RepositoryServiceTest.java | 3 ++- .../sonia/scm/web/GitScmProtocolProviderWrapper.java | 5 +++-- .../java/sonia/scm/web/HgScmProtocolProviderWrapper.java | 5 +++-- .../sonia/scm/web/SvnScmProtocolProviderWrapper.java | 5 +++-- .../v2/resources/RepositoryToRepositoryDtoMapper.java | 2 +- .../java/sonia/scm/api/v2/resources/MockScmProtocol.java | 4 +--- 9 files changed, 25 insertions(+), 19 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java index b865d6e55b..c987510491 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocol.java @@ -1,7 +1,5 @@ package sonia.scm.repository.api; -import java.net.URI; - /** * An ScmProtocol represents a concrete protocol provided by the SCM-Manager instance * to interact with a repository depending on its type. There may be multiple protocols @@ -17,5 +15,5 @@ public interface ScmProtocol { /** * The URL to access the repository providing this protocol. */ - String getUrl(URI baseUri); + String getUrl(); } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java index 310b663d5d..f2d49b8570 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java @@ -7,15 +7,18 @@ import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.net.URI; public abstract class HttpScmProtocol implements ScmProtocol { private final Repository repository; + private final UriInfo uriInfo; - public HttpScmProtocol(Repository repository) { + public HttpScmProtocol(Repository repository, UriInfo uriInfo) { this.repository = repository; + this.uriInfo = uriInfo; } @Override @@ -24,8 +27,8 @@ public abstract class HttpScmProtocol implements ScmProtocol { } @Override - public String getUrl(URI baseUri) { - return baseUri.resolve(URI.create("repo" + "/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); + public String getUrl() { + return uriInfo.getBaseUri().resolve(URI.create("../../repo/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); } public abstract void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException; diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index b83386a380..e2634826b1 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -1,5 +1,6 @@ package sonia.scm.repository.spi; +import sonia.scm.api.v2.resources.UriInfoStore; import sonia.scm.repository.Repository; import javax.inject.Provider; @@ -13,12 +14,14 @@ import java.io.IOException; public abstract class InitializingHttpScmProtocolWrapper { private final Provider delegateProvider; + private final Provider uriInfoStore; private volatile boolean isInitialized = false; - protected InitializingHttpScmProtocolWrapper(Provider delegateProvider) { + protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider uriInfoStore) { this.delegateProvider = delegateProvider; + this.uriInfoStore = uriInfoStore; } protected void initializeServlet(ServletConfig config, HttpServlet httpServlet) throws ServletException { @@ -32,7 +35,7 @@ public abstract class InitializingHttpScmProtocolWrapper { private class ProtocolWrapper extends HttpScmProtocol { public ProtocolWrapper(Repository repository) { - super(repository); + super(repository, uriInfoStore.get().get()); } @Override diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java index 0f7914b4b0..cc6d02e076 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java @@ -8,6 +8,7 @@ import sonia.scm.repository.spi.RepositoryServiceProvider; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.UriInfo; import java.util.Collection; import java.util.Collections; @@ -45,7 +46,7 @@ public class RepositoryServiceTest { private static class DummyHttpProtocol extends HttpScmProtocol { public DummyHttpProtocol(Repository repository) { - super(repository); + super(repository, mock(UriInfo.class)); } @Override diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java index 5cc7383500..f2210259c2 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java @@ -1,5 +1,6 @@ package sonia.scm.web; +import sonia.scm.api.v2.resources.UriInfoStore; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import javax.inject.Inject; @@ -9,7 +10,7 @@ import javax.inject.Singleton; @Singleton public class GitScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public GitScmProtocolProviderWrapper(Provider servletProvider) { - super(servletProvider); + public GitScmProtocolProviderWrapper(Provider servletProvider, Provider uriInfoStore) { + super(servletProvider, uriInfoStore); } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java index c67c68024e..a69ff10512 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java @@ -1,5 +1,6 @@ package sonia.scm.web; +import sonia.scm.api.v2.resources.UriInfoStore; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import javax.inject.Inject; @@ -9,7 +10,7 @@ import javax.inject.Singleton; @Singleton public class HgScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public HgScmProtocolProviderWrapper(Provider servletProvider) { - super(servletProvider); + public HgScmProtocolProviderWrapper(Provider servletProvider, Provider uriInfoStore) { + super(servletProvider, uriInfoStore); } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java index 5544bf796e..4e619e27f8 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -1,5 +1,6 @@ package sonia.scm.web; +import sonia.scm.api.v2.resources.UriInfoStore; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import javax.inject.Inject; @@ -16,8 +17,8 @@ import static sonia.scm.web.SvnServletModule.PARAMETER_SVN_PARENTPATH; @Singleton public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public SvnScmProtocolProviderWrapper(Provider servletProvider) { - super(servletProvider); + public SvnScmProtocolProviderWrapper(Provider servletProvider, Provider uriInfoStore) { + super(servletProvider, uriInfoStore); } @Override diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java index 5ca5d13219..74ce1a65dd 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java @@ -67,6 +67,6 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper Date: Mon, 10 Sep 2018 15:49:11 +0200 Subject: [PATCH 16/58] Correct user agent in git lfs test --- scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java index 2452afb909..b07f0c6067 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java @@ -52,6 +52,7 @@ import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; import sonia.scm.user.User; import sonia.scm.user.UserTestData; +import sonia.scm.util.HttpUtil; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -221,7 +222,7 @@ public class GitLfsITCase { LfsResponseBody response = request(client, request); String uploadURL = response.objects[0].actions.upload.href; - client.resource(uploadURL).put(data); + client.resource(uploadURL).header(HttpUtil.HEADER_USERAGENT, "git-lfs/z").put(data); return lfsObject; } @@ -233,13 +234,14 @@ public class GitLfsITCase { String json = client .resource(batchUrl) .accept("application/vnd.git-lfs+json") + .header(HttpUtil.HEADER_USERAGENT, "git-lfs/z") .header("Content-Type", "application/vnd.git-lfs+json") .post(String.class, requestAsString); return new ObjectMapperProvider().get().readValue(json, LfsResponseBody.class); } private String createBatchUrl() { - String url = BASE_URL + "git/" + repository.getNamespace() + "/" + repository.getName(); + String url = BASE_URL + "repo/" + repository.getNamespace() + "/" + repository.getName(); return url + "/info/lfs/objects/batch"; } @@ -248,7 +250,7 @@ public class GitLfsITCase { LfsResponseBody response = request(client, request); String downloadUrl = response.objects[0].actions.download.href; - return client.resource(downloadUrl).get(byte[].class); + return client.resource(downloadUrl).header(HttpUtil.HEADER_USERAGENT, "git-lfs/z").get(byte[].class); } private LfsObject createLfsObject(byte[] data) { From 5f667a2428d3a9a0e9141a9a34807ba8fe4c3961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 10 Sep 2018 15:50:55 +0200 Subject: [PATCH 17/58] Correct url in git path mather test --- .../test/java/sonia/scm/it/GitRepositoryPathMatcherITCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitRepositoryPathMatcherITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitRepositoryPathMatcherITCase.java index 13cae15907..9e75857f08 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/GitRepositoryPathMatcherITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/GitRepositoryPathMatcherITCase.java @@ -100,7 +100,7 @@ public class GitRepositoryPathMatcherITCase { // tests end private String createUrl() { - return BASE_URL + "git/" + repository.getNamespace() + "/" + repository.getName(); + return BASE_URL + "repo/" + repository.getNamespace() + "/" + repository.getName(); } private void cloneAndPush( String url ) throws IOException { From d9d3167bbb1416939c7d852ca10bde52099564c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 10 Sep 2018 15:53:03 +0200 Subject: [PATCH 18/58] Correct url in repository hook test --- scm-webapp/src/test/java/sonia/scm/it/RepositoryHookITCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-webapp/src/test/java/sonia/scm/it/RepositoryHookITCase.java b/scm-webapp/src/test/java/sonia/scm/it/RepositoryHookITCase.java index dae80cd00d..6ad8342d8a 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/RepositoryHookITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/RepositoryHookITCase.java @@ -196,7 +196,7 @@ public class RepositoryHookITCase extends AbstractAdminITCaseBase private RepositoryClient createRepositoryClient() throws IOException { return REPOSITORY_CLIENT_FACTORY.create(repositoryType, - IntegrationTestUtil.BASE_URL + repositoryType + "/" + repository.getNamespace() + "/" + repository.getName(), + IntegrationTestUtil.BASE_URL + "repo/" + repository.getNamespace() + "/" + repository.getName(), IntegrationTestUtil.ADMIN_USERNAME, IntegrationTestUtil.ADMIN_PASSWORD, workingCopy ); } From eb378de87f46e31f7b937996aaf6bca76c3bfca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 10 Sep 2018 16:35:50 +0200 Subject: [PATCH 19/58] Use existing permission filters in http servlet protocol Just as a POC, fix logging and public access. --- .../scm/repository/spi/HttpScmProtocol.java | 4 ++ .../InitializingHttpScmProtocolWrapper.java | 41 ++++++++++++++++++- .../scm/web/filter/PermissionFilter.java | 6 +-- .../sonia/scm/web/GitPermissionFilter.java | 2 +- .../web/GitScmProtocolProviderWrapper.java | 4 +- .../sonia/scm/web/HgPermissionFilter.java | 2 +- .../scm/web/HgScmProtocolProviderWrapper.java | 4 +- .../sonia/scm/web/SvnPermissionFilter.java | 2 +- .../web/SvnScmProtocolProviderWrapper.java | 4 +- 9 files changed, 55 insertions(+), 14 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java index f2d49b8570..51467d9f5c 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java @@ -32,4 +32,8 @@ public abstract class HttpScmProtocol implements ScmProtocol { } public abstract void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException; + + Repository getRepository() { + return repository; + } } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index e2634826b1..ba63cf8501 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -1,7 +1,13 @@ package sonia.scm.repository.spi; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.subject.Subject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.api.v2.resources.UriInfoStore; import sonia.scm.repository.Repository; +import sonia.scm.web.filter.PermissionFilter; +import sonia.scm.web.filter.ProviderPermissionFilter; import javax.inject.Provider; import javax.servlet.ServletConfig; @@ -13,14 +19,19 @@ import java.io.IOException; public abstract class InitializingHttpScmProtocolWrapper { + private static final Logger logger = + LoggerFactory.getLogger(InitializingHttpScmProtocolWrapper.class); + private final Provider delegateProvider; + private final Provider permissionFilterProvider; private final Provider uriInfoStore; private volatile boolean isInitialized = false; - protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider uriInfoStore) { + protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider permissionFilterProvider, Provider uriInfoStore) { this.delegateProvider = delegateProvider; + this.permissionFilterProvider = permissionFilterProvider; this.uriInfoStore = uriInfoStore; } @@ -49,7 +60,33 @@ public abstract class InitializingHttpScmProtocolWrapper { } } } - delegateProvider.get().service(request, response); + + if (getRepository() != null) + { + Subject subject = SecurityUtils.getSubject(); + + PermissionFilter permissionFilter = permissionFilterProvider.get(); + boolean writeRequest = permissionFilter.isWriteRequest(request); + + if (permissionFilter.hasPermission(getRepository(), writeRequest)) + { +// logger.trace("{} access to repository {} for user {} granted", +// getActionAsString(writeRequest), repository.getName(), +// getUserName(subject)); + + delegateProvider.get().service(request, response); + } + else + { +// logger.info("{} access to repository {} for user {} denied", +// getActionAsString(writeRequest), repository.getName(), +// getUserName(subject)); + + permissionFilter.sendAccessDenied(request, response, subject); + } + } + } } + } diff --git a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java index dd3c82e800..732bac1c57 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java @@ -106,7 +106,7 @@ public abstract class PermissionFilter extends HttpFilter * * @return returns true if the current request is a write request */ - protected abstract boolean isWriteRequest(HttpServletRequest request); + public abstract boolean isWriteRequest(HttpServletRequest request); //~--- methods -------------------------------------------------------------- @@ -249,7 +249,7 @@ public abstract class PermissionFilter extends HttpFilter * * @throws IOException */ - private void sendAccessDenied(HttpServletRequest request, + public void sendAccessDenied(HttpServletRequest request, HttpServletResponse response, Subject subject) throws IOException { @@ -328,7 +328,7 @@ public abstract class PermissionFilter extends HttpFilter * * @return true if the current user has the required permissions */ - private boolean hasPermission(Repository repository, boolean writeRequest) + public boolean hasPermission(Repository repository, boolean writeRequest) { boolean permitted; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java index 068284188d..ca88e06a41 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java @@ -98,7 +98,7 @@ public class GitPermissionFilter extends ProviderPermissionFilter } @Override - protected boolean isWriteRequest(HttpServletRequest request) { + public boolean isWriteRequest(HttpServletRequest request) { return isReceivePackRequest(request) || isReceiveServiceRequest(request) || isLfsFileUpload(request); diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java index f2210259c2..ae378c2439 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java @@ -10,7 +10,7 @@ import javax.inject.Singleton; @Singleton public class GitScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public GitScmProtocolProviderWrapper(Provider servletProvider, Provider uriInfoStore) { - super(servletProvider, uriInfoStore); + public GitScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore) { + super(servletProvider, permissionFilter, uriInfoStore); } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java index c05f03dc4e..9350f8399c 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java @@ -74,7 +74,7 @@ public class HgPermissionFilter extends ProviderPermissionFilter //~--- get methods ---------------------------------------------------------- @Override - protected boolean isWriteRequest(HttpServletRequest request) + public boolean isWriteRequest(HttpServletRequest request) { return !READ_METHODS.contains(request.getMethod()); } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java index a69ff10512..ba5c40e7f9 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java @@ -10,7 +10,7 @@ import javax.inject.Singleton; @Singleton public class HgScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public HgScmProtocolProviderWrapper(Provider servletProvider, Provider uriInfoStore) { - super(servletProvider, uriInfoStore); + public HgScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore) { + super(servletProvider, permissionFilter, uriInfoStore); } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java index 857e3d6d71..43a4f1baec 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java @@ -126,7 +126,7 @@ public class SvnPermissionFilter extends ProviderPermissionFilter * @return */ @Override - protected boolean isWriteRequest(HttpServletRequest request) + public boolean isWriteRequest(HttpServletRequest request) { return WRITEMETHOD_SET.contains(request.getMethod().toUpperCase()); } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java index 4e619e27f8..7907e55dcc 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -17,8 +17,8 @@ import static sonia.scm.web.SvnServletModule.PARAMETER_SVN_PARENTPATH; @Singleton public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public SvnScmProtocolProviderWrapper(Provider servletProvider, Provider uriInfoStore) { - super(servletProvider, uriInfoStore); + public SvnScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore) { + super(servletProvider, permissionFilter, uriInfoStore); } @Override From 1b200ae69dfa6e07078c363430f43ded7e79ed20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 10 Sep 2018 16:58:52 +0200 Subject: [PATCH 20/58] Remove http request filter implementation from permission filters --- .../InitializingHttpScmProtocolWrapper.java | 34 ++-------- .../scm/web/filter/PermissionFilter.java | 63 +++++++------------ .../web/filter/ProviderPermissionFilter.java | 49 +-------------- .../sonia/scm/web/GitPermissionFilter.java | 6 +- .../scm/web/GitPermissionFilterTest.java | 8 +-- .../sonia/scm/web/HgPermissionFilter.java | 7 +-- .../sonia/scm/web/SvnPermissionFilter.java | 7 +-- 7 files changed, 35 insertions(+), 139 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index ba63cf8501..12a62d13c5 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -1,12 +1,9 @@ package sonia.scm.repository.spi; -import org.apache.shiro.SecurityUtils; -import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.api.v2.resources.UriInfoStore; import sonia.scm.repository.Repository; -import sonia.scm.web.filter.PermissionFilter; import sonia.scm.web.filter.ProviderPermissionFilter; import javax.inject.Provider; @@ -61,32 +58,11 @@ public abstract class InitializingHttpScmProtocolWrapper { } } - if (getRepository() != null) - { - Subject subject = SecurityUtils.getSubject(); - - PermissionFilter permissionFilter = permissionFilterProvider.get(); - boolean writeRequest = permissionFilter.isWriteRequest(request); - - if (permissionFilter.hasPermission(getRepository(), writeRequest)) - { -// logger.trace("{} access to repository {} for user {} granted", -// getActionAsString(writeRequest), repository.getName(), -// getUserName(subject)); - - delegateProvider.get().service(request, response); - } - else - { -// logger.info("{} access to repository {} for user {} denied", -// getActionAsString(writeRequest), repository.getName(), -// getUserName(subject)); - - permissionFilter.sendAccessDenied(request, response, subject); - } - } - + permissionFilterProvider.get().executeIfPermitted( + request, + response, + getRepository(), + () -> delegateProvider.get().service(request, response)); } } - } diff --git a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java index 732bac1c57..8831756234 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java @@ -51,7 +51,6 @@ import sonia.scm.security.ScmSecurityException; import sonia.scm.util.HttpUtil; import sonia.scm.util.Util; -import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -65,7 +64,7 @@ import java.util.Iterator; * * @author Sebastian Sdorra */ -public abstract class PermissionFilter extends HttpFilter +public abstract class PermissionFilter { /** the logger for PermissionFilter */ @@ -81,23 +80,13 @@ public abstract class PermissionFilter extends HttpFilter * * @since 1.21 */ - public PermissionFilter(ScmConfiguration configuration) + protected PermissionFilter(ScmConfiguration configuration) { this.configuration = configuration; } //~--- get methods ---------------------------------------------------------- - /** - * Returns the requested repository. - * - * - * @param request current http request - * - * @return requested repository - */ - protected abstract Repository getRepository(HttpServletRequest request); - /** * Returns true if the current request is a write request. * @@ -106,7 +95,7 @@ public abstract class PermissionFilter extends HttpFilter * * @return returns true if the current request is a write request */ - public abstract boolean isWriteRequest(HttpServletRequest request); + protected abstract boolean isWriteRequest(HttpServletRequest request); //~--- methods -------------------------------------------------------------- @@ -117,48 +106,35 @@ public abstract class PermissionFilter extends HttpFilter * * @param request http request * @param response http response - * @param chain filter chain * * @throws IOException * @throws ServletException */ - @Override - protected void doFilter(HttpServletRequest request, - HttpServletResponse response, FilterChain chain) + public void executeIfPermitted(HttpServletRequest request, + HttpServletResponse response, Repository repository, ContinuationServlet continuation) throws IOException, ServletException { Subject subject = SecurityUtils.getSubject(); try { - Repository repository = getRepository(request); + boolean writeRequest = isWriteRequest(request); - if (repository != null) + if (hasPermission(repository, writeRequest)) { - boolean writeRequest = isWriteRequest(request); + logger.trace("{} access to repository {} for user {} granted", + getActionAsString(writeRequest), repository.getName(), + getUserName(subject)); - if (hasPermission(repository, writeRequest)) - { - logger.trace("{} access to repository {} for user {} granted", - getActionAsString(writeRequest), repository.getName(), - getUserName(subject)); - - chain.doFilter(request, response); - } - else - { - logger.info("{} access to repository {} for user {} denied", - getActionAsString(writeRequest), repository.getName(), - getUserName(subject)); - - sendAccessDenied(request, response, subject); - } + continuation.serve(); } else { - logger.debug("repository not found"); + logger.info("{} access to repository {} for user {} denied", + getActionAsString(writeRequest), repository.getName(), + getUserName(subject)); - response.sendError(HttpServletResponse.SC_NOT_FOUND); + sendAccessDenied(request, response, subject); } } catch (ArgumentIsInvalidException ex) @@ -249,7 +225,7 @@ public abstract class PermissionFilter extends HttpFilter * * @throws IOException */ - public void sendAccessDenied(HttpServletRequest request, + private void sendAccessDenied(HttpServletRequest request, HttpServletResponse response, Subject subject) throws IOException { @@ -328,7 +304,7 @@ public abstract class PermissionFilter extends HttpFilter * * @return true if the current user has the required permissions */ - public boolean hasPermission(Repository repository, boolean writeRequest) + private boolean hasPermission(Repository repository, boolean writeRequest) { boolean permitted; @@ -348,4 +324,9 @@ public abstract class PermissionFilter extends HttpFilter /** scm-manager global configuration */ private final ScmConfiguration configuration; + + @FunctionalInterface + public interface ContinuationServlet { + void serve() throws ServletException, IOException; + } } diff --git a/scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java index ea0d90c915..280ea0a77b 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java @@ -35,22 +35,12 @@ package sonia.scm.web.filter; //~--- non-JDK imports -------------------------------------------------------- -import com.google.common.base.Throwables; -import com.google.inject.ProvisionException; - -import org.apache.shiro.authz.AuthorizationException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import sonia.scm.config.ScmConfiguration; -import sonia.scm.repository.Repository; -import sonia.scm.repository.RepositoryProvider; //~--- JDK imports ------------------------------------------------------------ -import javax.servlet.http.HttpServletRequest; - /** * * @author Sebastian Sdorra @@ -72,47 +62,10 @@ public abstract class ProviderPermissionFilter extends PermissionFilter * * * @param configuration - * @param repositoryProvider * @since 1.21 */ - public ProviderPermissionFilter(ScmConfiguration configuration, - RepositoryProvider repositoryProvider) + public ProviderPermissionFilter(ScmConfiguration configuration) { super(configuration); - this.repositoryProvider = repositoryProvider; } - - //~--- get methods ---------------------------------------------------------- - - /** - * Method description - * - * - * @param request - * - * @return - */ - @Override - protected Repository getRepository(HttpServletRequest request) - { - Repository repository = null; - - try - { - repository = repositoryProvider.get(); - } - catch (ProvisionException ex) - { - Throwables.propagateIfPossible(ex.getCause(), - IllegalStateException.class, AuthorizationException.class); - logger.error("could not get repository from request", ex); - } - - return repository; - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private final RepositoryProvider repositoryProvider; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java index ca88e06a41..5606b73762 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java @@ -43,7 +43,6 @@ import sonia.scm.Priority; import sonia.scm.config.ScmConfiguration; import sonia.scm.filter.Filters; import sonia.scm.repository.GitUtil; -import sonia.scm.repository.RepositoryProvider; import sonia.scm.web.filter.ProviderPermissionFilter; import javax.servlet.http.HttpServletRequest; @@ -78,11 +77,10 @@ public class GitPermissionFilter extends ProviderPermissionFilter * Constructs a new instance of the GitPermissionFilter. * * @param configuration scm main configuration - * @param repositoryProvider repository provider */ @Inject - public GitPermissionFilter(ScmConfiguration configuration, RepositoryProvider repositoryProvider) { - super(configuration, repositoryProvider); + public GitPermissionFilter(ScmConfiguration configuration) { + super(configuration); } @Override diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java index fede8842a9..8e7ff3d954 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java @@ -5,7 +5,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.config.ScmConfiguration; -import sonia.scm.repository.RepositoryProvider; import sonia.scm.util.HttpUtil; import javax.servlet.ServletOutputStream; @@ -29,12 +28,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class GitPermissionFilterTest { - @Mock - private RepositoryProvider repositoryProvider; - - private final GitPermissionFilter permissionFilter = new GitPermissionFilter( - new ScmConfiguration(), repositoryProvider - ); + private final GitPermissionFilter permissionFilter = new GitPermissionFilter(new ScmConfiguration()); @Mock private HttpServletResponse response; diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java index 9350f8399c..3a1aba93e4 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java @@ -38,7 +38,6 @@ package sonia.scm.web; import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; import sonia.scm.config.ScmConfiguration; -import sonia.scm.repository.RepositoryProvider; import sonia.scm.web.filter.ProviderPermissionFilter; import javax.servlet.http.HttpServletRequest; @@ -62,13 +61,11 @@ public class HgPermissionFilter extends ProviderPermissionFilter * Constructs a new instance. * * @param configuration scm configuration - * @param repositoryProvider repository provider */ @Inject - public HgPermissionFilter(ScmConfiguration configuration, - RepositoryProvider repositoryProvider) + public HgPermissionFilter(ScmConfiguration configuration) { - super(configuration, repositoryProvider); + super(configuration); } //~--- get methods ---------------------------------------------------------- diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java index 43a4f1baec..2939b44753 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java @@ -39,7 +39,6 @@ import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; import sonia.scm.ClientMessages; import sonia.scm.config.ScmConfiguration; -import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.ScmSvnErrorCode; import sonia.scm.repository.SvnUtil; import sonia.scm.web.filter.ProviderPermissionFilter; @@ -71,13 +70,11 @@ public class SvnPermissionFilter extends ProviderPermissionFilter * Constructs ... * * @param configuration - * @param repository */ @Inject - public SvnPermissionFilter(ScmConfiguration configuration, - RepositoryProvider repository) + public SvnPermissionFilter(ScmConfiguration configuration) { - super(configuration, repository); + super(configuration); } //~--- methods -------------------------------------------------------------- From bf9de8ea8ed105776270cc0d9fbb82912d231404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 11 Sep 2018 07:40:24 +0200 Subject: [PATCH 21/58] Reduce dependency to RepositoryProvider in provider servlets --- .../scm/repository/spi/HttpScmProtocol.java | 8 +-- .../InitializingHttpScmProtocolWrapper.java | 15 +++--- .../spi/ScmProviderHttpServlet.java | 16 ++++++ .../repository/api/RepositoryServiceTest.java | 2 +- .../java/sonia/scm/web/ScmGitServlet.java | 47 ++--------------- .../main/java/sonia/scm/web/HgCGIServlet.java | 44 +++------------- .../java/sonia/scm/web/SvnDAVServlet.java | 51 +++++-------------- .../web/SvnScmProtocolProviderWrapper.java | 4 +- 8 files changed, 52 insertions(+), 135 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServlet.java diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java index 51467d9f5c..b93deba10a 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java @@ -31,9 +31,9 @@ public abstract class HttpScmProtocol implements ScmProtocol { return uriInfo.getBaseUri().resolve(URI.create("../../repo/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); } - public abstract void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException; - - Repository getRepository() { - return repository; + public final void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException { + serve(request, response, repository, config); } + + protected abstract void serve(HttpServletRequest request, HttpServletResponse response, Repository repository, ServletConfig config) throws ServletException, IOException; } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 12a62d13c5..22f7a25b57 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -9,7 +9,6 @@ import sonia.scm.web.filter.ProviderPermissionFilter; import javax.inject.Provider; import javax.servlet.ServletConfig; import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -19,20 +18,20 @@ public abstract class InitializingHttpScmProtocolWrapper { private static final Logger logger = LoggerFactory.getLogger(InitializingHttpScmProtocolWrapper.class); - private final Provider delegateProvider; + private final Provider delegateProvider; private final Provider permissionFilterProvider; private final Provider uriInfoStore; private volatile boolean isInitialized = false; - protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider permissionFilterProvider, Provider uriInfoStore) { + protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider permissionFilterProvider, Provider uriInfoStore) { this.delegateProvider = delegateProvider; this.permissionFilterProvider = permissionFilterProvider; this.uriInfoStore = uriInfoStore; } - protected void initializeServlet(ServletConfig config, HttpServlet httpServlet) throws ServletException { + protected void initializeServlet(ServletConfig config, ScmProviderHttpServlet httpServlet) throws ServletException { httpServlet.init(config); } @@ -47,11 +46,11 @@ public abstract class InitializingHttpScmProtocolWrapper { } @Override - public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException { + protected void serve(HttpServletRequest request, HttpServletResponse response, Repository repository, ServletConfig config) throws ServletException, IOException { if (!isInitialized) { synchronized (InitializingHttpScmProtocolWrapper.this) { if (!isInitialized) { - HttpServlet httpServlet = delegateProvider.get(); + ScmProviderHttpServlet httpServlet = delegateProvider.get(); initializeServlet(config, httpServlet); isInitialized = true; } @@ -61,8 +60,8 @@ public abstract class InitializingHttpScmProtocolWrapper { permissionFilterProvider.get().executeIfPermitted( request, response, - getRepository(), - () -> delegateProvider.get().service(request, response)); + repository, + () -> delegateProvider.get().service(request, response, repository)); } } } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServlet.java b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServlet.java new file mode 100644 index 0000000000..3a9dad52d6 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServlet.java @@ -0,0 +1,16 @@ +package sonia.scm.repository.spi; + +import sonia.scm.repository.Repository; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public interface ScmProviderHttpServlet { + + void service(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException; + + void init(ServletConfig config) throws ServletException; +} diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java index cc6d02e076..1783d17936 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java @@ -50,7 +50,7 @@ public class RepositoryServiceTest { } @Override - public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) { + public void serve(HttpServletRequest request, HttpServletResponse response, Repository repository, ServletConfig config) { } } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java index 261e67c185..8ec81d43f3 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java @@ -42,8 +42,8 @@ import org.eclipse.jgit.http.server.GitServlet; import org.eclipse.jgit.lfs.lib.Constants; import org.slf4j.Logger; import sonia.scm.repository.Repository; -import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryRequestListenerUtil; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.util.HttpUtil; import sonia.scm.web.lfs.servlet.LfsServletFactory; @@ -64,7 +64,7 @@ import static org.slf4j.LoggerFactory.getLogger; * @author Sebastian Sdorra */ @Singleton -public class ScmGitServlet extends GitServlet +public class ScmGitServlet extends GitServlet implements ScmProviderHttpServlet { /** Field description */ @@ -88,7 +88,6 @@ public class ScmGitServlet extends GitServlet * @param repositoryResolver * @param receivePackFactory * @param repositoryViewer - * @param repositoryProvider * @param repositoryRequestListenerUtil * @param lfsServletFactory */ @@ -96,11 +95,9 @@ public class ScmGitServlet extends GitServlet public ScmGitServlet(GitRepositoryResolver repositoryResolver, GitReceivePackFactory receivePackFactory, GitRepositoryViewer repositoryViewer, - RepositoryProvider repositoryProvider, RepositoryRequestListenerUtil repositoryRequestListenerUtil, LfsServletFactory lfsServletFactory) { - this.repositoryProvider = repositoryProvider; this.repositoryViewer = repositoryViewer; this.repositoryRequestListenerUtil = repositoryRequestListenerUtil; this.lfsServletFactory = lfsServletFactory; @@ -122,44 +119,9 @@ public class ScmGitServlet extends GitServlet * @throws ServletException */ @Override - protected void service(HttpServletRequest request, - HttpServletResponse response) + public void service(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException { - Repository repository = repositoryProvider.get(); - if (repository != null) { - handleRequest(request, response, repository); - } else { - // logger - response.sendError(HttpServletResponse.SC_NOT_FOUND); - } - } - - /** - * Decides the type request being currently made and delegates it accordingly. - *
    - *
  • Batch API:
  • - *
      - *
    • used to provide the client with information on how handle the large files of a repository.
    • - *
    • response contains the information where to perform the actual upload and download of the large objects.
    • - *
    - *
  • Transfer API:
  • - *
      - *
    • receives and provides the actual large objects (resolves the pointer placed in the file of the working copy).
    • - *
    • invoked only after the Batch API has been questioned about what to do with the large files
    • - *
    - *
  • Regular Git Http API:
  • - *
      - *
    • regular git http wire protocol, use by normal git clients.
    • - *
    - *
  • Browser Overview:
  • - *
      - *
    • short repository overview for browser clients.
    • - *
    - *
  • - *
- */ - private void handleRequest(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException { String repoPath = repository.getNamespace() + "/" + repository.getName(); logger.trace("handle git repository at {}", repoPath); if (isLfsBatchApiRequest(request, repoPath)) { @@ -286,9 +248,6 @@ public class ScmGitServlet extends GitServlet //~--- fields --------------------------------------------------------------- - /** Field description */ - private final RepositoryProvider repositoryProvider; - /** Field description */ private final RepositoryRequestListenerUtil repositoryRequestListenerUtil; diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index f8fabbc040..f3e6a54568 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -49,8 +49,8 @@ import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgPythonScript; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; -import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryRequestListenerUtil; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.security.CipherUtil; import sonia.scm.util.AssertUtil; import sonia.scm.util.HttpUtil; @@ -58,7 +58,6 @@ import sonia.scm.web.cgi.CGIExecutor; import sonia.scm.web.cgi.CGIExecutorFactory; import sonia.scm.web.cgi.EnvList; -import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -76,7 +75,7 @@ import java.util.Enumeration; * @author Sebastian Sdorra */ @Singleton -public class HgCGIServlet extends HttpServlet +public class HgCGIServlet extends HttpServlet implements ScmProviderHttpServlet { /** Field description */ @@ -109,20 +108,18 @@ public class HgCGIServlet extends HttpServlet * * @param cgiExecutorFactory * @param configuration - * @param repositoryProvider * @param handler * @param hookManager * @param requestListenerUtil */ @Inject public HgCGIServlet(CGIExecutorFactory cgiExecutorFactory, - ScmConfiguration configuration, RepositoryProvider repositoryProvider, + ScmConfiguration configuration, HgRepositoryHandler handler, HgHookManager hookManager, RepositoryRequestListenerUtil requestListenerUtil) { this.cgiExecutorFactory = cgiExecutorFactory; this.configuration = configuration; - this.repositoryProvider = repositoryProvider; this.handler = handler; this.hookManager = hookManager; this.requestListenerUtil = requestListenerUtil; @@ -132,32 +129,11 @@ public class HgCGIServlet extends HttpServlet //~--- methods -------------------------------------------------------------- - /** - * Method description - * - * - * @param request - * @param response - * - * @throws IOException - * @throws ServletException - */ @Override - protected void service(HttpServletRequest request, - HttpServletResponse response) + public void service(HttpServletRequest request, + HttpServletResponse response, Repository repository) { - Repository repository = repositoryProvider.get(); - - if (repository == null) - { - if (logger.isDebugEnabled()) - { - logger.debug("no hg repository found at {}", request.getRequestURI()); - } - - response.setStatus(HttpServletResponse.SC_NOT_FOUND); - } - else if (!handler.isConfigured()) + if (!handler.isConfigured()) { exceptionHandler.sendFormattedError(request, response, HgCGIExceptionHandler.ERROR_NOT_CONFIGURED); @@ -346,11 +322,6 @@ public class HgCGIServlet extends HttpServlet return python; } -// @Override - public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) { - service(request, response); - } - //~--- fields --------------------------------------------------------------- /** Field description */ @@ -371,9 +342,6 @@ public class HgCGIServlet extends HttpServlet /** Field description */ private final HgHookManager hookManager; - /** Field description */ - private final RepositoryProvider repositoryProvider; - /** Field description */ private final RepositoryRequestListenerUtil requestListenerUtil; } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java index 96d0dc82c7..35b420257d 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java @@ -45,10 +45,10 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryRequestListenerUtil; import sonia.scm.repository.SvnRepositoryHandler; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.util.AssertUtil; import sonia.scm.util.HttpUtil; -import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; @@ -62,7 +62,7 @@ import java.io.IOException; * @author Sebastian Sdorra */ @Singleton -public class SvnDAVServlet extends DAVServlet +public class SvnDAVServlet extends DAVServlet implements ScmProviderHttpServlet { /** Field description */ @@ -111,28 +111,18 @@ public class SvnDAVServlet extends DAVServlet * @throws ServletException */ @Override - public void service(HttpServletRequest request, HttpServletResponse response) + public void service(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException { - Repository repository = repositoryProvider.get(); - - if (repository != null) - { - if (repositoryRequestListenerUtil.callListeners(request, response, - repository)) - { - super.service(new SvnHttpServletRequestWrapper(request, - repositoryProvider), response); - } - else if (logger.isDebugEnabled()) - { - logger.debug("request aborted by repository request listener"); - } - } - else + if (repositoryRequestListenerUtil.callListeners(request, response, + repository)) { super.service(new SvnHttpServletRequestWrapper(request, - repositoryProvider), response); + repository), response); + } + else if (logger.isDebugEnabled()) + { + logger.debug("request aborted by repository request listener"); } } @@ -164,18 +154,11 @@ public class SvnDAVServlet extends DAVServlet extends HttpServletRequestWrapper { - /** - * Constructs ... - * - * - * @param request - * @param repositoryProvider - */ public SvnHttpServletRequestWrapper(HttpServletRequest request, - RepositoryProvider repositoryProvider) + Repository repository) { super(request); - this.repositoryProvider = repositoryProvider; + this.repository = repository; } //~--- get methods -------------------------------------------------------- @@ -212,8 +195,6 @@ public class SvnDAVServlet extends DAVServlet AssertUtil.assertIsNotEmpty(pathInfo); - Repository repository = repositoryProvider.get(); - if (repository != null) { if (pathInfo.startsWith(HttpUtil.SEPARATOR_PATH)) @@ -237,7 +218,6 @@ public class SvnDAVServlet extends DAVServlet public String getServletPath() { String servletPath = super.getServletPath(); - Repository repository = repositoryProvider.get(); if (repository != null) { @@ -281,12 +261,7 @@ public class SvnDAVServlet extends DAVServlet //~--- fields ------------------------------------------------------------- /** Field description */ - private final RepositoryProvider repositoryProvider; - } - -// @Override - public void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException { - service(request, response); + private final Repository repository; } //~--- fields --------------------------------------------------------------- diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java index 7907e55dcc..90ac29aa12 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -2,6 +2,7 @@ package sonia.scm.web; import sonia.scm.api.v2.resources.UriInfoStore; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import javax.inject.Inject; import javax.inject.Provider; @@ -9,7 +10,6 @@ import javax.inject.Singleton; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; import java.util.Enumeration; import static sonia.scm.web.SvnServletModule.PARAMETER_SVN_PARENTPATH; @@ -22,7 +22,7 @@ public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWr } @Override - protected void initializeServlet(ServletConfig config, HttpServlet httpServlet) throws ServletException { + protected void initializeServlet(ServletConfig config, ScmProviderHttpServlet httpServlet) throws ServletException { super.initializeServlet(new X(config), httpServlet); } From e90dc11bc7f3c4e762a0579d5eeaebc5d7fec347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 11 Sep 2018 10:50:53 +0200 Subject: [PATCH 22/58] Cleanup for http protocol servlet changes --- .../sonia/scm/ArgumentIsInvalidException.java | 85 --------------- .../InitializingHttpScmProtocolWrapper.java | 6 +- .../spi/RepositoryServiceProvider.java | 4 - .../scm/web/filter/PermissionFilter.java | 40 ------- .../web/filter/ProviderPermissionFilter.java | 71 ------------ .../spi/GitRepositoryServiceProvider.java | 4 - .../spi/GitRepositoryServiceResolver.java | 28 +---- .../sonia/scm/web/GitPermissionFilter.java | 12 +-- .../java/sonia/scm/web/GitServletModule.java | 12 --- .../java/sonia/scm/web/ScmGitServlet.java | 13 +-- .../spi/HgRepositoryServiceProvider.java | 4 - .../spi/HgRepositoryServiceResolver.java | 2 - .../scm/web/HgBasicAuthenticationFilter.java | 102 ------------------ .../main/java/sonia/scm/web/HgCGIServlet.java | 4 - .../sonia/scm/web/HgPermissionFilter.java | 17 +-- .../spi/SvnRepositoryServiceProvider.java | 4 - .../spi/SvnRepositoryServiceResolver.java | 41 +------ .../scm/web/SvnBasicAuthenticationFilter.java | 96 ----------------- .../java/sonia/scm/web/SvnDAVServlet.java | 4 - .../sonia/scm/web/SvnPermissionFilter.java | 10 +- .../web/SvnScmProtocolProviderWrapper.java | 11 +- .../java/sonia/scm/web/SvnServletModule.java | 26 +---- .../java/sonia/scm/ScmContextListener.java | 4 - .../main/java/sonia/scm/ScmServletModule.java | 12 --- .../resources/RepositoryRootResource.java | 4 - .../repository/DefaultRepositoryManager.java | 4 - .../repository/DefaultRepositoryProvider.java | 8 +- 27 files changed, 32 insertions(+), 596 deletions(-) delete mode 100644 scm-core/src/main/java/sonia/scm/ArgumentIsInvalidException.java delete mode 100644 scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java delete mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgBasicAuthenticationFilter.java delete mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnBasicAuthenticationFilter.java diff --git a/scm-core/src/main/java/sonia/scm/ArgumentIsInvalidException.java b/scm-core/src/main/java/sonia/scm/ArgumentIsInvalidException.java deleted file mode 100644 index 727e9a8160..0000000000 --- a/scm-core/src/main/java/sonia/scm/ArgumentIsInvalidException.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) 2010, Sebastian Sdorra - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ - - -package sonia.scm; - -/** - * - * @author Sebastian Sdorra - * @since 1.17 - */ -public class ArgumentIsInvalidException extends IllegalStateException -{ - - /** - * Constructs ... - * - */ - public ArgumentIsInvalidException() - { - super(); - } - - /** - * Constructs ... - * - * - * @param s - */ - public ArgumentIsInvalidException(String s) - { - super(s); - } - - /** - * Constructs ... - * - * - * @param cause - */ - public ArgumentIsInvalidException(Throwable cause) - { - super(cause); - } - - /** - * Constructs ... - * - * - * @param message - * @param cause - */ - public ArgumentIsInvalidException(String message, Throwable cause) - { - super(message, cause); - } -} diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 22f7a25b57..3d4d3c6205 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -4,7 +4,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.api.v2.resources.UriInfoStore; import sonia.scm.repository.Repository; -import sonia.scm.web.filter.ProviderPermissionFilter; +import sonia.scm.web.filter.PermissionFilter; import javax.inject.Provider; import javax.servlet.ServletConfig; @@ -19,13 +19,13 @@ public abstract class InitializingHttpScmProtocolWrapper { LoggerFactory.getLogger(InitializingHttpScmProtocolWrapper.class); private final Provider delegateProvider; - private final Provider permissionFilterProvider; + private final Provider permissionFilterProvider; private final Provider uriInfoStore; private volatile boolean isInitialized = false; - protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider permissionFilterProvider, Provider uriInfoStore) { + protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider permissionFilterProvider, Provider uriInfoStore) { this.delegateProvider = delegateProvider; this.permissionFilterProvider = permissionFilterProvider; this.uriInfoStore = uriInfoStore; diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java index d44db74f7c..0a56800f82 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java @@ -33,8 +33,6 @@ package sonia.scm.repository.spi; -//~--- non-JDK imports -------------------------------------------------------- - import sonia.scm.repository.Feature; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.CommandNotSupportedException; @@ -45,8 +43,6 @@ import java.io.IOException; import java.util.Collections; import java.util.Set; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra diff --git a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java index 8831756234..3415c3e338 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java @@ -33,15 +33,12 @@ package sonia.scm.web.filter; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.base.Splitter; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.ArgumentIsInvalidException; import sonia.scm.SCMContext; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; @@ -57,8 +54,6 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Iterator; -//~--- JDK imports ------------------------------------------------------------ - /** * Abstract http filter to check repository permissions. * @@ -137,22 +132,6 @@ public abstract class PermissionFilter sendAccessDenied(request, response, subject); } } - catch (ArgumentIsInvalidException ex) - { - if (logger.isTraceEnabled()) - { - logger.trace( - "wrong request at ".concat(request.getRequestURI()).concat( - " send redirect"), ex); - } - else if (logger.isWarnEnabled()) - { - logger.warn("wrong request at {} send redirect", - request.getRequestURI()); - } - - response.sendRedirect(getRepositoryRootHelpUrl(request)); - } catch (ScmSecurityException | AuthorizationException ex) { logger.warn("user " + subject.getPrincipal() + " has not enough permissions", ex); @@ -256,25 +235,6 @@ public abstract class PermissionFilter : "read"; } - /** - * Returns the repository root help url. - * - * - * @param request current http request - * - * @return repository root help url - */ - private String getRepositoryRootHelpUrl(HttpServletRequest request) - { - String type = extractType(request); - String helpUrl = HttpUtil.getCompleteUrl(request, - "/api/rest/help/repository-root/"); - - helpUrl = helpUrl.concat(type).concat(".html"); - - return helpUrl; - } - /** * Returns the username from the given subject or anonymous. * diff --git a/scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java deleted file mode 100644 index 280ea0a77b..0000000000 --- a/scm-core/src/main/java/sonia/scm/web/filter/ProviderPermissionFilter.java +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2010, Sebastian Sdorra - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ - - - -package sonia.scm.web.filter; - -//~--- non-JDK imports -------------------------------------------------------- - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import sonia.scm.config.ScmConfiguration; - -//~--- JDK imports ------------------------------------------------------------ - -/** - * - * @author Sebastian Sdorra - * @since 1.9 - */ -public abstract class ProviderPermissionFilter extends PermissionFilter -{ - - /** - * the logger for ProviderPermissionFilter - */ - private static final Logger logger = - LoggerFactory.getLogger(ProviderPermissionFilter.class); - - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param configuration - * @since 1.21 - */ - public ProviderPermissionFilter(ScmConfiguration configuration) - { - super(configuration); - } -} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java index 4874247785..235136938a 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java @@ -33,8 +33,6 @@ package sonia.scm.repository.spi; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.collect.ImmutableSet; import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; @@ -45,8 +43,6 @@ import java.io.IOException; import java.util.Collections; import java.util.Set; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java index 654b586088..d20eedca9f 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java @@ -45,47 +45,27 @@ import sonia.scm.web.GitScmProtocolProviderWrapper; * @author Sebastian Sdorra */ @Extension -public class GitRepositoryServiceResolver implements RepositoryServiceResolver -{ +public class GitRepositoryServiceResolver implements RepositoryServiceResolver { - /** Field description */ public static final String TYPE = "git"; - //~--- constructors --------------------------------------------------------- - @Inject - public GitRepositoryServiceResolver(GitRepositoryHandler handler, GitScmProtocolProviderWrapper providerWrapper) - { + public GitRepositoryServiceResolver(GitRepositoryHandler handler, GitScmProtocolProviderWrapper providerWrapper) { this.handler = handler; this.providerWrapper = providerWrapper; } - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param repository - * - * @return - */ @Override - public GitRepositoryServiceProvider resolve(Repository repository) - { + public GitRepositoryServiceProvider resolve(Repository repository) { GitRepositoryServiceProvider provider = null; - if (TYPE.equalsIgnoreCase(repository.getType())) - { + if (TYPE.equalsIgnoreCase(repository.getType())) { provider = new GitRepositoryServiceProvider(handler, repository, providerWrapper.get(repository)); } return provider; } - //~--- fields --------------------------------------------------------------- - - /** Field description */ private final GitRepositoryHandler handler; private final GitScmProtocolProviderWrapper providerWrapper; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java index 5606b73762..e183555b3b 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java @@ -33,32 +33,24 @@ package sonia.scm.web; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import org.eclipse.jgit.http.server.GitSmartHttpTools; import sonia.scm.ClientMessages; -import sonia.scm.Priority; import sonia.scm.config.ScmConfiguration; -import sonia.scm.filter.Filters; import sonia.scm.repository.GitUtil; -import sonia.scm.web.filter.ProviderPermissionFilter; +import sonia.scm.web.filter.PermissionFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -//~--- JDK imports ------------------------------------------------------------ - /** * GitPermissionFilter decides if a git request requires write or read privileges. * * @author Sebastian Sdorra */ -@Priority(Filters.PRIORITY_AUTHORIZATION) -//@WebElement(value = GitServletModule.PATTERN_GIT) -public class GitPermissionFilter extends ProviderPermissionFilter +public class GitPermissionFilter extends PermissionFilter { private static final String PARAMETER_SERVICE = "service"; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java index 9b8d53caf2..e731e01a62 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java @@ -51,18 +51,6 @@ import sonia.scm.web.lfs.LfsBlobStoreFactory; public class GitServletModule extends ServletModule { - public static final String GIT_PATH = "/repo"; - - /** Field description */ - public static final String PATTERN_GIT = GIT_PATH + "/*"; - - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - */ @Override protected void configureServlets() { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java index 8ec81d43f3..2701764607 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServlet.java @@ -33,8 +33,6 @@ package sonia.scm.web; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -57,8 +55,6 @@ import java.util.regex.Pattern; import static org.eclipse.jgit.lfs.lib.Constants.CONTENT_TYPE_GIT_LFS_JSON; import static org.slf4j.LoggerFactory.getLogger; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra @@ -67,7 +63,8 @@ import static org.slf4j.LoggerFactory.getLogger; public class ScmGitServlet extends GitServlet implements ScmProviderHttpServlet { - /** Field description */ + public static final String REPO_PATH = "/repo"; + public static final Pattern REGEX_GITHTTPBACKEND = Pattern.compile( "(?x)^/repo/(.*/(HEAD|info/refs|objects/(info/[^/]+|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\\.(pack|idx))|git-(upload|receive)-pack))$" ); @@ -172,7 +169,7 @@ public class ScmGitServlet extends GitServlet implements ScmProviderHttpServlet * @throws IOException * @throws ServletException */ - private void handleBrowserRequest(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException { + private void handleBrowserRequest(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException { try { repositoryViewer.handleRequest(request, response, repository); } catch (IOException ex) { @@ -191,7 +188,7 @@ public class ScmGitServlet extends GitServlet implements ScmProviderHttpServlet */ private static boolean isLfsFileTransferRequest(HttpServletRequest request, String repository) { - String regex = String.format("^%s%s/%s(\\.git)?/info/lfs/objects/[a-z0-9]{64}$", request.getContextPath(), GitServletModule.GIT_PATH, repository); + String regex = String.format("^%s%s/%s(\\.git)?/info/lfs/objects/[a-z0-9]{64}$", request.getContextPath(), REPO_PATH, repository); boolean pathMatches = request.getRequestURI().matches(regex); boolean methodMatches = request.getMethod().equals("PUT") || request.getMethod().equals("GET"); @@ -210,7 +207,7 @@ public class ScmGitServlet extends GitServlet implements ScmProviderHttpServlet */ private static boolean isLfsBatchApiRequest(HttpServletRequest request, String repository) { - String regex = String.format("^%s%s/%s(\\.git)?/info/lfs/objects/batch$", request.getContextPath(), GitServletModule.GIT_PATH, repository); + String regex = String.format("^%s%s/%s(\\.git)?/info/lfs/objects/batch$", request.getContextPath(), REPO_PATH, repository); boolean pathMatches = request.getRequestURI().matches(regex); boolean methodMatches = "POST".equals(request.getMethod()); diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java index 1fc837029c..8c280a9915 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java @@ -33,8 +33,6 @@ package sonia.scm.repository.spi; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.io.Closeables; import sonia.scm.repository.Feature; import sonia.scm.repository.HgHookManager; @@ -49,8 +47,6 @@ import java.util.Collections; import java.util.EnumSet; import java.util.Set; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java index 08db6d1dbd..c1accbad1a 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java @@ -33,8 +33,6 @@ package sonia.scm.repository.spi; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.inject.Inject; import sonia.scm.plugin.Extension; import sonia.scm.repository.HgHookManager; diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgBasicAuthenticationFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgBasicAuthenticationFilter.java deleted file mode 100644 index abc295fd68..0000000000 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgBasicAuthenticationFilter.java +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (c) 2010, Sebastian Sdorra All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. 2. Redistributions in - * binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. 3. Neither the name of SCM-Manager; - * nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ - - - -package sonia.scm.web; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.Inject; - -import sonia.scm.Priority; -import sonia.scm.config.ScmConfiguration; -import sonia.scm.filter.Filters; -import sonia.scm.filter.WebElement; -import sonia.scm.web.filter.AuthenticationFilter; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - -import java.util.Set; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * - * @author Sebastian Sdorra - */ -@Priority(Filters.PRIORITY_AUTHENTICATION) -@WebElement(value = HgServletModule.MAPPING_HG) -public class HgBasicAuthenticationFilter extends AuthenticationFilter -{ - - /** - * Constructs ... - * - * - * @param configuration - * @param webTokenGenerators - */ - @Inject - public HgBasicAuthenticationFilter(ScmConfiguration configuration, - Set webTokenGenerators) - { - super(configuration, webTokenGenerators); - } - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param request - * @param response - * - * @throws IOException - */ - @Override - protected void sendFailedAuthenticationError(HttpServletRequest request, - HttpServletResponse response) - throws IOException - { - if (HgUtil.isHgClient(request) - && (configuration.isLoginAttemptLimitEnabled())) - { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - } - else - { - super.sendFailedAuthenticationError(request, response); - } - } -} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java index f3e6a54568..1821f92fa4 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java @@ -33,8 +33,6 @@ package sonia.scm.web; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.base.Stopwatch; import com.google.common.base.Strings; import com.google.inject.Inject; @@ -68,8 +66,6 @@ import java.io.IOException; import java.util.Base64; import java.util.Enumeration; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java index 3a1aba93e4..a2dccb30c9 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java @@ -33,43 +33,30 @@ package sonia.scm.web; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; import sonia.scm.config.ScmConfiguration; -import sonia.scm.web.filter.ProviderPermissionFilter; +import sonia.scm.web.filter.PermissionFilter; import javax.servlet.http.HttpServletRequest; import java.util.Set; -//~--- JDK imports ------------------------------------------------------------ - /** * Permission filter for mercurial repositories. * * @author Sebastian Sdorra */ -//@Priority(Filters.PRIORITY_AUTHORIZATION) -//@WebElement(value = HgServletModule.MAPPING_HG) -public class HgPermissionFilter extends ProviderPermissionFilter +public class HgPermissionFilter extends PermissionFilter { private static final Set READ_METHODS = ImmutableSet.of("GET", "HEAD", "OPTIONS", "TRACE"); - /** - * Constructs a new instance. - * - * @param configuration scm configuration - */ @Inject public HgPermissionFilter(ScmConfiguration configuration) { super(configuration); } - //~--- get methods ---------------------------------------------------------- - @Override public boolean isWriteRequest(HttpServletRequest request) { diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java index 21d1659bec..6c08d35897 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java @@ -33,8 +33,6 @@ package sonia.scm.repository.spi; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.collect.ImmutableSet; import com.google.common.io.Closeables; import sonia.scm.repository.Repository; @@ -46,8 +44,6 @@ import java.io.IOException; import java.util.Collections; import java.util.Set; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java index eb52ba55f0..9f5ea234ce 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java @@ -32,67 +32,34 @@ package sonia.scm.repository.spi; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.inject.Inject; import sonia.scm.plugin.Extension; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; import sonia.scm.web.SvnScmProtocolProviderWrapper; -/** - * - * @author Sebastian Sdorra - */ @Extension -public class SvnRepositoryServiceResolver implements RepositoryServiceResolver -{ +public class SvnRepositoryServiceResolver implements RepositoryServiceResolver { - /** Field description */ public static final String TYPE = "svn"; - //~--- constructors --------------------------------------------------------- - - /** - * Constructs ... - * - * - * @param handler - * @param protocolWrapper - */ @Inject - public SvnRepositoryServiceResolver(SvnRepositoryHandler handler, SvnScmProtocolProviderWrapper protocolWrapper) - { + public SvnRepositoryServiceResolver(SvnRepositoryHandler handler, SvnScmProtocolProviderWrapper protocolWrapper) { this.handler = handler; this.protocolWrapper = protocolWrapper; } - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param repository - * - * @return - */ @Override - public SvnRepositoryServiceProvider resolve(Repository repository) - { + public SvnRepositoryServiceProvider resolve(Repository repository) { SvnRepositoryServiceProvider provider = null; - if (TYPE.equalsIgnoreCase(repository.getType())) - { + if (TYPE.equalsIgnoreCase(repository.getType())) { provider = new SvnRepositoryServiceProvider(handler, repository, protocolWrapper.get(repository)); } return provider; } - //~--- fields --------------------------------------------------------------- - - /** Field description */ private SvnRepositoryHandler handler; private final InitializingHttpScmProtocolWrapper protocolWrapper; diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnBasicAuthenticationFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnBasicAuthenticationFilter.java deleted file mode 100644 index b5db32a449..0000000000 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnBasicAuthenticationFilter.java +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2010, Sebastian Sdorra All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. 2. Redistributions in - * binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. 3. Neither the name of SCM-Manager; - * nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ - - - -package sonia.scm.web; - -//~--- non-JDK imports -------------------------------------------------------- - -import com.google.inject.Inject; -import sonia.scm.config.ScmConfiguration; -import sonia.scm.repository.SvnUtil; -import sonia.scm.util.HttpUtil; -import sonia.scm.web.filter.AuthenticationFilter; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.Set; - -//~--- JDK imports ------------------------------------------------------------ - -/** - * - * @author Sebastian Sdorra - */ -//@Priority(Filters.PRIORITY_AUTHENTICATION) -//@WebElement(value = SvnServletModule.PATTERN_SVN) -public class SvnBasicAuthenticationFilter extends AuthenticationFilter -{ - - /** - * Constructs ... - * - * - * @param configuration - * @param webTokenGenerators - */ - @Inject - public SvnBasicAuthenticationFilter(ScmConfiguration configuration, Set webTokenGenerators) { - super(configuration, webTokenGenerators); - } - - //~--- methods -------------------------------------------------------------- - - /** - * Sends unauthorized instead of forbidden for svn clients, because the - * svn client prompts again for authentication. - * - * - * @param request http request - * @param response http response - * - * @throws IOException - */ - @Override - protected void sendFailedAuthenticationError(HttpServletRequest request, - HttpServletResponse response) - throws IOException - { - if (SvnUtil.isSvnClient(request)) - { - HttpUtil.sendUnauthorized(response, configuration.getRealmDescription()); - } - else - { - super.sendFailedAuthenticationError(request, response); - } - } -} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java index 35b420257d..92d01db5a1 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServlet.java @@ -33,8 +33,6 @@ package sonia.scm.web; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.inject.Inject; import com.google.inject.Singleton; import org.slf4j.Logger; @@ -55,8 +53,6 @@ import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java index 2939b44753..8918b8fa90 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java @@ -33,30 +33,24 @@ package sonia.scm.web; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; import sonia.scm.ClientMessages; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.ScmSvnErrorCode; import sonia.scm.repository.SvnUtil; -import sonia.scm.web.filter.ProviderPermissionFilter; +import sonia.scm.web.filter.PermissionFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Set; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra */ -//@Priority(Filters.PRIORITY_AUTHORIZATION) -//@WebElement(value = SvnServletModule.PATTERN_SVN) -public class SvnPermissionFilter extends ProviderPermissionFilter +public class SvnPermissionFilter extends PermissionFilter { /** Field description */ diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java index 90ac29aa12..4f96059429 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -12,10 +12,11 @@ import javax.servlet.ServletContext; import javax.servlet.ServletException; import java.util.Enumeration; -import static sonia.scm.web.SvnServletModule.PARAMETER_SVN_PARENTPATH; - @Singleton public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { + + public static final String PARAMETER_SVN_PARENTPATH = "SVNParentPath"; + @Inject public SvnScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore) { super(servletProvider, permissionFilter, uriInfoStore); @@ -24,14 +25,14 @@ public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWr @Override protected void initializeServlet(ServletConfig config, ScmProviderHttpServlet httpServlet) throws ServletException { - super.initializeServlet(new X(config), httpServlet); + super.initializeServlet(new SvnConfigEnhancer(config), httpServlet); } - private static class X implements ServletConfig { + private static class SvnConfigEnhancer implements ServletConfig { private final ServletConfig originalConfig; - private X(ServletConfig originalConfig) { + private SvnConfigEnhancer(ServletConfig originalConfig) { this.originalConfig = originalConfig; } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java index 9b9dc0bcb0..8526d6380a 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java @@ -33,43 +33,21 @@ package sonia.scm.web; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.inject.servlet.ServletModule; import org.mapstruct.factory.Mappers; import sonia.scm.api.v2.resources.SvnConfigDtoToSvnConfigMapper; import sonia.scm.api.v2.resources.SvnConfigToSvnConfigDtoMapper; import sonia.scm.plugin.Extension; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra */ @Extension -public class SvnServletModule extends ServletModule -{ +public class SvnServletModule extends ServletModule { - /** Field description */ - public static final String PARAMETER_SVN_PARENTPATH = "SVNParentPath"; - - /** Field description */ - public static final String PATTERN_SVN = "/svn/*"; - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - */ @Override - protected void configureServlets() - { - filter(PATTERN_SVN).through(SvnGZipFilter.class); -// filter(PATTERN_SVN).through(SvnBasicAuthenticationFilter.class); -// filter(PATTERN_SVN).through(SvnPermissionFilter.class); - + protected void configureServlets() { bind(SvnConfigDtoToSvnConfigMapper.class).to(Mappers.getMapper(SvnConfigDtoToSvnConfigMapper.class).getClass()); bind(SvnConfigToSvnConfigDtoMapper.class).to(Mappers.getMapper(SvnConfigToSvnConfigDtoMapper.class).getClass()); } diff --git a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java index cb272de38f..5a087a1c70 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java @@ -33,8 +33,6 @@ package sonia.scm; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.base.Throwables; import com.google.common.collect.Lists; import com.google.inject.Injector; @@ -63,8 +61,6 @@ import java.util.Collections; import java.util.List; import java.util.Set; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java index 14fb8552f9..fd330a6d1d 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java @@ -33,8 +33,6 @@ package sonia.scm; -//~--- non-JDK imports -------------------------------------------------------- - import com.fasterxml.jackson.databind.ObjectMapper; import com.google.inject.Provider; import com.google.inject.multibindings.Multibinder; @@ -121,8 +119,6 @@ import sonia.scm.web.security.DefaultAdministrationContext; import javax.net.ssl.SSLContext; import javax.servlet.ServletContext; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra @@ -188,14 +184,6 @@ public class ScmServletModule extends ServletModule //~--- constructors --------------------------------------------------------- - /** - * Constructs ... - * - * - * @param servletContext - * @param pluginLoader - * @param overrides - */ ScmServletModule(ServletContext servletContext, DefaultPluginLoader pluginLoader, ClassOverrides overrides) { this.servletContext = servletContext; diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java index 59ffbe560b..6ad9b6257e 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java @@ -33,8 +33,6 @@ package sonia.scm.api.rest.resources; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.base.Function; import com.google.common.collect.Collections2; import com.google.common.collect.Maps; @@ -59,8 +57,6 @@ import java.util.Comparator; import java.util.List; import java.util.Map; -//~--- JDK imports ------------------------------------------------------------ - /** * * @author Sebastian Sdorra diff --git a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java index 8638c7e4e8..1ddfb4a3d3 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java @@ -31,8 +31,6 @@ package sonia.scm.repository; -//~--- non-JDK imports -------------------------------------------------------- - import com.github.sdorra.ssp.PermissionActionCheck; import com.google.common.collect.Lists; import com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -67,8 +65,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; -//~--- JDK imports ------------------------------------------------------------ - /** * Default implementation of {@link RepositoryManager}. * diff --git a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryProvider.java b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryProvider.java index 3f061ff46d..62067db172 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryProvider.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryProvider.java @@ -33,30 +33,26 @@ package sonia.scm.repository; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.servlet.RequestScoped; -import sonia.scm.security.ScmSecurityException; import javax.servlet.http.HttpServletRequest; -//~--- JDK imports ------------------------------------------------------------ - @RequestScoped public class DefaultRepositoryProvider implements RepositoryProvider { public static final String ATTRIBUTE_NAME = "scm.request.repository"; private final Provider requestProvider; + @Inject public DefaultRepositoryProvider(Provider requestProvider) { this.requestProvider = requestProvider; } @Override - public Repository get() throws ScmSecurityException { + public Repository get() { HttpServletRequest request = requestProvider.get(); if (request != null) { From c21612bd8ef152e325b64e66e2d238ea921f0464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 11 Sep 2018 13:15:08 +0200 Subject: [PATCH 23/58] Fix permission git lfs integration test --- .../scm/web/filter/PermissionFilter.java | 30 +------------- .../api/v2/resources/UserToUserDtoMapper.java | 2 +- .../scm/web/protocol/HttpProtocolServlet.java | 1 + .../test/java/sonia/scm/it/GitLfsITCase.java | 40 ++++++++++++++++--- 4 files changed, 38 insertions(+), 35 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java index 3415c3e338..a01875fed0 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java @@ -33,7 +33,6 @@ package sonia.scm.web.filter; -import com.google.common.base.Splitter; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.subject.Subject; @@ -46,13 +45,11 @@ import sonia.scm.repository.RepositoryPermissions; import sonia.scm.security.Role; import sonia.scm.security.ScmSecurityException; import sonia.scm.util.HttpUtil; -import sonia.scm.util.Util; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.Iterator; /** * Abstract http filter to check repository permissions. @@ -121,7 +118,7 @@ public abstract class PermissionFilter getActionAsString(writeRequest), repository.getName(), getUserName(subject)); - continuation.serve(); + continuation.doService(); } else { @@ -172,29 +169,6 @@ public abstract class PermissionFilter HttpUtil.sendUnauthorized(response, configuration.getRealmDescription()); } - /** - * Extracts the type of the repositroy from url. - * - * - * @param request http request - * - * @return type of repository - */ - private String extractType(HttpServletRequest request) - { - Iterator it = Splitter.on( - HttpUtil.SEPARATOR_PATH).omitEmptyStrings().split( - request.getRequestURI()).iterator(); - String type = it.next(); - - if (Util.isNotEmpty(request.getContextPath())) - { - type = it.next(); - } - - return type; - } - /** * Send access denied to the servlet response. * @@ -287,6 +261,6 @@ public abstract class PermissionFilter @FunctionalInterface public interface ContinuationServlet { - void serve() throws ServletException, IOException; + void doService() throws ServletException, IOException; } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserToUserDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserToUserDtoMapper.java index 00aba5a700..97a3a21482 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserToUserDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserToUserDtoMapper.java @@ -33,7 +33,7 @@ public abstract class UserToUserDtoMapper extends BaseMapper { } @AfterMapping - void appendLinks(User user, @MappingTarget UserDto target) { + protected void appendLinks(User user, @MappingTarget UserDto target) { Links.Builder linksBuilder = linkingTo().self(resourceLinks.user().self(target.getName())); if (UserPermissions.delete(user).isPermitted()) { linksBuilder.single(link("delete", resourceLinks.user().delete(target.getName()))); diff --git a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java index 7ba4d2392c..2a02afe7f6 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java +++ b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java @@ -56,6 +56,7 @@ public class HttpProtocolServlet extends HttpServlet { log.trace("dispatch browser request for user agent {}", userAgent); dispatcher.dispatch(request, response, request.getRequestURI()); } else { + String pathInfo = request.getPathInfo(); Optional namespaceAndName = namespaceAndNameFromPathExtractor.fromUri(pathInfo); if (namespaceAndName.isPresent()) { diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java index b07f0c6067..7da9b8adfb 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java @@ -36,34 +36,39 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; import com.google.common.base.Charsets; +import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.UniformInterfaceException; import org.apache.shiro.crypto.hash.Sha256Hash; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import sonia.scm.api.rest.ObjectMapperProvider; import sonia.scm.api.v2.resources.RepositoryDto; +import sonia.scm.api.v2.resources.UserDto; +import sonia.scm.api.v2.resources.UserToUserDtoMapperImpl; import sonia.scm.repository.PermissionType; import sonia.scm.repository.Repository; import sonia.scm.user.User; import sonia.scm.user.UserTestData; import sonia.scm.util.HttpUtil; +import sonia.scm.web.VndMediaType; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import java.io.IOException; +import java.net.URI; import java.util.UUID; import static org.junit.Assert.assertArrayEquals; import static sonia.scm.it.IntegrationTestUtil.BASE_URL; import static sonia.scm.it.IntegrationTestUtil.REST_BASE_URL; import static sonia.scm.it.IntegrationTestUtil.createAdminClient; +import static sonia.scm.it.IntegrationTestUtil.createResource; import static sonia.scm.it.IntegrationTestUtil.readJson; import static sonia.scm.it.RepositoryITUtil.createRepository; import static sonia.scm.it.RepositoryITUtil.deleteRepository; @@ -112,7 +117,7 @@ public class GitLfsITCase { } @Test - @Ignore("permissions not yet implemented") +// @Ignore("permissions not yet implemented") public void testLfsAPIWithOwnerPermissions() throws IOException { uploadAndDownloadAsUser(PermissionType.OWNER); } @@ -126,6 +131,11 @@ public class GitLfsITCase { // TODO enable when permissions are implemented in v2 // repository.getPermissions().add(new Permission(trillian.getId(), permissionType)); // modifyRepository(repository); + String permissionsUrl = repository.getLinks().getLinkBy("permissions").get().getHref(); + IntegrationTestUtil.createResource(adminClient, URI.create(permissionsUrl)) + .accept("*/*") + .type(VndMediaType.PERMISSION) + .post(ClientResponse.class, "{\"name\": \""+ trillian.getId() +"\", \"type\":\"WRITE\"}"); ScmClient client = new ScmClient(trillian.getId(), "secret123"); @@ -136,13 +146,21 @@ public class GitLfsITCase { } @Test - @Ignore("permissions not yet implemented") +// @Ignore("permissions not yet implemented") public void testLfsAPIWithWritePermissions() throws IOException { uploadAndDownloadAsUser(PermissionType.WRITE); } private void createUser(User user) { - adminClient.resource(REST_BASE_URL + "users.json").post(user); + UserDto dto = new UserToUserDtoMapperImpl(){ + @Override + protected void appendLinks(User user, UserDto target) {} + }.map(user); + dto.setPassword(user.getPassword()); + createResource(adminClient, "users") + .accept("*/*") + .type(VndMediaType.USER) + .post(ClientResponse.class, dto); } private void modifyRepository(Repository repository) { @@ -154,7 +172,7 @@ public class GitLfsITCase { } @Test - @Ignore("permissions not yet implemented") +// @Ignore("permissions not yet implemented") public void testLfsAPIWithoutWritePermissions() throws IOException { User trillian = UserTestData.createTrillian(); trillian.setPassword("secret123"); @@ -168,6 +186,11 @@ public class GitLfsITCase { // TODO enable when permissions are implemented in v2 // repository.getPermissions().add(new Permission(trillian.getId(), PermissionType.READ)); // modifyRepository(repository); + String permissionsUrl = repository.getLinks().getLinkBy("permissions").get().getHref(); + IntegrationTestUtil.createResource(adminClient, URI.create(permissionsUrl)) + .accept("*/*") + .type(VndMediaType.PERMISSION) + .post(ClientResponse.class, "{\"name\": \""+ trillian.getId() +"\", \"type\":\"READ\"}"); ScmClient client = new ScmClient(trillian.getId(), "secret123"); uploadAndDownload(client); @@ -177,7 +200,7 @@ public class GitLfsITCase { } @Test - @Ignore("permissions not yet implemented") +// @Ignore("permissions not yet implemented") public void testLfsDownloadWithReadPermissions() throws IOException { User trillian = UserTestData.createTrillian(); trillian.setPassword("secret123"); @@ -188,6 +211,11 @@ public class GitLfsITCase { // TODO enable when permissions are implemented in v2 // repository.getPermissions().add(new Permission(trillian.getId(), PermissionType.READ)); // modifyRepository(repository); + String permissionsUrl = repository.getLinks().getLinkBy("permissions").get().getHref(); + IntegrationTestUtil.createResource(adminClient, URI.create(permissionsUrl)) + .accept("*/*") + .type(VndMediaType.PERMISSION) + .post(ClientResponse.class, "{\"name\": \""+ trillian.getId() +"\", \"type\":\"READ\"}"); // upload data as admin String data = UUID.randomUUID().toString(); From b3088fa7622eab080ea916f0f6053be55fe3f326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 11 Sep 2018 14:28:07 +0200 Subject: [PATCH 24/58] Delete user after test --- .../test/java/sonia/scm/it/GitLfsITCase.java | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java index 7da9b8adfb..611a584485 100644 --- a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java +++ b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java @@ -51,7 +51,6 @@ import sonia.scm.api.v2.resources.RepositoryDto; import sonia.scm.api.v2.resources.UserDto; import sonia.scm.api.v2.resources.UserToUserDtoMapperImpl; import sonia.scm.repository.PermissionType; -import sonia.scm.repository.Repository; import sonia.scm.user.User; import sonia.scm.user.UserTestData; import sonia.scm.util.HttpUtil; @@ -117,7 +116,6 @@ public class GitLfsITCase { } @Test -// @Ignore("permissions not yet implemented") public void testLfsAPIWithOwnerPermissions() throws IOException { uploadAndDownloadAsUser(PermissionType.OWNER); } @@ -128,9 +126,6 @@ public class GitLfsITCase { createUser(trillian); try { - // TODO enable when permissions are implemented in v2 -// repository.getPermissions().add(new Permission(trillian.getId(), permissionType)); -// modifyRepository(repository); String permissionsUrl = repository.getLinks().getLinkBy("permissions").get().getHref(); IntegrationTestUtil.createResource(adminClient, URI.create(permissionsUrl)) .accept("*/*") @@ -146,7 +141,6 @@ public class GitLfsITCase { } @Test -// @Ignore("permissions not yet implemented") public void testLfsAPIWithWritePermissions() throws IOException { uploadAndDownloadAsUser(PermissionType.WRITE); } @@ -163,16 +157,11 @@ public class GitLfsITCase { .post(ClientResponse.class, dto); } - private void modifyRepository(Repository repository) { - adminClient.resource(REST_BASE_URL + "repositories/" + repository.getId() + ".json").put(repository); - } - private void removeUser(User user) { - adminClient.resource(REST_BASE_URL + "users/" + user.getId() + ".json").delete(); + adminClient.resource(REST_BASE_URL + "users/" + user.getId()).delete(); } @Test -// @Ignore("permissions not yet implemented") public void testLfsAPIWithoutWritePermissions() throws IOException { User trillian = UserTestData.createTrillian(); trillian.setPassword("secret123"); @@ -183,9 +172,6 @@ public class GitLfsITCase { try { - // TODO enable when permissions are implemented in v2 -// repository.getPermissions().add(new Permission(trillian.getId(), PermissionType.READ)); -// modifyRepository(repository); String permissionsUrl = repository.getLinks().getLinkBy("permissions").get().getHref(); IntegrationTestUtil.createResource(adminClient, URI.create(permissionsUrl)) .accept("*/*") @@ -200,7 +186,6 @@ public class GitLfsITCase { } @Test -// @Ignore("permissions not yet implemented") public void testLfsDownloadWithReadPermissions() throws IOException { User trillian = UserTestData.createTrillian(); trillian.setPassword("secret123"); @@ -208,9 +193,6 @@ public class GitLfsITCase { try { - // TODO enable when permissions are implemented in v2 -// repository.getPermissions().add(new Permission(trillian.getId(), PermissionType.READ)); -// modifyRepository(repository); String permissionsUrl = repository.getLinks().getLinkBy("permissions").get().getHref(); IntegrationTestUtil.createResource(adminClient, URI.create(permissionsUrl)) .accept("*/*") From 5b35fb2372515f45f336a13de5452119b2498c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 11 Sep 2018 16:03:32 +0200 Subject: [PATCH 25/58] Fallback to configured base url if UriInfoStore not set --- .../scm/repository/spi/HttpScmProtocol.java | 9 ++--- .../InitializingHttpScmProtocolWrapper.java | 16 +++++++- .../repository/api/RepositoryServiceTest.java | 3 +- .../repository/spi/HttpScmProtocolTest.java | 40 +++++++++++++++++++ .../web/GitScmProtocolProviderWrapper.java | 5 ++- .../scm/web/HgScmProtocolProviderWrapper.java | 5 ++- .../web/SvnScmProtocolProviderWrapper.java | 5 ++- 7 files changed, 68 insertions(+), 15 deletions(-) create mode 100644 scm-core/src/test/java/sonia/scm/repository/spi/HttpScmProtocolTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java index b93deba10a..7ec47ea284 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java @@ -7,18 +7,17 @@ import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.net.URI; public abstract class HttpScmProtocol implements ScmProtocol { private final Repository repository; - private final UriInfo uriInfo; + private final String basePath; - public HttpScmProtocol(Repository repository, UriInfo uriInfo) { + public HttpScmProtocol(Repository repository, String basePath) { this.repository = repository; - this.uriInfo = uriInfo; + this.basePath = basePath; } @Override @@ -28,7 +27,7 @@ public abstract class HttpScmProtocol implements ScmProtocol { @Override public String getUrl() { - return uriInfo.getBaseUri().resolve(URI.create("../../repo/" + repository.getNamespace() + "/" + repository.getName())).toASCIIString(); + return URI.create(basePath + "/").resolve("repo/" + repository.getNamespace() + "/" + repository.getName()).toASCIIString(); } public final void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException { diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 3d4d3c6205..b54b5c812c 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -3,6 +3,7 @@ package sonia.scm.repository.spi; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.api.v2.resources.UriInfoStore; +import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; import sonia.scm.web.filter.PermissionFilter; @@ -21,14 +22,16 @@ public abstract class InitializingHttpScmProtocolWrapper { private final Provider delegateProvider; private final Provider permissionFilterProvider; private final Provider uriInfoStore; + private final ScmConfiguration scmConfiguration; private volatile boolean isInitialized = false; - protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider permissionFilterProvider, Provider uriInfoStore) { + protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider permissionFilterProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { this.delegateProvider = delegateProvider; this.permissionFilterProvider = permissionFilterProvider; this.uriInfoStore = uriInfoStore; + this.scmConfiguration = scmConfiguration; } protected void initializeServlet(ServletConfig config, ScmProviderHttpServlet httpServlet) throws ServletException { @@ -39,10 +42,18 @@ public abstract class InitializingHttpScmProtocolWrapper { return new ProtocolWrapper(repository); } + private String computeBasePath() { + if (uriInfoStore.get() != null) { + return uriInfoStore.get().get().getBaseUri().resolve("../..").toASCIIString(); + } else { + return scmConfiguration.getBaseUrl(); + } + } + private class ProtocolWrapper extends HttpScmProtocol { public ProtocolWrapper(Repository repository) { - super(repository, uriInfoStore.get().get()); + super(repository, computeBasePath()); } @Override @@ -63,5 +74,6 @@ public abstract class InitializingHttpScmProtocolWrapper { repository, () -> delegateProvider.get().service(request, response, repository)); } + } } diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java index 1783d17936..9cb398b571 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java @@ -8,7 +8,6 @@ import sonia.scm.repository.spi.RepositoryServiceProvider; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.UriInfo; import java.util.Collection; import java.util.Collections; @@ -46,7 +45,7 @@ public class RepositoryServiceTest { private static class DummyHttpProtocol extends HttpScmProtocol { public DummyHttpProtocol(Repository repository) { - super(repository, mock(UriInfo.class)); + super(repository, ""); } @Override diff --git a/scm-core/src/test/java/sonia/scm/repository/spi/HttpScmProtocolTest.java b/scm-core/src/test/java/sonia/scm/repository/spi/HttpScmProtocolTest.java new file mode 100644 index 0000000000..1fd772fee3 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/repository/spi/HttpScmProtocolTest.java @@ -0,0 +1,40 @@ +package sonia.scm.repository.spi; + +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; +import sonia.scm.repository.Repository; + +import javax.servlet.ServletConfig; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +class HttpScmProtocolTest { + + @TestFactory + Stream shouldCreateCorrectUrlsWithContextPath() { + return Stream.of("http://localhost/scm", "http://localhost/scm/") + .map(url -> assertResultingUrl(url, "http://localhost/scm/repo/space/name")); + } + + @TestFactory + Stream shouldCreateCorrectUrlsWithPort() { + return Stream.of("http://localhost:8080", "http://localhost:8080/") + .map(url -> assertResultingUrl(url, "http://localhost:8080/repo/space/name")); + } + + DynamicTest assertResultingUrl(String baseUrl, String expectedUrl) { + String actualUrl = createInstanceOfHttpScmProtocol(baseUrl).getUrl(); + return DynamicTest.dynamicTest(baseUrl + " -> " + expectedUrl, () -> assertThat(actualUrl).isEqualTo(expectedUrl)); + } + + private HttpScmProtocol createInstanceOfHttpScmProtocol(String baseUrl) { + return new HttpScmProtocol(new Repository("", "", "space", "name"), baseUrl) { + @Override + protected void serve(HttpServletRequest request, HttpServletResponse response, Repository repository, ServletConfig config) { + } + }; + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java index ae378c2439..cda8431283 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java @@ -1,6 +1,7 @@ package sonia.scm.web; import sonia.scm.api.v2.resources.UriInfoStore; +import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import javax.inject.Inject; @@ -10,7 +11,7 @@ import javax.inject.Singleton; @Singleton public class GitScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public GitScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore) { - super(servletProvider, permissionFilter, uriInfoStore); + public GitScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java index ba5c40e7f9..9cb22363ce 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java @@ -1,6 +1,7 @@ package sonia.scm.web; import sonia.scm.api.v2.resources.UriInfoStore; +import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import javax.inject.Inject; @@ -10,7 +11,7 @@ import javax.inject.Singleton; @Singleton public class HgScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public HgScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore) { - super(servletProvider, permissionFilter, uriInfoStore); + public HgScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java index 4f96059429..99f5b42fb2 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -1,6 +1,7 @@ package sonia.scm.web; import sonia.scm.api.v2.resources.UriInfoStore; +import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import sonia.scm.repository.spi.ScmProviderHttpServlet; @@ -18,8 +19,8 @@ public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWr public static final String PARAMETER_SVN_PARENTPATH = "SVNParentPath"; @Inject - public SvnScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore) { - super(servletProvider, permissionFilter, uriInfoStore); + public SvnScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); } @Override From e5e3e678ad3c3a922aa1bccf618e54377f0e99ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 11 Sep 2018 16:26:20 +0200 Subject: [PATCH 26/58] Correct check for set UriInfo --- .../repository/spi/InitializingHttpScmProtocolWrapper.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index b54b5c812c..6e6a3cb512 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -1,7 +1,5 @@ package sonia.scm.repository.spi; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import sonia.scm.api.v2.resources.UriInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; @@ -16,9 +14,6 @@ import java.io.IOException; public abstract class InitializingHttpScmProtocolWrapper { - private static final Logger logger = - LoggerFactory.getLogger(InitializingHttpScmProtocolWrapper.class); - private final Provider delegateProvider; private final Provider permissionFilterProvider; private final Provider uriInfoStore; @@ -43,7 +38,7 @@ public abstract class InitializingHttpScmProtocolWrapper { } private String computeBasePath() { - if (uriInfoStore.get() != null) { + if (uriInfoStore.get() != null && uriInfoStore.get().get() != null) { return uriInfoStore.get().get().getBaseUri().resolve("../..").toASCIIString(); } else { return scmConfiguration.getBaseUrl(); From f718a2ba4c2cdc4e7030558824a076a4b6095464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Sep 2018 08:40:41 +0200 Subject: [PATCH 27/58] Remove direct dependency to UriInfo --- .../scm/api/v2/resources/LinkBuilder.java | 9 ++--- .../scm/api/v2/resources/ScmPathInfo.java | 7 ++++ .../scm/api/v2/resources/UriInfoStore.java | 5 ++- .../InitializingHttpScmProtocolWrapper.java | 2 +- .../v2/resources/GitConfigResourceTest.java | 2 +- .../GitConfigToGitConfigDtoMapperTest.java | 2 +- .../HgConfigInstallationsResourceTest.java | 2 +- .../HgConfigInstallationsToDtoMapperTest.java | 2 +- .../HgConfigPackageResourceTest.java | 2 +- .../HgConfigPackagesToDtoMapperTest.java | 5 +-- .../v2/resources/HgConfigResourceTest.java | 2 +- .../HgConfigToHgConfigDtoMapperTest.java | 2 +- .../v2/resources/SvnConfigResourceTest.java | 2 +- .../SvnConfigToSvnConfigDtoMapperTest.java | 2 +- .../scm/api/v2/resources/ResourceLinks.java | 39 +++++++++---------- .../scm/api/v2/resources/LinkBuilderTest.java | 5 +-- .../scm/api/v2/resources/MeResourceTest.java | 5 +-- .../resources/RepositoryRootResourceTest.java | 5 +-- .../RepositoryToRepositoryDtoMapperTest.java | 5 +-- .../api/v2/resources/ResourceLinksMock.java | 5 +-- .../api/v2/resources/ResourceLinksTest.java | 5 +-- .../api/v2/resources/UriInfoStoreTest.java | 9 ++++- 22 files changed, 64 insertions(+), 60 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkBuilder.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkBuilder.java index 6f6831b058..13ae04b093 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkBuilder.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkBuilder.java @@ -3,7 +3,6 @@ package sonia.scm.api.v2.resources; import com.google.common.collect.ImmutableList; import javax.ws.rs.core.UriBuilder; -import javax.ws.rs.core.UriInfo; import java.net.URI; import java.util.Arrays; @@ -25,15 +24,15 @@ import java.util.Arrays; */ @SuppressWarnings("WeakerAccess") // Non-public will result in IllegalAccessError for plugins public class LinkBuilder { - private final UriInfo uriInfo; + private final ScmPathInfo uriInfo; private final Class[] classes; private final ImmutableList calls; - public LinkBuilder(UriInfo uriInfo, Class... classes) { + public LinkBuilder(ScmPathInfo uriInfo, Class... classes) { this(uriInfo, classes, ImmutableList.of()); } - private LinkBuilder(UriInfo uriInfo, Class[] classes, ImmutableList calls) { + private LinkBuilder(ScmPathInfo uriInfo, Class[] classes, ImmutableList calls) { this.uriInfo = uriInfo; this.classes = classes; this.calls = calls; @@ -51,7 +50,7 @@ public class LinkBuilder { throw new IllegalStateException("not enough methods for all classes"); } - URI baseUri = uriInfo.getBaseUri(); + URI baseUri = uriInfo.getApiRestUri(); URI relativeUri = createRelativeUri(); return baseUri.resolve(relativeUri); } diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java new file mode 100644 index 0000000000..0afb379eed --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java @@ -0,0 +1,7 @@ +package sonia.scm.api.v2.resources; + +import java.net.URI; + +public interface ScmPathInfo { + URI getApiRestUri(); +} diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java index 2f61383cfd..5193ea6937 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java @@ -6,8 +6,8 @@ public class UriInfoStore { private UriInfo uriInfo; - public UriInfo get() { - return uriInfo; + public ScmPathInfo get() { + return () -> uriInfo.getBaseUri(); } public void set(UriInfo uriInfo) { @@ -16,4 +16,5 @@ public class UriInfoStore { } this.uriInfo = uriInfo; } + } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 6e6a3cb512..651e4b3a7d 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -39,7 +39,7 @@ public abstract class InitializingHttpScmProtocolWrapper { private String computeBasePath() { if (uriInfoStore.get() != null && uriInfoStore.get().get() != null) { - return uriInfoStore.get().get().getBaseUri().resolve("../..").toASCIIString(); + return uriInfoStore.get().get().getApiRestUri().resolve("../..").toASCIIString(); } else { return scmConfiguration.getBaseUrl(); } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java index 42790ea7a4..44603a65d3 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java @@ -67,7 +67,7 @@ public class GitConfigResourceTest { when(repositoryHandler.getConfig()).thenReturn(gitConfig); GitConfigResource gitConfigResource = new GitConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler); dispatcher.getRegistry().addSingletonResource(gitConfigResource); - when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); + when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); } @Test diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapperTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapperTest.java index 51fded4839..903ee4e653 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapperTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapperTest.java @@ -40,7 +40,7 @@ public class GitConfigToGitConfigDtoMapperTest { @Before public void init() { - when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); + when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); expectedBaseUri = baseUri.resolve(GitConfigResource.GIT_CONFIG_PATH_V2); subjectThreadState.bind(); ThreadContext.bind(subject); diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java index 540a5b6757..748b2c1b6e 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java @@ -61,7 +61,7 @@ public class HgConfigInstallationsResourceTest { new HgConfigResource(null, null, null, null, null, resourceProvider)); - when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); + when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); } @Test diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapperTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapperTest.java index 34048f80b2..fcc90ee4e6 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapperTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapperTest.java @@ -34,7 +34,7 @@ public class HgConfigInstallationsToDtoMapperTest { @Before public void init() { - when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); + when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); expectedBaseUri = baseUri.resolve(HgConfigResource.HG_CONFIG_PATH_V2 + "/installations/" + expectedPath); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java index 044897ad80..f24b30f515 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java @@ -81,7 +81,7 @@ public class HgConfigPackageResourceTest { public void prepareEnvironment() { setupResources(); - when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); + when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); when(hgPackageReader.getPackages().getPackages()).thenReturn(createPackages()); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapperTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapperTest.java index 671d9fb7e1..0773499462 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapperTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapperTest.java @@ -1,6 +1,5 @@ package sonia.scm.api.v2.resources; -import de.otto.edison.hal.HalRepresentation; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -13,12 +12,10 @@ import sonia.scm.installer.HgPackages; import java.net.URI; import java.util.Arrays; -import java.util.Collection; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; import static sonia.scm.api.v2.resources.HgConfigTests.assertEqualsPackage; import static sonia.scm.api.v2.resources.HgConfigTests.createPackage; @@ -38,7 +35,7 @@ public class HgConfigPackagesToDtoMapperTest { @Before public void init() { - when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); + when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); expectedBaseUri = baseUri.resolve(HgConfigResource.HG_CONFIG_PATH_V2 + "/packages"); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java index 11a0fb55f9..aa29603ff1 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java @@ -79,7 +79,7 @@ public class HgConfigResourceTest { new HgConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler, packagesResource, autoconfigResource, installationsResource); dispatcher.getRegistry().addSingletonResource(gitConfigResource); - when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); + when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); } @Test diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapperTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapperTest.java index a12e95926c..3f22c12f86 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapperTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapperTest.java @@ -41,7 +41,7 @@ public class HgConfigToHgConfigDtoMapperTest { @Before public void init() { - when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); + when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); expectedBaseUri = baseUri.resolve(HgConfigResource.HG_CONFIG_PATH_V2); subjectThreadState.bind(); ThreadContext.bind(subject); diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java index de4d654910..67f3e47950 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java @@ -67,7 +67,7 @@ public class SvnConfigResourceTest { when(repositoryHandler.getConfig()).thenReturn(gitConfig); SvnConfigResource gitConfigResource = new SvnConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler); dispatcher.getRegistry().addSingletonResource(gitConfigResource); - when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); + when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); } @Test diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapperTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapperTest.java index de7b0ecd31..cfe2c59772 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapperTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapperTest.java @@ -42,7 +42,7 @@ public class SvnConfigToSvnConfigDtoMapperTest { @Before public void init() { - when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); + when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); expectedBaseUri = baseUri.resolve(SvnConfigResource.SVN_CONFIG_PATH_V2); subjectThreadState.bind(); ThreadContext.bind(subject); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java index 11258745a8..7059ea257d 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java @@ -3,7 +3,6 @@ package sonia.scm.api.v2.resources; import sonia.scm.repository.NamespaceAndName; import javax.inject.Inject; -import javax.ws.rs.core.UriInfo; import java.net.URI; class ResourceLinks { @@ -23,7 +22,7 @@ class ResourceLinks { static class GroupLinks { private final LinkBuilder groupLinkBuilder; - GroupLinks(UriInfo uriInfo) { + GroupLinks(ScmPathInfo uriInfo) { groupLinkBuilder = new LinkBuilder(uriInfo, GroupRootResource.class, GroupResource.class); } @@ -47,7 +46,7 @@ class ResourceLinks { static class GroupCollectionLinks { private final LinkBuilder collectionLinkBuilder; - GroupCollectionLinks(UriInfo uriInfo) { + GroupCollectionLinks(ScmPathInfo uriInfo) { collectionLinkBuilder = new LinkBuilder(uriInfo, GroupRootResource.class, GroupCollectionResource.class); } @@ -67,7 +66,7 @@ class ResourceLinks { static class UserLinks { private final LinkBuilder userLinkBuilder; - UserLinks(UriInfo uriInfo) { + UserLinks(ScmPathInfo uriInfo) { userLinkBuilder = new LinkBuilder(uriInfo, UserRootResource.class, UserResource.class); } @@ -91,7 +90,7 @@ class ResourceLinks { static class UserCollectionLinks { private final LinkBuilder collectionLinkBuilder; - UserCollectionLinks(UriInfo uriInfo) { + UserCollectionLinks(ScmPathInfo uriInfo) { collectionLinkBuilder = new LinkBuilder(uriInfo, UserRootResource.class, UserCollectionResource.class); } @@ -111,7 +110,7 @@ class ResourceLinks { static class ConfigLinks { private final LinkBuilder configLinkBuilder; - ConfigLinks(UriInfo uriInfo) { + ConfigLinks(ScmPathInfo uriInfo) { configLinkBuilder = new LinkBuilder(uriInfo, ConfigResource.class); } @@ -130,9 +129,9 @@ class ResourceLinks { static class RepositoryLinks { private final LinkBuilder repositoryLinkBuilder; - private final UriInfo uriInfo; + private final ScmPathInfo uriInfo; - RepositoryLinks(UriInfo uriInfo) { + RepositoryLinks(ScmPathInfo uriInfo) { repositoryLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class); this.uriInfo = uriInfo; } @@ -157,7 +156,7 @@ class ResourceLinks { static class RepositoryCollectionLinks { private final LinkBuilder collectionLinkBuilder; - RepositoryCollectionLinks(UriInfo uriInfo) { + RepositoryCollectionLinks(ScmPathInfo uriInfo) { collectionLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryCollectionResource.class); } @@ -177,7 +176,7 @@ class ResourceLinks { static class RepositoryTypeLinks { private final LinkBuilder repositoryTypeLinkBuilder; - RepositoryTypeLinks(UriInfo uriInfo) { + RepositoryTypeLinks(ScmPathInfo uriInfo) { repositoryTypeLinkBuilder = new LinkBuilder(uriInfo, RepositoryTypeRootResource.class, RepositoryTypeResource.class); } @@ -193,7 +192,7 @@ class ResourceLinks { static class RepositoryTypeCollectionLinks { private final LinkBuilder collectionLinkBuilder; - RepositoryTypeCollectionLinks(UriInfo uriInfo) { + RepositoryTypeCollectionLinks(ScmPathInfo uriInfo) { collectionLinkBuilder = new LinkBuilder(uriInfo, RepositoryTypeRootResource.class, RepositoryTypeCollectionResource.class); } @@ -210,7 +209,7 @@ class ResourceLinks { static class TagCollectionLinks { private final LinkBuilder tagLinkBuilder; - TagCollectionLinks(UriInfo uriInfo) { + TagCollectionLinks(ScmPathInfo uriInfo) { tagLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, TagRootResource.class); } @@ -230,7 +229,7 @@ class ResourceLinks { static class DiffLinks { private final LinkBuilder diffLinkBuilder; - DiffLinks(UriInfo uriInfo) { + DiffLinks(ScmPathInfo uriInfo) { diffLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, DiffRootResource.class); } @@ -250,7 +249,7 @@ class ResourceLinks { static class BranchLinks { private final LinkBuilder branchLinkBuilder; - BranchLinks(UriInfo uriInfo) { + BranchLinks(ScmPathInfo uriInfo) { branchLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, BranchRootResource.class); } @@ -270,7 +269,7 @@ class ResourceLinks { static class BranchCollectionLinks { private final LinkBuilder branchLinkBuilder; - BranchCollectionLinks(UriInfo uriInfo) { + BranchCollectionLinks(ScmPathInfo uriInfo) { branchLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, BranchRootResource.class); } @@ -286,7 +285,7 @@ class ResourceLinks { static class ChangesetLinks { private final LinkBuilder changesetLinkBuilder; - ChangesetLinks(UriInfo uriInfo) { + ChangesetLinks(ScmPathInfo uriInfo) { changesetLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, ChangesetRootResource.class); } @@ -310,7 +309,7 @@ class ResourceLinks { static class SourceLinks { private final LinkBuilder sourceLinkBuilder; - SourceLinks(UriInfo uriInfo) { + SourceLinks(ScmPathInfo uriInfo) { sourceLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, SourceRootResource.class); } @@ -346,7 +345,7 @@ class ResourceLinks { static class PermissionLinks { private final LinkBuilder permissionLinkBuilder; - PermissionLinks(UriInfo uriInfo) { + PermissionLinks(ScmPathInfo uriInfo) { permissionLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, PermissionRootResource.class); } @@ -383,7 +382,7 @@ class ResourceLinks { static class UIPluginLinks { private final LinkBuilder uiPluginLinkBuilder; - UIPluginLinks(UriInfo uriInfo) { + UIPluginLinks(ScmPathInfo uriInfo) { uiPluginLinkBuilder = new LinkBuilder(uriInfo, UIRootResource.class, UIPluginResource.class); } @@ -399,7 +398,7 @@ class ResourceLinks { static class UIPluginCollectionLinks { private final LinkBuilder uiPluginCollectionLinkBuilder; - UIPluginCollectionLinks(UriInfo uriInfo) { + UIPluginCollectionLinks(ScmPathInfo uriInfo) { uiPluginCollectionLinkBuilder = new LinkBuilder(uriInfo, UIRootResource.class, UIPluginResource.class); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/LinkBuilderTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/LinkBuilderTest.java index 37c584dfdf..c84e1a21a7 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/LinkBuilderTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/LinkBuilderTest.java @@ -4,7 +4,6 @@ import org.junit.Before; import org.junit.Test; import javax.ws.rs.Path; -import javax.ws.rs.core.UriInfo; import java.net.URI; import java.net.URISyntaxException; @@ -37,7 +36,7 @@ public class LinkBuilderTest { } } - private UriInfo uriInfo = mock(UriInfo.class); + private ScmPathInfo uriInfo = mock(ScmPathInfo.class); @Test public void shouldBuildSimplePath() { @@ -94,6 +93,6 @@ public class LinkBuilderTest { @Before public void setBaseUri() throws URISyntaxException { - when(uriInfo.getBaseUri()).thenReturn(new URI("http://example.com/")); + when(uriInfo.getApiRestUri()).thenReturn(new URI("http://example.com/")); } } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java index 09dd545eb5..0040e8b45e 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeResourceTest.java @@ -17,7 +17,6 @@ import sonia.scm.user.UserManager; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.UriInfo; import java.net.URI; import java.net.URISyntaxException; @@ -40,7 +39,7 @@ public class MeResourceTest { private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(URI.create("/")); @Mock - private UriInfo uriInfo; + private ScmPathInfo uriInfo; @Mock private UriInfoStore uriInfoStore; @@ -62,7 +61,7 @@ public class MeResourceTest { userToDtoMapper.setResourceLinks(resourceLinks); MeResource meResource = new MeResource(userToDtoMapper, userManager); dispatcher.getRegistry().addSingletonResource(meResource); - when(uriInfo.getBaseUri()).thenReturn(URI.create("/")); + when(uriInfo.getApiRestUri()).thenReturn(URI.create("/")); when(uriInfoStore.get()).thenReturn(uriInfo); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index 609ff282af..9fdef26d13 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -24,7 +24,6 @@ import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.web.VndMediaType; import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -73,7 +72,7 @@ public class RepositoryRootResourceTest { @Mock private UriInfoStore uriInfoStore; @Mock - private UriInfo uriInfo; + private ScmPathInfo uriInfo; private final URI baseUri = URI.create("/"); @@ -93,7 +92,7 @@ public class RepositoryRootResourceTest { RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(repositoryResource), MockProvider.of(repositoryCollectionResource)); when(serviceFactory.create(any(Repository.class))).thenReturn(service); when(uriInfoStore.get()).thenReturn(uriInfo); - when(uriInfo.getBaseUri()).thenReturn(URI.create("/x/y")); + when(uriInfo.getApiRestUri()).thenReturn(URI.create("/x/y")); dispatcher = createDispatcher(repositoryRootResource); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java index b77ad958c3..250da56908 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java @@ -18,7 +18,6 @@ import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.repository.api.ScmProtocol; -import javax.ws.rs.core.UriInfo; import java.net.URI; import static java.util.Arrays.asList; @@ -51,7 +50,7 @@ public class RepositoryToRepositoryDtoMapperTest { @Mock private UriInfoStore uriInfoStore; @Mock - private UriInfo uriInfo; + private ScmPathInfo uriInfo; @InjectMocks private RepositoryToRepositoryDtoMapperImpl mapper; @@ -63,7 +62,7 @@ public class RepositoryToRepositoryDtoMapperTest { when(repositoryService.isSupported(any(Command.class))).thenReturn(true); when(repositoryService.getSupportedProtocols()).thenReturn(emptySet()); when(uriInfoStore.get()).thenReturn(uriInfo); - when(uriInfo.getBaseUri()).thenReturn(URI.create("/x/y")); + when(uriInfo.getApiRestUri()).thenReturn(URI.create("/x/y")); } @After diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java index f9ace9f8f6..1df652ea26 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java @@ -1,6 +1,5 @@ package sonia.scm.api.v2.resources; -import javax.ws.rs.core.UriInfo; import java.net.URI; import static org.mockito.Mockito.mock; @@ -10,8 +9,8 @@ public class ResourceLinksMock { public static ResourceLinks createMock(URI baseUri) { ResourceLinks resourceLinks = mock(ResourceLinks.class); - UriInfo uriInfo = mock(UriInfo.class); - when(uriInfo.getBaseUri()).thenReturn(baseUri); + ScmPathInfo uriInfo = mock(ScmPathInfo.class); + when(uriInfo.getApiRestUri()).thenReturn(baseUri); when(resourceLinks.user()).thenReturn(new ResourceLinks.UserLinks(uriInfo)); when(resourceLinks.userCollection()).thenReturn(new ResourceLinks.UserCollectionLinks(uriInfo)); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksTest.java index a9209828c3..0f33476436 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksTest.java @@ -6,7 +6,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import sonia.scm.repository.NamespaceAndName; -import javax.ws.rs.core.UriInfo; import java.net.URI; import static org.junit.Assert.assertEquals; @@ -20,7 +19,7 @@ public class ResourceLinksTest { @Mock private UriInfoStore uriInfoStore; @Mock - private UriInfo uriInfo; + private ScmPathInfo uriInfo; @InjectMocks private ResourceLinks resourceLinks; @@ -178,6 +177,6 @@ public class ResourceLinksTest { public void initUriInfo() { initMocks(this); when(uriInfoStore.get()).thenReturn(uriInfo); - when(uriInfo.getBaseUri()).thenReturn(URI.create(BASE_URL)); + when(uriInfo.getApiRestUri()).thenReturn(URI.create(BASE_URL)); } } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UriInfoStoreTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UriInfoStoreTest.java index 559e701ae3..da0682c640 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UriInfoStoreTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UriInfoStoreTest.java @@ -4,19 +4,26 @@ import org.junit.Test; import javax.ws.rs.core.UriInfo; +import java.net.URI; + import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class UriInfoStoreTest { @Test public void shouldReturnSetInfo() { + URI someUri = URI.create("/anything"); + UriInfo uriInfo = mock(UriInfo.class); UriInfoStore uriInfoStore = new UriInfoStore(); + when(uriInfo.getBaseUri()).thenReturn(someUri); + uriInfoStore.set(uriInfo); - assertSame(uriInfo, uriInfoStore.get()); + assertSame(someUri, uriInfoStore.get().getApiRestUri()); } @Test(expected = IllegalStateException.class) From 7c09f35ac8856d967042569d7c6236bbb883001e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Sep 2018 08:53:15 +0200 Subject: [PATCH 28/58] Rename UriInfoStore to ScmPathInfoStore --- ...riInfoStore.java => ScmPathInfoStore.java} | 2 +- .../InitializingHttpScmProtocolWrapper.java | 6 +-- .../GitConfigToGitConfigDtoMapper.java | 6 +-- .../web/GitScmProtocolProviderWrapper.java | 4 +- .../v2/resources/GitConfigResourceTest.java | 4 +- .../GitConfigToGitConfigDtoMapperTest.java | 4 +- .../HgConfigInstallationsToDtoMapper.java | 8 ++-- .../HgConfigPackagesToDtoMapper.java | 4 +- .../HgConfigToHgConfigDtoMapper.java | 6 +-- .../scm/web/HgScmProtocolProviderWrapper.java | 4 +- .../HgConfigInstallationsResourceTest.java | 4 +- .../HgConfigInstallationsToDtoMapperTest.java | 4 +- .../HgConfigPackageResourceTest.java | 4 +- .../HgConfigPackagesToDtoMapperTest.java | 4 +- .../v2/resources/HgConfigResourceTest.java | 4 +- .../HgConfigToHgConfigDtoMapperTest.java | 4 +- .../SvnConfigToSvnConfigDtoMapper.java | 6 +-- .../web/SvnScmProtocolProviderWrapper.java | 4 +- .../v2/resources/SvnConfigResourceTest.java | 4 +- .../SvnConfigToSvnConfigDtoMapperTest.java | 4 +- .../sonia/scm/api/rest/UriInfoFilter.java | 6 +-- .../scm/api/v2/resources/MapperModule.java | 2 +- .../RepositoryToRepositoryDtoMapper.java | 2 +- .../scm/api/v2/resources/ResourceLinks.java | 42 +++++++++---------- .../GroupCollectionToDtoMapperTest.java | 6 +-- .../scm/api/v2/resources/MeResourceTest.java | 4 +- .../resources/RepositoryRootResourceTest.java | 4 +- .../RepositoryToRepositoryDtoMapperTest.java | 4 +- .../api/v2/resources/ResourceLinksTest.java | 4 +- ...oreTest.java => ScmPathInfoStoreTest.java} | 15 ++++--- 30 files changed, 89 insertions(+), 90 deletions(-) rename scm-core/src/main/java/sonia/scm/api/v2/resources/{UriInfoStore.java => ScmPathInfoStore.java} (91%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{UriInfoStoreTest.java => ScmPathInfoStoreTest.java} (63%) diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfoStore.java similarity index 91% rename from scm-core/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java rename to scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfoStore.java index 5193ea6937..caa1183378 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfoStore.java @@ -2,7 +2,7 @@ package sonia.scm.api.v2.resources; import javax.ws.rs.core.UriInfo; -public class UriInfoStore { +public class ScmPathInfoStore { private UriInfo uriInfo; diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 651e4b3a7d..450f1d4495 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -1,6 +1,6 @@ package sonia.scm.repository.spi; -import sonia.scm.api.v2.resources.UriInfoStore; +import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; import sonia.scm.web.filter.PermissionFilter; @@ -16,13 +16,13 @@ public abstract class InitializingHttpScmProtocolWrapper { private final Provider delegateProvider; private final Provider permissionFilterProvider; - private final Provider uriInfoStore; + private final Provider uriInfoStore; private final ScmConfiguration scmConfiguration; private volatile boolean isInitialized = false; - protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider permissionFilterProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider permissionFilterProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { this.delegateProvider = delegateProvider; this.permissionFilterProvider = permissionFilterProvider; this.uriInfoStore = uriInfoStore; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapper.java index 7163497487..7607b31faf 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapper.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapper.java @@ -18,7 +18,7 @@ import static de.otto.edison.hal.Links.linkingTo; public abstract class GitConfigToGitConfigDtoMapper extends BaseMapper { @Inject - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @AfterMapping void appendLinks(GitConfig config, @MappingTarget GitConfigDto target) { @@ -30,12 +30,12 @@ public abstract class GitConfigToGitConfigDtoMapper extends BaseMapper servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + public GitScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java index 44603a65d3..1ebe7fc98b 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigResourceTest.java @@ -53,7 +53,7 @@ public class GitConfigResourceTest { private GitConfigDtoToGitConfigMapperImpl dtoToConfigMapper; @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @InjectMocks private GitConfigToGitConfigDtoMapperImpl configToDtoMapper; @@ -67,7 +67,7 @@ public class GitConfigResourceTest { when(repositoryHandler.getConfig()).thenReturn(gitConfig); GitConfigResource gitConfigResource = new GitConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler); dispatcher.getRegistry().addSingletonResource(gitConfigResource); - when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); + when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); } @Test diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapperTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapperTest.java index 903ee4e653..82c85029a3 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapperTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/api/v2/resources/GitConfigToGitConfigDtoMapperTest.java @@ -28,7 +28,7 @@ public class GitConfigToGitConfigDtoMapperTest { private URI baseUri = URI.create("http://example.com/base/"); @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @InjectMocks private GitConfigToGitConfigDtoMapperImpl mapper; @@ -40,7 +40,7 @@ public class GitConfigToGitConfigDtoMapperTest { @Before public void init() { - when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); + when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); expectedBaseUri = baseUri.resolve(GitConfigResource.GIT_CONFIG_PATH_V2); subjectThreadState.bind(); ThreadContext.bind(subject); diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapper.java index d2f4aecf7e..da980f75c0 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapper.java @@ -8,11 +8,11 @@ import static de.otto.edison.hal.Links.linkingTo; public class HgConfigInstallationsToDtoMapper { - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @Inject - public HgConfigInstallationsToDtoMapper(UriInfoStore uriInfoStore) { - this.uriInfoStore = uriInfoStore; + public HgConfigInstallationsToDtoMapper(ScmPathInfoStore scmPathInfoStore) { + this.scmPathInfoStore = scmPathInfoStore; } public HgConfigInstallationsDto map(List installations, String path) { @@ -20,7 +20,7 @@ public class HgConfigInstallationsToDtoMapper { } private String createSelfLink(String path) { - LinkBuilder linkBuilder = new LinkBuilder(uriInfoStore.get(), HgConfigResource.class); + LinkBuilder linkBuilder = new LinkBuilder(scmPathInfoStore.get(), HgConfigResource.class); return linkBuilder.method("getInstallationsResource").parameters().href() + '/' + path; } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapper.java index 67d7e58dff..3ee87cef84 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapper.java @@ -20,7 +20,7 @@ import static de.otto.edison.hal.Links.linkingTo; public abstract class HgConfigPackagesToDtoMapper { @Inject - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; public HgConfigPackagesDto map(HgPackages hgpackages) { return map(new HgPackagesNonIterable(hgpackages)); @@ -40,7 +40,7 @@ public abstract class HgConfigPackagesToDtoMapper { } private String createSelfLink() { - LinkBuilder linkBuilder = new LinkBuilder(uriInfoStore.get(), HgConfigResource.class); + LinkBuilder linkBuilder = new LinkBuilder(scmPathInfoStore.get(), HgConfigResource.class); return linkBuilder.method("getPackagesResource").parameters().href(); } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapper.java index 98137aebd5..b2a67e2aa4 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapper.java @@ -18,7 +18,7 @@ import static de.otto.edison.hal.Links.linkingTo; public abstract class HgConfigToHgConfigDtoMapper extends BaseMapper { @Inject - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @AfterMapping void appendLinks(HgConfig config, @MappingTarget HgConfigDto target) { @@ -30,12 +30,12 @@ public abstract class HgConfigToHgConfigDtoMapper extends BaseMapper servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + public HgScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); } } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java index 748b2c1b6e..65b9c262cb 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsResourceTest.java @@ -43,7 +43,7 @@ public class HgConfigInstallationsResourceTest { private final URI baseUri = URI.create("/"); @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @InjectMocks private HgConfigInstallationsToDtoMapper mapper; @@ -61,7 +61,7 @@ public class HgConfigInstallationsResourceTest { new HgConfigResource(null, null, null, null, null, resourceProvider)); - when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); + when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); } @Test diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapperTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapperTest.java index fcc90ee4e6..7cae1d9f7e 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapperTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapperTest.java @@ -23,7 +23,7 @@ public class HgConfigInstallationsToDtoMapperTest { private URI baseUri = URI.create("http://example.com/base/"); @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @InjectMocks private HgConfigInstallationsToDtoMapper mapper; @@ -34,7 +34,7 @@ public class HgConfigInstallationsToDtoMapperTest { @Before public void init() { - when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); + when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); expectedBaseUri = baseUri.resolve(HgConfigResource.HG_CONFIG_PATH_V2 + "/installations/" + expectedPath); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java index f24b30f515..f1558b6efb 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java @@ -57,7 +57,7 @@ public class HgConfigPackageResourceTest { private final URI baseUri = java.net.URI.create("/"); @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @InjectMocks private HgConfigPackagesToDtoMapperImpl mapper; @@ -81,7 +81,7 @@ public class HgConfigPackageResourceTest { public void prepareEnvironment() { setupResources(); - when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); + when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); when(hgPackageReader.getPackages().getPackages()).thenReturn(createPackages()); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapperTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapperTest.java index 0773499462..c4431da6d5 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapperTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapperTest.java @@ -26,7 +26,7 @@ public class HgConfigPackagesToDtoMapperTest { private URI baseUri = URI.create("http://example.com/base/"); @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @InjectMocks private HgConfigPackagesToDtoMapperImpl mapper; @@ -35,7 +35,7 @@ public class HgConfigPackagesToDtoMapperTest { @Before public void init() { - when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); + when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); expectedBaseUri = baseUri.resolve(HgConfigResource.HG_CONFIG_PATH_V2 + "/packages"); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java index aa29603ff1..9cd04a0789 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigResourceTest.java @@ -54,7 +54,7 @@ public class HgConfigResourceTest { private HgConfigDtoToHgConfigMapperImpl dtoToConfigMapper; @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @InjectMocks private HgConfigToHgConfigDtoMapperImpl configToDtoMapper; @@ -79,7 +79,7 @@ public class HgConfigResourceTest { new HgConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler, packagesResource, autoconfigResource, installationsResource); dispatcher.getRegistry().addSingletonResource(gitConfigResource); - when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); + when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); } @Test diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapperTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapperTest.java index 3f22c12f86..81c50f3d58 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapperTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigToHgConfigDtoMapperTest.java @@ -29,7 +29,7 @@ public class HgConfigToHgConfigDtoMapperTest { private URI baseUri = URI.create("http://example.com/base/"); @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @InjectMocks private HgConfigToHgConfigDtoMapperImpl mapper; @@ -41,7 +41,7 @@ public class HgConfigToHgConfigDtoMapperTest { @Before public void init() { - when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); + when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); expectedBaseUri = baseUri.resolve(HgConfigResource.HG_CONFIG_PATH_V2); subjectThreadState.bind(); ThreadContext.bind(subject); diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapper.java index a71d75151d..c160280822 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapper.java @@ -18,7 +18,7 @@ import static de.otto.edison.hal.Links.linkingTo; public abstract class SvnConfigToSvnConfigDtoMapper extends BaseMapper { @Inject - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @AfterMapping void appendLinks(SvnConfig config, @MappingTarget SvnConfigDto target) { @@ -30,12 +30,12 @@ public abstract class SvnConfigToSvnConfigDtoMapper extends BaseMapper servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + public SvnScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); } diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java index 67f3e47950..28dbe09e92 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigResourceTest.java @@ -53,7 +53,7 @@ public class SvnConfigResourceTest { private SvnConfigDtoToSvnConfigMapperImpl dtoToConfigMapper; @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @InjectMocks private SvnConfigToSvnConfigDtoMapperImpl configToDtoMapper; @@ -67,7 +67,7 @@ public class SvnConfigResourceTest { when(repositoryHandler.getConfig()).thenReturn(gitConfig); SvnConfigResource gitConfigResource = new SvnConfigResource(dtoToConfigMapper, configToDtoMapper, repositoryHandler); dispatcher.getRegistry().addSingletonResource(gitConfigResource); - when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); + when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); } @Test diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapperTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapperTest.java index cfe2c59772..5184aa3d41 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapperTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/api/v2/resources/SvnConfigToSvnConfigDtoMapperTest.java @@ -30,7 +30,7 @@ public class SvnConfigToSvnConfigDtoMapperTest { private URI baseUri = URI.create("http://example.com/base/"); @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private UriInfoStore uriInfoStore; + private ScmPathInfoStore scmPathInfoStore; @InjectMocks private SvnConfigToSvnConfigDtoMapperImpl mapper; @@ -42,7 +42,7 @@ public class SvnConfigToSvnConfigDtoMapperTest { @Before public void init() { - when(uriInfoStore.get().getApiRestUri()).thenReturn(baseUri); + when(scmPathInfoStore.get().getApiRestUri()).thenReturn(baseUri); expectedBaseUri = baseUri.resolve(SvnConfigResource.SVN_CONFIG_PATH_V2); subjectThreadState.bind(); ThreadContext.bind(subject); 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 index de0f1dd626..1683d5c11a 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java @@ -1,6 +1,6 @@ package sonia.scm.api.rest; -import sonia.scm.api.v2.resources.UriInfoStore; +import sonia.scm.api.v2.resources.ScmPathInfoStore; import javax.inject.Inject; import javax.ws.rs.container.ContainerRequestContext; @@ -10,10 +10,10 @@ import javax.ws.rs.ext.Provider; @Provider public class UriInfoFilter implements ContainerRequestFilter { - private final javax.inject.Provider storeProvider; + private final javax.inject.Provider storeProvider; @Inject - public UriInfoFilter(javax.inject.Provider storeProvider) { + public UriInfoFilter(javax.inject.Provider storeProvider) { this.storeProvider = storeProvider; } 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 9cadbfb6ff..7d8b015c27 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 @@ -39,6 +39,6 @@ public class MapperModule extends AbstractModule { bind(UIPluginDtoMapper.class); bind(UIPluginDtoCollectionMapper.class); - bind(UriInfoStore.class).in(ServletScopes.REQUEST); + bind(ScmPathInfoStore.class).in(ServletScopes.REQUEST); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java index 74ce1a65dd..ce716f2f6f 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java @@ -31,7 +31,7 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper Date: Wed, 12 Sep 2018 09:19:52 +0200 Subject: [PATCH 29/58] Give name to initialization --- .../sonia/scm/api/v2/resources/ScmPathInfoStore.java | 10 +++++----- .../main/java/sonia/scm/api/rest/UriInfoFilter.java | 2 +- .../v2/resources/GroupCollectionToDtoMapperTest.java | 2 +- .../scm/api/v2/resources/ScmPathInfoStoreTest.java | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfoStore.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfoStore.java index caa1183378..c6854e7117 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfoStore.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfoStore.java @@ -4,17 +4,17 @@ import javax.ws.rs.core.UriInfo; public class ScmPathInfoStore { - private UriInfo uriInfo; + private ScmPathInfo pathInfo; public ScmPathInfo get() { - return () -> uriInfo.getBaseUri(); + return pathInfo; } - public void set(UriInfo uriInfo) { - if (this.uriInfo != null) { + public void setFromRestRequest(UriInfo uriInfo) { + if (this.pathInfo != null) { throw new IllegalStateException("UriInfo already set"); } - this.uriInfo = uriInfo; + this.pathInfo = uriInfo::getBaseUri; } } 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 index 1683d5c11a..a0b5644a05 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java @@ -19,6 +19,6 @@ public class UriInfoFilter implements ContainerRequestFilter { @Override public void filter(ContainerRequestContext requestContext) { - storeProvider.get().set(requestContext.getUriInfo()); + storeProvider.get().setFromRestRequest(requestContext.getUriInfo()); } } 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 b6dcf6d809..41faa49568 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 @@ -41,7 +41,7 @@ public class GroupCollectionToDtoMapperTest { @Before public void init() throws URISyntaxException { - scmPathInfoStore.set(uriInfo); + scmPathInfoStore.setFromRestRequest(uriInfo); URI baseUri = new URI("http://example.com/base/"); expectedBaseUri = baseUri.resolve(GroupRootResource.GROUPS_PATH_V2 + "/"); when(uriInfo.getBaseUri()).thenReturn(baseUri); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmPathInfoStoreTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmPathInfoStoreTest.java index 4c3f49d2fd..1058dc182b 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmPathInfoStoreTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmPathInfoStoreTest.java @@ -20,7 +20,7 @@ public class ScmPathInfoStoreTest { when(uriInfo.getBaseUri()).thenReturn(someUri); - scmPathInfoStore.set(uriInfo); + scmPathInfoStore.setFromRestRequest(uriInfo); assertSame(someUri, scmPathInfoStore.get().getApiRestUri()); } @@ -30,7 +30,7 @@ public class ScmPathInfoStoreTest { UriInfo uriInfo = mock(UriInfo.class); ScmPathInfoStore scmPathInfoStore = new ScmPathInfoStore(); - scmPathInfoStore.set(uriInfo); - scmPathInfoStore.set(uriInfo); + scmPathInfoStore.setFromRestRequest(uriInfo); + scmPathInfoStore.setFromRestRequest(uriInfo); } } From b809abaa45e9acee47afe0efc97ca888c1161116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Sep 2018 09:23:04 +0200 Subject: [PATCH 30/58] Move info initialization to filter --- .../scm/api/v2/resources/ScmPathInfoStore.java | 6 ++---- .../main/java/sonia/scm/api/rest/UriInfoFilter.java | 4 +++- .../resources/GroupCollectionToDtoMapperTest.java | 7 +++---- .../scm/api/v2/resources/ScmPathInfoStoreTest.java | 13 ++++++------- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfoStore.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfoStore.java index c6854e7117..c88bd4a2b5 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfoStore.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfoStore.java @@ -1,7 +1,5 @@ package sonia.scm.api.v2.resources; -import javax.ws.rs.core.UriInfo; - public class ScmPathInfoStore { private ScmPathInfo pathInfo; @@ -10,11 +8,11 @@ public class ScmPathInfoStore { return pathInfo; } - public void setFromRestRequest(UriInfo uriInfo) { + public void set(ScmPathInfo info) { if (this.pathInfo != null) { throw new IllegalStateException("UriInfo already set"); } - this.pathInfo = uriInfo::getBaseUri; + this.pathInfo = info; } } 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 index a0b5644a05..b602e918ea 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java @@ -5,6 +5,7 @@ import sonia.scm.api.v2.resources.ScmPathInfoStore; import javax.inject.Inject; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.Provider; @Provider @@ -19,6 +20,7 @@ public class UriInfoFilter implements ContainerRequestFilter { @Override public void filter(ContainerRequestContext requestContext) { - storeProvider.get().setFromRestRequest(requestContext.getUriInfo()); + UriInfo uriInfo = requestContext.getUriInfo(); + storeProvider.get().set(uriInfo::getBaseUri); } } 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 41faa49568..5066f56ff7 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 @@ -11,7 +11,6 @@ import org.junit.Test; import sonia.scm.PageResult; import sonia.scm.group.Group; -import javax.ws.rs.core.UriInfo; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; @@ -28,7 +27,7 @@ import static sonia.scm.PageResult.createPage; public class GroupCollectionToDtoMapperTest { - private final UriInfo uriInfo = mock(UriInfo.class); + private final ScmPathInfo uriInfo = mock(ScmPathInfo.class); private final ScmPathInfoStore scmPathInfoStore = new ScmPathInfoStore(); private final ResourceLinks resourceLinks = new ResourceLinks(scmPathInfoStore); private final GroupToGroupDtoMapper groupToDtoMapper = mock(GroupToGroupDtoMapper.class); @@ -41,10 +40,10 @@ public class GroupCollectionToDtoMapperTest { @Before public void init() throws URISyntaxException { - scmPathInfoStore.setFromRestRequest(uriInfo); + scmPathInfoStore.set(uriInfo); URI baseUri = new URI("http://example.com/base/"); expectedBaseUri = baseUri.resolve(GroupRootResource.GROUPS_PATH_V2 + "/"); - when(uriInfo.getBaseUri()).thenReturn(baseUri); + when(uriInfo.getApiRestUri()).thenReturn(baseUri); subjectThreadState.bind(); ThreadContext.bind(subject); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmPathInfoStoreTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmPathInfoStoreTest.java index 1058dc182b..544a918b8b 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmPathInfoStoreTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmPathInfoStoreTest.java @@ -2,7 +2,6 @@ package sonia.scm.api.v2.resources; import org.junit.Test; -import javax.ws.rs.core.UriInfo; import java.net.URI; import static org.junit.Assert.assertSame; @@ -15,22 +14,22 @@ public class ScmPathInfoStoreTest { public void shouldReturnSetInfo() { URI someUri = URI.create("/anything"); - UriInfo uriInfo = mock(UriInfo.class); + ScmPathInfo uriInfo = mock(ScmPathInfo.class); ScmPathInfoStore scmPathInfoStore = new ScmPathInfoStore(); - when(uriInfo.getBaseUri()).thenReturn(someUri); + when(uriInfo.getApiRestUri()).thenReturn(someUri); - scmPathInfoStore.setFromRestRequest(uriInfo); + scmPathInfoStore.set(uriInfo); assertSame(someUri, scmPathInfoStore.get().getApiRestUri()); } @Test(expected = IllegalStateException.class) public void shouldFailIfSetTwice() { - UriInfo uriInfo = mock(UriInfo.class); + ScmPathInfo uriInfo = mock(ScmPathInfo.class); ScmPathInfoStore scmPathInfoStore = new ScmPathInfoStore(); - scmPathInfoStore.setFromRestRequest(uriInfo); - scmPathInfoStore.setFromRestRequest(uriInfo); + scmPathInfoStore.set(uriInfo); + scmPathInfoStore.set(uriInfo); } } From ef28350ce31279d9442e3e605b6b85d3d35c7ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Sep 2018 11:43:29 +0200 Subject: [PATCH 31/58] Handle missing request scope for url computation --- .../InitializingHttpScmProtocolWrapper.java | 29 +++- .../test/java/sonia/scm}/MockProvider.java | 6 +- ...nitializingHttpScmProtocolWrapperTest.java | 143 ++++++++++++++++++ scm-webapp/pom.xml | 9 +- .../v2/resources/BranchRootResourceTest.java | 1 + .../resources/ChangesetRootResourceTest.java | 1 + .../v2/resources/GroupRootResourceTest.java | 1 + .../resources/PermissionRootResourceTest.java | 1 + .../resources/RepositoryRootResourceTest.java | 1 + .../RepositoryTypeRootResourceTest.java | 7 +- .../v2/resources/SourceRootResourceTest.java | 2 +- .../api/v2/resources/TagRootResourceTest.java | 1 + .../v2/resources/UserRootResourceTest.java | 1 + 13 files changed, 192 insertions(+), 11 deletions(-) rename {scm-webapp/src/test/java/sonia/scm/api/v2/resources => scm-core/src/test/java/sonia/scm}/MockProvider.java (80%) create mode 100644 scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 450f1d4495..7e7fb243cc 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -1,5 +1,7 @@ package sonia.scm.repository.spi; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; @@ -11,9 +13,15 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.util.Optional; + +import static java.util.Optional.empty; +import static java.util.Optional.of; public abstract class InitializingHttpScmProtocolWrapper { + private static final Logger logger = LoggerFactory.getLogger(InitializingHttpScmProtocolWrapper.class); + private final Provider delegateProvider; private final Provider permissionFilterProvider; private final Provider uriInfoStore; @@ -38,11 +46,24 @@ public abstract class InitializingHttpScmProtocolWrapper { } private String computeBasePath() { - if (uriInfoStore.get() != null && uriInfoStore.get().get() != null) { - return uriInfoStore.get().get().getApiRestUri().resolve("../..").toASCIIString(); - } else { - return scmConfiguration.getBaseUrl(); + return getPathFromScmPathInfoIfAvailable().orElse(getPathFromConfiguration()); + } + + private Optional getPathFromScmPathInfoIfAvailable() { + try { + ScmPathInfoStore scmPathInfoStore = uriInfoStore.get(); + if (scmPathInfoStore != null && scmPathInfoStore.get() != null) { + return of(scmPathInfoStore.get().getApiRestUri().resolve("../..").toASCIIString()); + } + } catch (Exception e) { + logger.debug("could not get ScmPathInfoStore from context", e); } + return empty(); + } + + private String getPathFromConfiguration() { + logger.debug("using base path from configuration: " + scmConfiguration.getBaseUrl()); + return scmConfiguration.getBaseUrl(); } private class ProtocolWrapper extends HttpScmProtocol { diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MockProvider.java b/scm-core/src/test/java/sonia/scm/MockProvider.java similarity index 80% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/MockProvider.java rename to scm-core/src/test/java/sonia/scm/MockProvider.java index bf84e4fe15..fae1b07586 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MockProvider.java +++ b/scm-core/src/test/java/sonia/scm/MockProvider.java @@ -1,4 +1,4 @@ -package sonia.scm.api.v2.resources; +package sonia.scm; import javax.inject.Provider; @@ -8,11 +8,11 @@ import static org.mockito.Mockito.when; /** * A mockito implementation of CDI {@link javax.inject.Provider}. */ -class MockProvider { +public class MockProvider { private MockProvider() {} - static Provider of(I instance) { + public static Provider of(I instance) { @SuppressWarnings("unchecked") // Can't make mockito return typed provider Provider provider = mock(Provider.class); when(provider.get()).thenReturn(instance); diff --git a/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java b/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java new file mode 100644 index 0000000000..3b43e16e5b --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java @@ -0,0 +1,143 @@ +package sonia.scm.repository.spi; + +import com.google.inject.ProvisionException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.stubbing.Answer; +import org.mockito.stubbing.OngoingStubbing; +import sonia.scm.MockProvider; +import sonia.scm.api.v2.resources.ScmPathInfo; +import sonia.scm.api.v2.resources.ScmPathInfoStore; +import sonia.scm.config.ScmConfiguration; +import sonia.scm.repository.Repository; +import sonia.scm.web.filter.PermissionFilter; + +import javax.inject.Provider; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URI; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +public class InitializingHttpScmProtocolWrapperTest { + + private static final Repository REPOSITORY = new Repository("", "git", "space", "name"); + + @Mock + private ScmProviderHttpServlet delegateServlet; + @Mock + private PermissionFilter permissionFilter; + @Mock + private ScmPathInfoStore pathInfoStore; + @Mock + private ScmConfiguration scmConfiguration; + private Provider pathInfoStoreProvider; + + @Mock + private HttpServletRequest request; + @Mock + private HttpServletResponse response; + @Mock + private ServletConfig servletConfig; + + private InitializingHttpScmProtocolWrapper wrapper; + + @Before + public void init() { + initMocks(this); + pathInfoStoreProvider = MockProvider.of(pathInfoStore); + wrapper = new InitializingHttpScmProtocolWrapper(MockProvider.of(this.delegateServlet), MockProvider.of(permissionFilter), pathInfoStoreProvider, scmConfiguration) {}; + when(scmConfiguration.getBaseUrl()).thenReturn("http://example.com/scm"); + } + + @Test + public void shouldUsePathFromPathInfo() { + mockSetPathInfo(); + + HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); + + assertEquals("http://example.com/scm/repo/space/name", httpScmProtocol.getUrl()); + } + + @Test + public void shouldUseConfigurationWhenPathInfoNotSet() { + HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); + + assertEquals("http://example.com/scm/repo/space/name", httpScmProtocol.getUrl()); + } + + @Test + public void shouldUseConfigurationWhenNotInRequestScope() { + when(pathInfoStoreProvider.get()).thenThrow(new ProvisionException("test")); + + HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); + + assertEquals("http://example.com/scm/repo/space/name", httpScmProtocol.getUrl()); + } + + @Test + public void shouldInitializeAndDelegateRequestThroughFilter() throws ServletException, IOException { + doAnswer(proceedInvocation()). + when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any()); + HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); + + httpScmProtocol.serve(request, response, servletConfig); + + verify(delegateServlet).init(servletConfig); + verify(delegateServlet).service(request, response, REPOSITORY); + } + + @Test + public void shouldNotDelegateRequestWhenFilterBlocks() throws ServletException, IOException { + doNothing(). + when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any()); + HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); + + httpScmProtocol.serve(request, response, servletConfig); + + verify(delegateServlet, never()).service(request, response, REPOSITORY); + } + + @Test + public void shouldInitializeOnlyOnce() throws ServletException, IOException { + doAnswer(proceedInvocation()). + when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any()); + HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); + + httpScmProtocol.serve(request, response, servletConfig); + httpScmProtocol.serve(request, response, servletConfig); + + verify(delegateServlet, times(1)).init(servletConfig); + verify(delegateServlet, times(2)).service(request, response, REPOSITORY); + } + + private Answer proceedInvocation() { + return invocation -> { + ((PermissionFilter.ContinuationServlet) invocation.getArgument(3)).doService(); + return null; + }; + } + + private OngoingStubbing mockSetPathInfo() { + return when(pathInfoStore.get()).thenReturn(new ScmPathInfo() { + @Override + public URI getApiRestUri() { + return URI.create("http://example.com/scm/api/rest/"); + } + }); + } + +} diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index fb5cc57e44..c7d4dbc45c 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -49,7 +49,14 @@ scm-core 2.0.0-SNAPSHOT - + + sonia.scm + scm-core + 2.0.0-SNAPSHOT + tests + test + + sonia.scm scm-dao-xml diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java index e23d3dc39b..f2563b3522 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java @@ -17,6 +17,7 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import sonia.scm.MockProvider; import sonia.scm.repository.Branch; import sonia.scm.repository.Branches; import sonia.scm.repository.Changeset; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java index 40aa61852a..45ff631828 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java @@ -18,6 +18,7 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import sonia.scm.MockProvider; import sonia.scm.api.rest.AuthorizationExceptionMapper; import sonia.scm.repository.Changeset; import sonia.scm.repository.ChangesetPagingResult; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java index 1e42016ace..9b1699691c 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java @@ -12,6 +12,7 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; +import sonia.scm.MockProvider; import sonia.scm.PageResult; import sonia.scm.api.rest.JSONContextResolver; import sonia.scm.api.rest.ObjectMapperProvider; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java index 8d05c1f455..f4c88b7be1 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.TestFactory; import org.mockito.InjectMocks; import org.mockito.Mock; +import sonia.scm.MockProvider; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Permission; import sonia.scm.repository.PermissionType; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index ca679764ad..68ea56299b 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -12,6 +12,7 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; +import sonia.scm.MockProvider; import sonia.scm.PageResult; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Permission; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java index 9adca13225..a0bb5ccf08 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java @@ -12,6 +12,7 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import sonia.scm.MockProvider; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryType; import sonia.scm.web.VndMediaType; @@ -22,8 +23,10 @@ import java.util.List; import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; import static javax.servlet.http.HttpServletResponse.SC_OK; -import static org.junit.Assert.*; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.equalToIgnoringCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java index a59ed0c103..4bc11fad82 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java @@ -1,7 +1,6 @@ package sonia.scm.api.v2.resources; import org.jboss.resteasy.core.Dispatcher; -import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; @@ -10,6 +9,7 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import sonia.scm.MockProvider; import sonia.scm.repository.BrowserResult; import sonia.scm.repository.FileObject; import sonia.scm.repository.NamespaceAndName; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java index 92d11b3895..eaa7deb578 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java @@ -17,6 +17,7 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import sonia.scm.MockProvider; import sonia.scm.api.rest.AuthorizationExceptionMapper; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java index 5004eb7665..e54c875373 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java @@ -13,6 +13,7 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; +import sonia.scm.MockProvider; import sonia.scm.PageResult; import sonia.scm.user.User; import sonia.scm.user.UserManager; From f5d5d3a6dc680749744281d0a48a181524bd56fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Sep 2018 11:47:53 +0200 Subject: [PATCH 32/58] Move path computation away from protocol handling --- .../src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java | 4 ++++ .../repository/spi/InitializingHttpScmProtocolWrapper.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java index 0afb379eed..34fa5004fc 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java @@ -4,4 +4,8 @@ import java.net.URI; public interface ScmPathInfo { URI getApiRestUri(); + + default URI getRootUri() { + return getApiRestUri().resolve("../.."); + } } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 7e7fb243cc..c5fd037cc8 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -53,7 +53,7 @@ public abstract class InitializingHttpScmProtocolWrapper { try { ScmPathInfoStore scmPathInfoStore = uriInfoStore.get(); if (scmPathInfoStore != null && scmPathInfoStore.get() != null) { - return of(scmPathInfoStore.get().getApiRestUri().resolve("../..").toASCIIString()); + return of(scmPathInfoStore.get().getRootUri().toASCIIString()); } } catch (Exception e) { logger.debug("could not get ScmPathInfoStore from context", e); From f47c5ef16f5cc22ddeb901c443725c379d2041f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Sep 2018 12:05:24 +0200 Subject: [PATCH 33/58] Replace MockProvider test helper with guice class --- .../src/test/java/sonia/scm/MockProvider.java | 22 ------------------- ...nitializingHttpScmProtocolWrapperTest.java | 9 +++++--- scm-webapp/pom.xml | 7 ------ .../v2/resources/BranchRootResourceTest.java | 4 ++-- .../resources/ChangesetRootResourceTest.java | 6 ++--- .../v2/resources/GroupRootResourceTest.java | 4 ++-- .../resources/PermissionRootResourceTest.java | 6 ++--- .../resources/RepositoryRootResourceTest.java | 4 ++-- .../RepositoryTypeRootResourceTest.java | 4 ++-- .../v2/resources/SourceRootResourceTest.java | 6 ++--- .../api/v2/resources/TagRootResourceTest.java | 6 ++--- .../v2/resources/UserRootResourceTest.java | 6 ++--- 12 files changed, 29 insertions(+), 55 deletions(-) delete mode 100644 scm-core/src/test/java/sonia/scm/MockProvider.java diff --git a/scm-core/src/test/java/sonia/scm/MockProvider.java b/scm-core/src/test/java/sonia/scm/MockProvider.java deleted file mode 100644 index fae1b07586..0000000000 --- a/scm-core/src/test/java/sonia/scm/MockProvider.java +++ /dev/null @@ -1,22 +0,0 @@ -package sonia.scm; - -import javax.inject.Provider; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * A mockito implementation of CDI {@link javax.inject.Provider}. - */ -public class MockProvider { - - private MockProvider() {} - - public static Provider of(I instance) { - @SuppressWarnings("unchecked") // Can't make mockito return typed provider - Provider provider = mock(Provider.class); - when(provider.get()).thenReturn(instance); - return provider; - } - -} diff --git a/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java b/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java index 3b43e16e5b..1e742a768a 100644 --- a/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java @@ -1,12 +1,12 @@ package sonia.scm.repository.spi; import com.google.inject.ProvisionException; +import com.google.inject.util.Providers; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.stubbing.Answer; import org.mockito.stubbing.OngoingStubbing; -import sonia.scm.MockProvider; import sonia.scm.api.v2.resources.ScmPathInfo; import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; @@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -58,8 +59,10 @@ public class InitializingHttpScmProtocolWrapperTest { @Before public void init() { initMocks(this); - pathInfoStoreProvider = MockProvider.of(pathInfoStore); - wrapper = new InitializingHttpScmProtocolWrapper(MockProvider.of(this.delegateServlet), MockProvider.of(permissionFilter), pathInfoStoreProvider, scmConfiguration) {}; + pathInfoStoreProvider = mock(Provider.class); + when(pathInfoStoreProvider.get()).thenReturn(pathInfoStore); + + wrapper = new InitializingHttpScmProtocolWrapper(Providers.of(this.delegateServlet), Providers.of(permissionFilter), pathInfoStoreProvider, scmConfiguration) {}; when(scmConfiguration.getBaseUrl()).thenReturn("http://example.com/scm"); } diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index c7d4dbc45c..bc40e434cf 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -49,13 +49,6 @@ scm-core 2.0.0-SNAPSHOT - - sonia.scm - scm-core - 2.0.0-SNAPSHOT - tests - test - sonia.scm diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java index f2563b3522..bc883ef37a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java @@ -1,5 +1,6 @@ package sonia.scm.api.v2.resources; +import com.google.inject.util.Providers; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.support.SubjectThreadState; @@ -17,7 +18,6 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.MockProvider; import sonia.scm.repository.Branch; import sonia.scm.repository.Branches; import sonia.scm.repository.Changeset; @@ -93,7 +93,7 @@ public class BranchRootResourceTest { changesetCollectionToDtoMapper = new ChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks); BranchCollectionToDtoMapper branchCollectionToDtoMapper = new BranchCollectionToDtoMapper(branchToDtoMapper, resourceLinks); branchRootResource = new BranchRootResource(serviceFactory, branchToDtoMapper, branchCollectionToDtoMapper, changesetCollectionToDtoMapper); - RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(new RepositoryResource(null, null, null, null, MockProvider.of(branchRootResource), null, null, null, null, null)), null); + RepositoryRootResource repositoryRootResource = new RepositoryRootResource(Providers.of(new RepositoryResource(null, null, null, null, Providers.of(branchRootResource), null, null, null, null, null)), null); dispatcher.getRegistry().addSingletonResource(repositoryRootResource); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java index 45ff631828..3980dcef1f 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java @@ -1,6 +1,7 @@ package sonia.scm.api.v2.resources; +import com.google.inject.util.Providers; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.support.SubjectThreadState; @@ -18,7 +19,6 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.MockProvider; import sonia.scm.api.rest.AuthorizationExceptionMapper; import sonia.scm.repository.Changeset; import sonia.scm.repository.ChangesetPagingResult; @@ -80,9 +80,9 @@ public class ChangesetRootResourceTest { public void prepareEnvironment() throws Exception { changesetCollectionToDtoMapper = new ChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks); changesetRootResource = new ChangesetRootResource(serviceFactory, changesetCollectionToDtoMapper, changesetToChangesetDtoMapper); - RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider + RepositoryRootResource repositoryRootResource = new RepositoryRootResource(Providers .of(new RepositoryResource(null, null, null, null, null, - MockProvider.of(changesetRootResource), null, null, null, null)), null); + Providers.of(changesetRootResource), null, null, null, null)), null); dispatcher.getRegistry().addSingletonResource(repositoryRootResource); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService); when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java index 9b1699691c..f662542ff7 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupRootResourceTest.java @@ -3,6 +3,7 @@ package sonia.scm.api.v2.resources; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.common.io.Resources; +import com.google.inject.util.Providers; import org.jboss.resteasy.core.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; @@ -12,7 +13,6 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; -import sonia.scm.MockProvider; import sonia.scm.PageResult; import sonia.scm.api.rest.JSONContextResolver; import sonia.scm.api.rest.ObjectMapperProvider; @@ -74,7 +74,7 @@ public class GroupRootResourceTest { GroupCollectionToDtoMapper groupCollectionToDtoMapper = new GroupCollectionToDtoMapper(groupToDtoMapper, resourceLinks); GroupCollectionResource groupCollectionResource = new GroupCollectionResource(groupManager, dtoToGroupMapper, groupCollectionToDtoMapper, resourceLinks); GroupResource groupResource = new GroupResource(groupManager, groupToDtoMapper, dtoToGroupMapper); - GroupRootResource groupRootResource = new GroupRootResource(MockProvider.of(groupCollectionResource), MockProvider.of(groupResource)); + GroupRootResource groupRootResource = new GroupRootResource(Providers.of(groupCollectionResource), Providers.of(groupResource)); dispatcher = createDispatcher(groupRootResource); dispatcher.getProviderFactory().registerProviderInstance(new JSONContextResolver(new ObjectMapperProvider().get())); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java index f4c88b7be1..25f59c3e38 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.common.collect.ImmutableList; +import com.google.inject.util.Providers; import de.otto.edison.hal.HalRepresentation; import lombok.ToString; import lombok.extern.slf4j.Slf4j; @@ -27,7 +28,6 @@ import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.TestFactory; import org.mockito.InjectMocks; import org.mockito.Mock; -import sonia.scm.MockProvider; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Permission; import sonia.scm.repository.PermissionType; @@ -138,8 +138,8 @@ public class PermissionRootResourceTest { initMocks(this); permissionCollectionToDtoMapper = new PermissionCollectionToDtoMapper(permissionToPermissionDtoMapper, resourceLinks); permissionRootResource = new PermissionRootResource(permissionDtoToPermissionMapper, permissionToPermissionDtoMapper, permissionCollectionToDtoMapper, resourceLinks, repositoryManager); - RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider - .of(new RepositoryResource(null, null, null, null, null, null, null, null, MockProvider.of(permissionRootResource), null)), null); + RepositoryRootResource repositoryRootResource = new RepositoryRootResource(Providers + .of(new RepositoryResource(null, null, null, null, null, null, null, null, Providers.of(permissionRootResource), null)), null); dispatcher = createDispatcher(repositoryRootResource); subjectThreadState.bind(); ThreadContext.bind(subject); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index 68ea56299b..3b76d42f44 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -3,6 +3,7 @@ package sonia.scm.api.v2.resources; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.common.io.Resources; +import com.google.inject.util.Providers; import org.jboss.resteasy.core.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; @@ -12,7 +13,6 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; -import sonia.scm.MockProvider; import sonia.scm.PageResult; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Permission; @@ -90,7 +90,7 @@ public class RepositoryRootResourceTest { RepositoryResource repositoryResource = new RepositoryResource(repositoryToDtoMapper, dtoToRepositoryMapper, repositoryManager, null, null, null, null, null, null, null); RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks); RepositoryCollectionResource repositoryCollectionResource = new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks); - RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(repositoryResource), MockProvider.of(repositoryCollectionResource)); + RepositoryRootResource repositoryRootResource = new RepositoryRootResource(Providers.of(repositoryResource), Providers.of(repositoryCollectionResource)); when(serviceFactory.create(any(Repository.class))).thenReturn(service); when(scmPathInfoStore.get()).thenReturn(uriInfo); when(uriInfo.getApiRestUri()).thenReturn(URI.create("/x/y")); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java index a0bb5ccf08..2476785d70 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTypeRootResourceTest.java @@ -2,6 +2,7 @@ package sonia.scm.api.v2.resources; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import com.google.inject.util.Providers; import org.jboss.resteasy.core.Dispatcher; import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; @@ -12,7 +13,6 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.MockProvider; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryType; import sonia.scm.web.VndMediaType; @@ -55,7 +55,7 @@ public class RepositoryTypeRootResourceTest { RepositoryTypeCollectionToDtoMapper collectionMapper = new RepositoryTypeCollectionToDtoMapper(mapper, resourceLinks); RepositoryTypeCollectionResource collectionResource = new RepositoryTypeCollectionResource(repositoryManager, collectionMapper); RepositoryTypeResource resource = new RepositoryTypeResource(repositoryManager, mapper); - RepositoryTypeRootResource rootResource = new RepositoryTypeRootResource(MockProvider.of(collectionResource), MockProvider.of(resource)); + RepositoryTypeRootResource rootResource = new RepositoryTypeRootResource(Providers.of(collectionResource), Providers.of(resource)); dispatcher.getRegistry().addSingletonResource(rootResource); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java index 4bc11fad82..69b4af9871 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java @@ -1,5 +1,6 @@ package sonia.scm.api.v2.resources; +import com.google.inject.util.Providers; import org.jboss.resteasy.core.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; @@ -9,7 +10,6 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.MockProvider; import sonia.scm.repository.BrowserResult; import sonia.scm.repository.FileObject; import sonia.scm.repository.NamespaceAndName; @@ -65,13 +65,13 @@ public class SourceRootResourceTest { when(fileObjectToFileObjectDtoMapper.map(any(FileObject.class), any(NamespaceAndName.class), anyString())).thenReturn(dto); SourceRootResource sourceRootResource = new SourceRootResource(serviceFactory, browserResultToBrowserResultDtoMapper); RepositoryRootResource repositoryRootResource = - new RepositoryRootResource(MockProvider.of(new RepositoryResource(null, + new RepositoryRootResource(Providers.of(new RepositoryResource(null, null, null, null, null, null, - MockProvider.of(sourceRootResource), + Providers.of(sourceRootResource), null, null, null)), diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java index eaa7deb578..0266d9a9e0 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java @@ -1,5 +1,6 @@ package sonia.scm.api.v2.resources; +import com.google.inject.util.Providers; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.support.SubjectThreadState; @@ -17,7 +18,6 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import sonia.scm.MockProvider; import sonia.scm.api.rest.AuthorizationExceptionMapper; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; @@ -73,8 +73,8 @@ public class TagRootResourceTest { public void prepareEnvironment() throws Exception { tagCollectionToDtoMapper = new TagCollectionToDtoMapper(resourceLinks, tagToTagDtoMapper); tagRootResource = new TagRootResource(serviceFactory, tagCollectionToDtoMapper, tagToTagDtoMapper); - RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider - .of(new RepositoryResource(null, null, null, MockProvider.of(tagRootResource), null, + RepositoryRootResource repositoryRootResource = new RepositoryRootResource(Providers + .of(new RepositoryResource(null, null, null, Providers.of(tagRootResource), null, null, null, null, null, null)), null); dispatcher.getRegistry().addSingletonResource(repositoryRootResource); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java index e54c875373..c0b50bfd5e 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserRootResourceTest.java @@ -3,6 +3,7 @@ package sonia.scm.api.v2.resources; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.common.io.Resources; +import com.google.inject.util.Providers; import org.apache.shiro.authc.credential.PasswordService; import org.jboss.resteasy.core.Dispatcher; import org.jboss.resteasy.mock.MockHttpRequest; @@ -13,7 +14,6 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; -import sonia.scm.MockProvider; import sonia.scm.PageResult; import sonia.scm.user.User; import sonia.scm.user.UserManager; @@ -74,8 +74,8 @@ public class UserRootResourceTest { UserCollectionResource userCollectionResource = new UserCollectionResource(userManager, dtoToUserMapper, userCollectionToDtoMapper, resourceLinks); UserResource userResource = new UserResource(dtoToUserMapper, userToDtoMapper, userManager); - UserRootResource userRootResource = new UserRootResource(MockProvider.of(userCollectionResource), - MockProvider.of(userResource)); + UserRootResource userRootResource = new UserRootResource(Providers.of(userCollectionResource), + Providers.of(userResource)); dispatcher = createDispatcher(userRootResource); } From 9aa9b779222c592994aa8c946c078feb6e8d4914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 12 Sep 2018 12:24:57 +0200 Subject: [PATCH 34/58] Use constant for rest api path --- .../sonia/scm/api/v2/resources/ScmPathInfo.java | 3 +++ .../src/main/java/sonia/scm/filter/Filters.java | 12 +++++++----- .../src/main/java/sonia/scm/ScmServletModule.java | 8 +++++--- .../main/java/sonia/scm/filter/SecurityFilter.java | 14 +++++++------- .../java/sonia/scm/security/SecurityRequests.java | 4 +++- 5 files changed, 25 insertions(+), 16 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java index 34fa5004fc..fa975520c1 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/ScmPathInfo.java @@ -3,6 +3,9 @@ package sonia.scm.api.v2.resources; import java.net.URI; public interface ScmPathInfo { + + String REST_API_PATH = "/api/rest"; + URI getApiRestUri(); default URI getRootUri() { diff --git a/scm-core/src/main/java/sonia/scm/filter/Filters.java b/scm-core/src/main/java/sonia/scm/filter/Filters.java index b6a45811bc..b1f5ea47cf 100644 --- a/scm-core/src/main/java/sonia/scm/filter/Filters.java +++ b/scm-core/src/main/java/sonia/scm/filter/Filters.java @@ -31,6 +31,8 @@ package sonia.scm.filter; +import static sonia.scm.api.v2.resources.ScmPathInfo.REST_API_PATH; + /** * Useful constants for filter implementations. * @@ -44,26 +46,26 @@ public final class Filters public static final String PATTERN_ALL = "/*"; /** Field description */ - public static final String PATTERN_CONFIG = "/api/rest/config*"; + public static final String PATTERN_CONFIG = REST_API_PATH + "/config*"; /** Field description */ public static final String PATTERN_DEBUG = "/debug.html"; /** Field description */ - public static final String PATTERN_GROUPS = "/api/rest/groups*"; + public static final String PATTERN_GROUPS = REST_API_PATH + "/groups*"; /** Field description */ - public static final String PATTERN_PLUGINS = "/api/rest/plugins*"; + public static final String PATTERN_PLUGINS = REST_API_PATH + "/plugins*"; /** Field description */ public static final String PATTERN_RESOURCE_REGEX = "^/(?:resources|api|plugins|index)[\\./].*(?:html|\\.css|\\.js|\\.xml|\\.json|\\.txt)"; /** Field description */ - public static final String PATTERN_RESTAPI = "/api/rest/*"; + public static final String PATTERN_RESTAPI = REST_API_PATH + "/*"; /** Field description */ - public static final String PATTERN_USERS = "/api/rest/users*"; + public static final String PATTERN_USERS = REST_API_PATH + "/users*"; /** authentication priority */ public static final int PRIORITY_AUTHENTICATION = 5000; diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java index fd330a6d1d..e9ec9e4a39 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java @@ -119,6 +119,8 @@ import sonia.scm.web.security.DefaultAdministrationContext; import javax.net.ssl.SSLContext; import javax.servlet.ServletContext; +import static sonia.scm.api.v2.resources.ScmPathInfo.REST_API_PATH; + /** * * @author Sebastian Sdorra @@ -128,14 +130,14 @@ public class ScmServletModule extends ServletModule /** Field description */ public static final String[] PATTERN_ADMIN = new String[] { - "/api/rest/groups*", - "/api/rest/users*", "/api/rest/plguins*" }; + REST_API_PATH + "/groups*", + REST_API_PATH + "/users*", REST_API_PATH + "/plguins*" }; /** Field description */ public static final String PATTERN_ALL = "/*"; /** Field description */ - public static final String PATTERN_CONFIG = "/api/rest/config*"; + public static final String PATTERN_CONFIG = REST_API_PATH + "/config*"; /** Field description */ public static final String PATTERN_DEBUG = "/debug.html"; diff --git a/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java b/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java index 0d59d77027..de0d689c52 100644 --- a/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java +++ b/scm-webapp/src/main/java/sonia/scm/filter/SecurityFilter.java @@ -37,10 +37,8 @@ package sonia.scm.filter; import com.google.common.annotations.VisibleForTesting; import com.google.inject.Inject; - import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; - import sonia.scm.Priority; import sonia.scm.SCMContext; import sonia.scm.config.ScmConfiguration; @@ -48,14 +46,15 @@ import sonia.scm.security.SecurityRequests; import sonia.scm.web.filter.HttpFilter; import sonia.scm.web.filter.SecurityHttpServletRequestWrapper; -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; - import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +import static sonia.scm.api.v2.resources.ScmPathInfo.REST_API_PATH; + +//~--- JDK imports ------------------------------------------------------------ /** * @@ -63,7 +62,8 @@ import javax.servlet.http.HttpServletResponse; */ @Priority(Filters.PRIORITY_AUTHORIZATION) // TODO find a better way for unprotected resources -@WebElement(value = "/api/rest/(?!v2/ui).*", regex = true) +@WebElement(value = REST_API_PATH + "" + + "/(?!v2/ui).*", regex = true) public class SecurityFilter extends HttpFilter { diff --git a/scm-webapp/src/main/java/sonia/scm/security/SecurityRequests.java b/scm-webapp/src/main/java/sonia/scm/security/SecurityRequests.java index 225767cd3b..81bb2092c9 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/SecurityRequests.java +++ b/scm-webapp/src/main/java/sonia/scm/security/SecurityRequests.java @@ -3,12 +3,14 @@ package sonia.scm.security; import javax.servlet.http.HttpServletRequest; import java.util.regex.Pattern; +import static sonia.scm.api.v2.resources.ScmPathInfo.REST_API_PATH; + /** * Created by masuewer on 04.07.18. */ public final class SecurityRequests { - private static final Pattern URI_LOGIN_PATTERN = Pattern.compile("/api/rest(?:/v2)?/auth/access_token"); + private static final Pattern URI_LOGIN_PATTERN = Pattern.compile(REST_API_PATH + "(?:/v2)?/auth/access_token"); private SecurityRequests() {} From 7fc78e7c32296406a3b90af036a0ba2a645d26a8 Mon Sep 17 00:00:00 2001 From: Johannes Schnatterer Date: Wed, 12 Sep 2018 17:57:48 +0200 Subject: [PATCH 35/58] Maven: Downgrade to animal-sniffer Prepares migration to oss.cloudogu.com. There, builds failed every now and then (when a lot of builds ran in parallel) with the problem described in the link of the comment in pom.xml --- pom.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8ca4318230..944ebb6eb6 100644 --- a/pom.xml +++ b/pom.xml @@ -430,7 +430,9 @@ org.codehaus.mojo animal-sniffer-maven-plugin - 1.17 + + 1.16 org.codehaus.mojo.signature From f9a9a94a3f7f8425424355e04ecad960c9454b95 Mon Sep 17 00:00:00 2001 From: Johannes Schnatterer Date: Wed, 12 Sep 2018 17:59:03 +0200 Subject: [PATCH 36/58] Jenkins: Run maven build in docker. Prepares migration to oss.cloudogu.com. There, we're only running on one build node, where concurrent builds result in failing integration tests, because they all bind to port 8081. --- .mvn/wrapper/maven-wrapper.properties | 1 + Jenkinsfile | 40 ++++++++++++--------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 9dda3b659b..8b4bf8dee1 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1,2 @@ +# Keep this version number in sync with Jenkinsfile distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip diff --git a/Jenkinsfile b/Jenkinsfile index cd02d15487..2c9a4e18e5 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -17,34 +17,29 @@ node() { // No specific label catchError { Maven mvn = setupMavenBuild() - // Maven build specified it must be 1.8.0-101 or newer - def javaHome = tool 'JDK-1.8.0-101+' - withEnv(["JAVA_HOME=${javaHome}", "PATH=${env.JAVA_HOME}/bin:${env.PATH}"]) { + stage('Checkout') { + checkout scm + } - stage('Checkout') { - checkout scm - } + stage('Build') { + mvn 'clean install -DskipTests' + } - stage('Build') { - mvn 'clean install -DskipTests' - } + stage('Unit Test') { + mvn 'test -Dsonia.scm.test.skip.hg=true -Dmaven.test.failure.ignore=true' + } - stage('Unit Test') { - mvn 'test -Dsonia.scm.test.skip.hg=true -Dmaven.test.failure.ignore=true' - } + stage('Integration Test') { + mvn 'verify -Pit -pl :scm-webapp,:scm-it -Dmaven.test.failure.ignore=true' + } - stage('Integration Test') { - mvn 'verify -Pit -pl :scm-webapp,:scm-it -Dmaven.test.failure.ignore=true' - } + stage('SonarQube') { - stage('SonarQube') { + analyzeWith(mvn) - analyzeWith(mvn) - - if (!waitForQualityGateWebhookToBeCalled()) { - currentBuild.result = 'UNSTABLE' - } + if (!waitForQualityGateWebhookToBeCalled()) { + currentBuild.result = 'UNSTABLE' } } } @@ -61,7 +56,8 @@ node() { // No specific label String mainBranch Maven setupMavenBuild() { - Maven mvn = new MavenWrapper(this) + // Keep this version number in sync with .mvn/maven-wrapper.properties + Maven mvn = new MavenInDocker(this, "3.5.2-jdk-8") if (mainBranch.equals(env.BRANCH_NAME)) { // Release starts javadoc, which takes very long, so do only for certain branches From 2c752f9e8b51c6b000d68fd9b91a3a22673086fb Mon Sep 17 00:00:00 2001 From: Johannes Schnatterer Date: Wed, 12 Sep 2018 18:01:00 +0200 Subject: [PATCH 37/58] Jenkins: Add a global build timeout Prepares migration to oss.cloudogu.com. There, we're recognized some builds that hang for hours after some errors. --- Jenkinsfile | 57 ++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 2c9a4e18e5..50a2374544 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,46 +11,49 @@ node() { // No specific label properties([ // Keep only the last 10 build to preserve space - buildDiscarder(logRotator(numToKeepStr: '10')), + buildDiscarder(logRotator(numToKeepStr: '10')) ]) - catchError { + timeout(activity: true, time: 20, unit: 'MINUTES') { - Maven mvn = setupMavenBuild() + catchError { - stage('Checkout') { - checkout scm - } + Maven mvn = setupMavenBuild() - stage('Build') { - mvn 'clean install -DskipTests' - } + stage('Checkout') { + checkout scm + } - stage('Unit Test') { - mvn 'test -Dsonia.scm.test.skip.hg=true -Dmaven.test.failure.ignore=true' - } + stage('Build') { + mvn 'clean install -DskipTests' + } - stage('Integration Test') { - mvn 'verify -Pit -pl :scm-webapp,:scm-it -Dmaven.test.failure.ignore=true' - } + stage('Unit Test') { + mvn 'test -Dsonia.scm.test.skip.hg=true -Dmaven.test.failure.ignore=true' + } - stage('SonarQube') { + stage('Integration Test') { + mvn 'verify -Pit -pl :scm-webapp,:scm-it -Dmaven.test.failure.ignore=true' + } - analyzeWith(mvn) + stage('SonarQube') { - if (!waitForQualityGateWebhookToBeCalled()) { - currentBuild.result = 'UNSTABLE' + analyzeWith(mvn) + + if (!waitForQualityGateWebhookToBeCalled()) { + currentBuild.result = 'UNSTABLE' + } } } + + // Archive Unit and integration test results, if any + junit allowEmptyResults: true, testResults: '**/target/failsafe-reports/TEST-*.xml,**/target/surefire-reports/TEST-*.xml,**/target/jest-reports/TEST-*.xml' + + // Find maven warnings and visualize in job + warnings consoleParsers: [[parserName: 'Maven']], canRunOnFailed: true + + mailIfStatusChanged(commitAuthorEmail) } - - // Archive Unit and integration test results, if any - junit allowEmptyResults: true, testResults: '**/target/failsafe-reports/TEST-*.xml,**/target/surefire-reports/TEST-*.xml,**/target/jest-reports/TEST-*.xml' - - // Find maven warnings and visualize in job - warnings consoleParsers: [[parserName: 'Maven']], canRunOnFailed: true - - mailIfStatusChanged(commitAuthorEmail) } String mainBranch From 145502a7b8dd1a21d3f0855227ff89d1f0d70f5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 13 Sep 2018 10:35:10 +0200 Subject: [PATCH 38/58] Introduce extension point for further protocol implementations --- .../scm/repository/api/RepositoryService.java | 44 +++++++++--------- .../api/RepositoryServiceFactory.java | 8 +++- .../repository/api/ScmProtocolProvider.java | 12 +++++ .../InitializingHttpScmProtocolWrapper.java | 7 ++- .../spi/RepositoryServiceProvider.java | 3 -- .../repository/api/RepositoryServiceTest.java | 43 +++++++++++++----- ...nitializingHttpScmProtocolWrapperTest.java | 19 +++++--- .../spi/GitRepositoryServiceProvider.java | 14 +----- .../spi/GitRepositoryServiceResolver.java | 11 ++--- .../web/GitScmProtocolProviderWrapper.java | 7 +++ .../spi/HgRepositoryServiceProvider.java | 12 +---- .../spi/HgRepositoryServiceResolver.java | 45 +++---------------- .../scm/web/HgScmProtocolProviderWrapper.java | 7 +++ .../spi/SvnRepositoryServiceProvider.java | 19 +------- .../spi/SvnRepositoryServiceResolver.java | 12 ++--- .../web/SvnScmProtocolProviderWrapper.java | 7 +++ .../RepositoryToRepositoryDtoMapper.java | 5 +-- .../resources/RepositoryRootResourceTest.java | 4 +- .../RepositoryToRepositoryDtoMapperTest.java | 11 +++-- 19 files changed, 137 insertions(+), 153 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/api/ScmProtocolProvider.java diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java index 61c3ce5d87..4d388609d8 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java @@ -42,7 +42,8 @@ import sonia.scm.repository.spi.RepositoryServiceProvider; import java.io.Closeable; import java.io.IOException; -import java.util.Collection; +import java.util.Set; +import java.util.stream.Stream; /** * From the {@link RepositoryService} it is possible to access all commands for @@ -80,29 +81,30 @@ import java.util.Collection; * @since 1.17 */ public final class RepositoryService implements Closeable { - private CacheManager cacheManager; - private PreProcessorUtil preProcessorUtil; - private RepositoryServiceProvider provider; - private Repository repository; - private static final Logger logger = - LoggerFactory.getLogger(RepositoryService.class); + + private static final Logger logger = LoggerFactory.getLogger(RepositoryService.class); + + private final CacheManager cacheManager; + private final PreProcessorUtil preProcessorUtil; + private final RepositoryServiceProvider provider; + private final Repository repository; + private final Set protocolProviders; /** * Constructs a new {@link RepositoryService}. This constructor should only * be called from the {@link RepositoryServiceFactory}. - * - * @param cacheManager cache manager + * @param cacheManager cache manager * @param provider implementation for {@link RepositoryServiceProvider} * @param repository the repository - * @param preProcessorUtil */ RepositoryService(CacheManager cacheManager, - RepositoryServiceProvider provider, Repository repository, - PreProcessorUtil preProcessorUtil) { + RepositoryServiceProvider provider, Repository repository, + PreProcessorUtil preProcessorUtil, Set protocolProviders) { this.cacheManager = cacheManager; this.provider = provider; this.repository = repository; this.preProcessorUtil = preProcessorUtil; + this.protocolProviders = protocolProviders; } /** @@ -359,16 +361,18 @@ public final class RepositoryService implements Closeable { } - public Collection getSupportedProtocols() { - return provider.getSupportedProtocols(); + public Stream getSupportedProtocols() { + return protocolProviders.stream().filter(provider -> provider.getType().equals(getRepository().getType())).map(this::createProviderInstanceForRepository); + } + + private ScmProtocol createProviderInstanceForRepository(ScmProtocolProvider protocolProvider) { + return protocolProvider.get(repository); } public T getProtocol(Class clazz) { - for (ScmProtocol scmProtocol : getSupportedProtocols()) { - if (clazz.isAssignableFrom(scmProtocol.getClass())) { - return (T) scmProtocol; - } - } - throw new IllegalArgumentException("no implementation for " + clazz.getName() + " and repository type " + getRepository().getType()); + return (T) getSupportedProtocols() + .filter(scmProtocol -> clazz.isAssignableFrom(scmProtocol.getClass())) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("no implementation for " + clazz.getName() + " and repository type " + getRepository().getType())); } } diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java index 33f57d4524..fbb1ee6b58 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java @@ -137,13 +137,15 @@ public final class RepositoryServiceFactory @Inject public RepositoryServiceFactory(ScmConfiguration configuration, CacheManager cacheManager, RepositoryManager repositoryManager, - Set resolvers, PreProcessorUtil preProcessorUtil) + Set resolvers, PreProcessorUtil preProcessorUtil, + Set protocolProviders) { this.configuration = configuration; this.cacheManager = cacheManager; this.repositoryManager = repositoryManager; this.resolvers = resolvers; this.preProcessorUtil = preProcessorUtil; + this.protocolProviders = protocolProviders; ScmEventBus.getInstance().register(new CacheClearHook(cacheManager)); } @@ -252,7 +254,7 @@ public final class RepositoryServiceFactory } service = new RepositoryService(cacheManager, provider, repository, - preProcessorUtil); + preProcessorUtil, protocolProviders); break; } @@ -367,4 +369,6 @@ public final class RepositoryServiceFactory /** service resolvers */ private final Set resolvers; + + private Set protocolProviders; } diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocolProvider.java b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocolProvider.java new file mode 100644 index 0000000000..d4be5dca59 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocolProvider.java @@ -0,0 +1,12 @@ +package sonia.scm.repository.api; + +import sonia.scm.plugin.ExtensionPoint; +import sonia.scm.repository.Repository; + +@ExtensionPoint(multi = true) +public interface ScmProtocolProvider { + + String getType(); + + ScmProtocol get(Repository repository); +} diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index c5fd037cc8..6e59470c5e 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory; import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; +import sonia.scm.repository.api.ScmProtocolProvider; import sonia.scm.web.filter.PermissionFilter; import javax.inject.Provider; @@ -18,7 +19,7 @@ import java.util.Optional; import static java.util.Optional.empty; import static java.util.Optional.of; -public abstract class InitializingHttpScmProtocolWrapper { +public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolProvider { private static final Logger logger = LoggerFactory.getLogger(InitializingHttpScmProtocolWrapper.class); @@ -41,7 +42,11 @@ public abstract class InitializingHttpScmProtocolWrapper { httpServlet.init(config); } + @Override public HttpScmProtocol get(Repository repository) { + if (!repository.getType().equals(getType())) { + throw new IllegalArgumentException("cannot handle repository with type " + repository.getType() + " with protocol for type " + getType()); + } return new ProtocolWrapper(repository); } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java index 0a56800f82..e0981b840c 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java @@ -36,7 +36,6 @@ package sonia.scm.repository.spi; import sonia.scm.repository.Feature; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.CommandNotSupportedException; -import sonia.scm.repository.api.ScmProtocol; import java.io.Closeable; import java.io.IOException; @@ -240,6 +239,4 @@ public abstract class RepositoryServiceProvider implements Closeable { throw new CommandNotSupportedException(Command.UNBUNDLE); } - - public abstract Set getSupportedProtocols(); } diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java index 9cb398b571..2ceafc19bb 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java @@ -8,38 +8,43 @@ import sonia.scm.repository.spi.RepositoryServiceProvider; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.util.Collection; import java.util.Collections; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.util.IterableUtil.sizeOf; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class RepositoryServiceTest { private final RepositoryServiceProvider provider = mock(RepositoryServiceProvider.class); - private final Repository repository = mock(Repository.class); + private final Repository repository = new Repository("", "git", "space", "repo"); @Test - public void shouldReturnProtocolsFromProvider() { - when(provider.getSupportedProtocols()).thenReturn(Collections.singleton(new DummyHttpProtocol(repository))); + public void shouldReturnMatchingProtocolsFromProvider() { + RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider())); + Stream supportedProtocols = repositoryService.getSupportedProtocols(); - RepositoryService repositoryService = new RepositoryService(null, provider, repository, null); - Collection supportedProtocols = repositoryService.getSupportedProtocols(); + assertThat(sizeOf(supportedProtocols.collect(Collectors.toList()))).isEqualTo(1); + } - assertThat(sizeOf(supportedProtocols)).isEqualTo(1); + @Test + public void shouldFindKnownProtocol() { + RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider())); + + HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class); + + assertThat(protocol).isNotNull(); } @Test public void shouldFailForUnknownProtocol() { - when(provider.getSupportedProtocols()).thenReturn(Collections.emptySet()); - - RepositoryService repositoryService = new RepositoryService(null, provider, repository, null); + RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider())); assertThrows(IllegalArgumentException.class, () -> { - repositoryService.getProtocol(HttpScmProtocol.class); + repositoryService.getProtocol(UnknownScmProtocol.class); }); } @@ -52,4 +57,18 @@ public class RepositoryServiceTest { public void serve(HttpServletRequest request, HttpServletResponse response, Repository repository, ServletConfig config) { } } + + private static class DummyScmProtocolProvider implements ScmProtocolProvider { + @Override + public String getType() { + return "git"; + } + + @Override + public ScmProtocol get(Repository repository) { + return new DummyHttpProtocol(repository); + } + } + + private interface UnknownScmProtocol extends ScmProtocol {} } diff --git a/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java b/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java index 1e742a768a..6d01232fe3 100644 --- a/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java @@ -62,7 +62,12 @@ public class InitializingHttpScmProtocolWrapperTest { pathInfoStoreProvider = mock(Provider.class); when(pathInfoStoreProvider.get()).thenReturn(pathInfoStore); - wrapper = new InitializingHttpScmProtocolWrapper(Providers.of(this.delegateServlet), Providers.of(permissionFilter), pathInfoStoreProvider, scmConfiguration) {}; + wrapper = new InitializingHttpScmProtocolWrapper(Providers.of(this.delegateServlet), Providers.of(permissionFilter), pathInfoStoreProvider, scmConfiguration) { + @Override + public String getType() { + return "git"; + } + }; when(scmConfiguration.getBaseUrl()).thenReturn("http://example.com/scm"); } @@ -127,6 +132,11 @@ public class InitializingHttpScmProtocolWrapperTest { verify(delegateServlet, times(2)).service(request, response, REPOSITORY); } + @Test(expected = IllegalArgumentException.class) + public void shouldFailForIllegalScmType() { + HttpScmProtocol httpScmProtocol = wrapper.get(new Repository("", "other", "space", "name")); + } + private Answer proceedInvocation() { return invocation -> { ((PermissionFilter.ContinuationServlet) invocation.getArgument(3)).doService(); @@ -135,12 +145,7 @@ public class InitializingHttpScmProtocolWrapperTest { } private OngoingStubbing mockSetPathInfo() { - return when(pathInfoStore.get()).thenReturn(new ScmPathInfo() { - @Override - public URI getApiRestUri() { - return URI.create("http://example.com/scm/api/rest/"); - } - }); + return when(pathInfoStore.get()).thenReturn(() -> URI.create("http://example.com/scm/api/rest/")); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java index 235136938a..2d6b49a8e5 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java @@ -37,10 +37,8 @@ import com.google.common.collect.ImmutableSet; import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; -import sonia.scm.repository.api.ScmProtocol; import java.io.IOException; -import java.util.Collections; import java.util.Set; /** @@ -69,12 +67,9 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider //~--- constructors --------------------------------------------------------- - public GitRepositoryServiceProvider(GitRepositoryHandler handler, - Repository repository, HttpScmProtocol httpScmProtocol) - { + public GitRepositoryServiceProvider(GitRepositoryHandler handler, Repository repository) { this.handler = handler; this.repository = repository; - this.httpScmProtocol = httpScmProtocol; this.context = new GitContext(handler.getDirectory(repository)); } @@ -238,11 +233,6 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider return new GitTagsCommand(context, repository); } - @Override - public Set getSupportedProtocols() { - return Collections.singleton(httpScmProtocol); - } - //~--- fields --------------------------------------------------------------- /** Field description */ @@ -253,6 +243,4 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider /** Field description */ private Repository repository; - - private final HttpScmProtocol httpScmProtocol; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java index d20eedca9f..b1e9143afd 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java @@ -38,7 +38,6 @@ import com.google.inject.Inject; import sonia.scm.plugin.Extension; import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; -import sonia.scm.web.GitScmProtocolProviderWrapper; /** * @@ -49,10 +48,11 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver { public static final String TYPE = "git"; + private final GitRepositoryHandler handler; + @Inject - public GitRepositoryServiceResolver(GitRepositoryHandler handler, GitScmProtocolProviderWrapper providerWrapper) { + public GitRepositoryServiceResolver(GitRepositoryHandler handler) { this.handler = handler; - this.providerWrapper = providerWrapper; } @Override @@ -60,12 +60,9 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver { GitRepositoryServiceProvider provider = null; if (TYPE.equalsIgnoreCase(repository.getType())) { - provider = new GitRepositoryServiceProvider(handler, repository, providerWrapper.get(repository)); + provider = new GitRepositoryServiceProvider(handler, repository); } return provider; } - - private final GitRepositoryHandler handler; - private final GitScmProtocolProviderWrapper providerWrapper; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java index 8ff0c6d421..3df7bcce3f 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java @@ -2,6 +2,7 @@ package sonia.scm.web; import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; +import sonia.scm.plugin.Extension; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import javax.inject.Inject; @@ -9,9 +10,15 @@ import javax.inject.Provider; import javax.inject.Singleton; @Singleton +@Extension public class GitScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject public GitScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); } + + @Override + public String getType() { + return "git"; + } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java index 8c280a9915..164eb4e13a 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java @@ -39,11 +39,9 @@ import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; -import sonia.scm.repository.api.ScmProtocol; import java.io.File; import java.io.IOException; -import java.util.Collections; import java.util.EnumSet; import java.util.Set; @@ -78,11 +76,10 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider //~--- constructors --------------------------------------------------------- HgRepositoryServiceProvider(HgRepositoryHandler handler, - HgHookManager hookManager, Repository repository, HttpScmProtocol httpScmProtocol) + HgHookManager hookManager, Repository repository) { this.repository = repository; this.handler = handler; - this.httpScmProtocol = httpScmProtocol; this.repositoryDirectory = handler.getDirectory(repository); this.context = new HgCommandContext(hookManager, handler, repository, repositoryDirectory); @@ -260,11 +257,6 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider return new HgTagsCommand(context, repository); } - @Override - public Set getSupportedProtocols() { - return Collections.singleton(httpScmProtocol); - } - //~--- fields --------------------------------------------------------------- /** Field description */ @@ -278,6 +270,4 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider /** Field description */ private File repositoryDirectory; - - private final HttpScmProtocol httpScmProtocol; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java index c1accbad1a..f80dcd5ba8 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java @@ -38,7 +38,6 @@ import sonia.scm.plugin.Extension; import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; -import sonia.scm.web.HgScmProtocolProviderWrapper; /** * @@ -48,59 +47,27 @@ import sonia.scm.web.HgScmProtocolProviderWrapper; public class HgRepositoryServiceResolver implements RepositoryServiceResolver { - /** Field description */ private static final String TYPE = "hg"; - //~--- constructors --------------------------------------------------------- + private HgRepositoryHandler handler; + private HgHookManager hookManager; - /** - * Constructs ... - * - * - * - * @param hookManager - * @param handler - */ @Inject public HgRepositoryServiceResolver(HgRepositoryHandler handler, - HgHookManager hookManager, HgScmProtocolProviderWrapper providerWrapper) + HgHookManager hookManager) { this.handler = handler; this.hookManager = hookManager; - this.providerWrapper = providerWrapper; } - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - * - * @param repository - * - * @return - */ @Override - public HgRepositoryServiceProvider resolve(Repository repository) - { + public HgRepositoryServiceProvider resolve(Repository repository) { HgRepositoryServiceProvider provider = null; - if (TYPE.equalsIgnoreCase(repository.getType())) - { - provider = new HgRepositoryServiceProvider(handler, hookManager, - repository, providerWrapper.get(repository)); + if (TYPE.equalsIgnoreCase(repository.getType())) { + provider = new HgRepositoryServiceProvider(handler, hookManager, repository); } return provider; } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private HgRepositoryHandler handler; - - /** Field description */ - private HgHookManager hookManager; - - private final HgScmProtocolProviderWrapper providerWrapper; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java index e843f09ad4..5ea8e66501 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java @@ -2,6 +2,7 @@ package sonia.scm.web; import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; +import sonia.scm.plugin.Extension; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import javax.inject.Inject; @@ -9,9 +10,15 @@ import javax.inject.Provider; import javax.inject.Singleton; @Singleton +@Extension public class HgScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject public HgScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); } + + @Override + public String getType() { + return "hg"; + } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java index 6c08d35897..909daf7e36 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java @@ -38,10 +38,8 @@ import com.google.common.io.Closeables; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; import sonia.scm.repository.api.Command; -import sonia.scm.repository.api.ScmProtocol; import java.io.IOException; -import java.util.Collections; import java.util.Set; /** @@ -61,18 +59,10 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider //~--- constructors --------------------------------------------------------- - /** - * Constructs ... - * - * @param handler - * @param repository - * @param httpScmProtocol - */ SvnRepositoryServiceProvider(SvnRepositoryHandler handler, - Repository repository, HttpScmProtocol httpScmProtocol) + Repository repository) { this.repository = repository; - this.httpScmProtocol = httpScmProtocol; this.context = new SvnContext(handler.getDirectory(repository)); } @@ -188,11 +178,6 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider return new SvnUnbundleCommand(context, repository); } - @Override - public Set getSupportedProtocols() { - return Collections.singleton(httpScmProtocol); - } - //~--- fields --------------------------------------------------------------- /** Field description */ @@ -200,6 +185,4 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider /** Field description */ private final Repository repository; - - private final HttpScmProtocol httpScmProtocol; } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java index 9f5ea234ce..c674a7827a 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java @@ -36,17 +36,17 @@ import com.google.inject.Inject; import sonia.scm.plugin.Extension; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; -import sonia.scm.web.SvnScmProtocolProviderWrapper; @Extension public class SvnRepositoryServiceResolver implements RepositoryServiceResolver { public static final String TYPE = "svn"; + private SvnRepositoryHandler handler; + @Inject - public SvnRepositoryServiceResolver(SvnRepositoryHandler handler, SvnScmProtocolProviderWrapper protocolWrapper) { + public SvnRepositoryServiceResolver(SvnRepositoryHandler handler) { this.handler = handler; - this.protocolWrapper = protocolWrapper; } @Override @@ -54,13 +54,9 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver { SvnRepositoryServiceProvider provider = null; if (TYPE.equalsIgnoreCase(repository.getType())) { - provider = new SvnRepositoryServiceProvider(handler, repository, protocolWrapper.get(repository)); + provider = new SvnRepositoryServiceProvider(handler, repository); } return provider; } - - private SvnRepositoryHandler handler; - - private final InitializingHttpScmProtocolWrapper protocolWrapper; } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java index ebcfa138bc..14b946acc7 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -2,6 +2,7 @@ package sonia.scm.web; import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; +import sonia.scm.plugin.Extension; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import sonia.scm.repository.spi.ScmProviderHttpServlet; @@ -14,10 +15,16 @@ import javax.servlet.ServletException; import java.util.Enumeration; @Singleton +@Extension public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { public static final String PARAMETER_SVN_PARENTPATH = "SVNParentPath"; + @Override + public String getType() { + return "svn"; + } + @Inject public SvnScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java index ce716f2f6f..6675caac88 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java @@ -14,7 +14,6 @@ import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.repository.api.ScmProtocol; -import java.util.Collection; import java.util.List; import static de.otto.edison.hal.Link.link; @@ -47,9 +46,7 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper supportedProtocols = repositoryService.getSupportedProtocols(); - List protocolLinks = supportedProtocols - .stream() + List protocolLinks = repositoryService.getSupportedProtocols() .map(protocol -> createProtocolLink(protocol, repository)) .collect(toList()); linksBuilder.array(protocolLinks); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index 4d0bb38785..04a4602a7c 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -30,8 +30,8 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import static java.util.Arrays.asList; import static java.util.Collections.singletonList; +import static java.util.stream.Stream.of; import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT; @@ -281,7 +281,7 @@ public class RepositoryRootResourceTest { @Test public void shouldCreateArrayOfProtocolUrls() throws Exception { mockRepository("space", "repo"); - when(service.getSupportedProtocols()).thenReturn(asList(new MockScmProtocol("http", "http://"), new MockScmProtocol("ssh", "ssh://"))); + when(service.getSupportedProtocols()).thenReturn(of(new MockScmProtocol("http", "http://"), new MockScmProtocol("ssh", "ssh://"))); MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo"); MockHttpResponse response = new MockHttpResponse(); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java index 0fbece9730..d60b62937e 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java @@ -20,9 +20,8 @@ import sonia.scm.repository.api.ScmProtocol; import java.net.URI; -import static java.util.Arrays.asList; -import static java.util.Collections.emptySet; import static java.util.Collections.singletonList; +import static java.util.stream.Stream.of; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -60,7 +59,7 @@ public class RepositoryToRepositoryDtoMapperTest { initMocks(this); when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService); when(repositoryService.isSupported(any(Command.class))).thenReturn(true); - when(repositoryService.getSupportedProtocols()).thenReturn(emptySet()); + when(repositoryService.getSupportedProtocols()).thenReturn(of()); when(scmPathInfoStore.get()).thenReturn(uriInfo); when(uriInfo.getApiRestUri()).thenReturn(URI.create("/x/y")); } @@ -182,7 +181,7 @@ public class RepositoryToRepositoryDtoMapperTest { @Test public void shouldCreateCorrectProtocolLinks() { when(repositoryService.getSupportedProtocols()).thenReturn( - asList(mockProtocol("http", "http://scm"), mockProtocol("other", "some://protocol")) + of(mockProtocol("http", "http://scm"), mockProtocol("other", "some://protocol")) ); RepositoryDto dto = mapper.map(createTestRepository()); @@ -194,7 +193,7 @@ public class RepositoryToRepositoryDtoMapperTest { @SubjectAware(username = "community") public void shouldCreateProtocolLinksForPullPermission() { when(repositoryService.getSupportedProtocols()).thenReturn( - asList(mockProtocol("http", "http://scm"), mockProtocol("other", "some://protocol")) + of(mockProtocol("http", "http://scm"), mockProtocol("other", "some://protocol")) ); RepositoryDto dto = mapper.map(createTestRepository()); @@ -205,7 +204,7 @@ public class RepositoryToRepositoryDtoMapperTest { @SubjectAware(username = "unpriv") public void shouldNotCreateProtocolLinksWithoutPullPermission() { when(repositoryService.getSupportedProtocols()).thenReturn( - asList(mockProtocol("http", "http://scm"), mockProtocol("other", "some://protocol")) + of(mockProtocol("http", "http://scm"), mockProtocol("other", "some://protocol")) ); RepositoryDto dto = mapper.map(createTestRepository()); From c5daacfd589ec0bf1e07dfc00532368dcf75d356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 13 Sep 2018 10:45:51 +0200 Subject: [PATCH 39/58] Format --- .../main/java/sonia/scm/repository/api/RepositoryService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java index 4d388609d8..b9e1cb2a5d 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java @@ -362,7 +362,9 @@ public final class RepositoryService implements Closeable { public Stream getSupportedProtocols() { - return protocolProviders.stream().filter(provider -> provider.getType().equals(getRepository().getType())).map(this::createProviderInstanceForRepository); + return protocolProviders.stream() + .filter(provider -> provider.getType().equals(getRepository().getType())) + .map(this::createProviderInstanceForRepository); } private ScmProtocol createProviderInstanceForRepository(ScmProtocolProvider protocolProvider) { From 4697c55f96b5610c8e1e911be04bc984e427cf65 Mon Sep 17 00:00:00 2001 From: Mohamed Karray Date: Thu, 13 Sep 2018 11:57:10 +0200 Subject: [PATCH 40/58] implement modification api in git, svn and hg. implement the endpoint --- scm-core/pom.xml | 7 + .../java/sonia/scm/repository/Changeset.java | 41 +---- .../java/sonia/scm/repository/EscapeUtil.java | 12 +- .../sonia/scm/repository/Modifications.java | 13 +- .../repository/ModificationsPreProcessor.java | 23 +++ .../ModificationsPreProcessorFactory.java | 26 +++ .../scm/repository/PreProcessorUtil.java | 103 ++++++------ .../sonia/scm/repository/api/Command.java | 8 +- .../api/ModificationsCommandBuilder.java | 114 +++++++++++++ .../scm/repository/api/RepositoryService.java | 12 ++ .../repository/spi/ModificationsCommand.java | 61 ++----- .../spi/ModificationsCommandRequest.java | 24 +++ .../spi/RepositoryServiceProvider.java | 15 +- .../main/java/sonia/scm/web/VndMediaType.java | 1 + .../scm/repository/GitChangesetConverter.java | 119 +------------- .../spi/GitModificationsCommand.java | 106 ++++++++++++ .../spi/GitRepositoryServiceProvider.java | 11 +- .../UnsupportedModificationTypeException.java | 9 ++ .../spi/AbstractRemoteCommandTestBase.java | 6 +- .../spi/GitIncomingCommandTest.java | 4 +- .../scm/repository/spi/GitLogCommandTest.java | 18 ++- .../spi/GitModificationsCommandTest.java | 126 +++++++++++++++ .../spi/GitOutgoingCommandTest.java | 10 +- .../repository/spi/GitPushCommandTest.java | 2 +- .../spi/HgModificationsCommand.java | 32 ++++ .../spi/javahg/AbstractChangesetCommand.java | 60 ++++--- .../spi/javahg/HgLogChangesetCommand.java | 29 ++-- .../client/spi/HgCommitCommand.java | 7 +- .../scm/repository/spi/HgLogCommandTest.java | 26 +-- .../spi/HgModificationsCommandTest.java | 111 +++++++++++++ .../java/sonia/scm/repository/SvnUtil.java | 65 ++++---- .../scm/repository/spi/SvnLogCommand.java | 21 +-- .../spi/SvnModificationsCommand.java | 50 ++++++ .../SvnPreReceiveHookChangesetProvier.java | 11 +- .../scm/repository/spi/SvnLogCommandTest.java | 20 +-- .../rest/IllegalArgumentExceptionMapper.java | 3 +- .../ChangesetToChangesetDtoMapper.java | 3 +- .../InternalRepositoryExceptionMapper.java | 15 ++ .../scm/api/v2/resources/MapperModule.java | 1 + .../api/v2/resources/ModificationsDto.java | 45 ++++++ .../resources/ModificationsRootResource.java | 70 ++++++++ .../resources/ModificationsToDtoMapper.java | 31 ++++ .../api/v2/resources/RepositoryResource.java | 7 +- .../scm/api/v2/resources/ResourceLinks.java | 15 ++ .../v2/resources/BranchRootResourceTest.java | 2 +- .../resources/ChangesetRootResourceTest.java | 2 +- .../resources/ModificationsResourceTest.java | 151 ++++++++++++++++++ .../resources/PermissionRootResourceTest.java | 2 +- .../resources/RepositoryRootResourceTest.java | 2 +- .../api/v2/resources/ResourceLinksMock.java | 1 + .../v2/resources/SourceRootResourceTest.java | 2 +- .../api/v2/resources/TagRootResourceTest.java | 2 +- 52 files changed, 1231 insertions(+), 426 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/ModificationsPreProcessor.java create mode 100644 scm-core/src/main/java/sonia/scm/repository/ModificationsPreProcessorFactory.java create mode 100644 scm-core/src/main/java/sonia/scm/repository/api/ModificationsCommandBuilder.java rename scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnModificationHandler.java => scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommand.java (57%) create mode 100644 scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommandRequest.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModificationsCommand.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/UnsupportedModificationTypeException.java create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModificationsCommand.java create mode 100644 scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModificationsCommandTest.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnModificationsCommand.java create mode 100644 scm-webapp/src/main/java/sonia/scm/api/v2/resources/InternalRepositoryExceptionMapper.java create mode 100644 scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsDto.java create mode 100644 scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsRootResource.java create mode 100644 scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsToDtoMapper.java create mode 100644 scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 17ca03b115..a3fa037c7b 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -32,6 +32,13 @@ scm-annotations 2.0.0-SNAPSHOT + + + org.projectlombok + lombok + provided + + diff --git a/scm-core/src/main/java/sonia/scm/repository/Changeset.java b/scm-core/src/main/java/sonia/scm/repository/Changeset.java index 18ede493f6..7397fecabe 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Changeset.java +++ b/scm-core/src/main/java/sonia/scm/repository/Changeset.java @@ -41,7 +41,6 @@ import sonia.scm.util.ValidationUtil; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import java.util.ArrayList; import java.util.Date; @@ -84,12 +83,6 @@ public class Changeset extends BasicPropertiesAware implements ModelObject { */ private String id; - /** - * List of files changed by this changeset - */ - @XmlElement(name = "modifications") - private Modifications modifications; - /** * parent changeset ids */ @@ -137,7 +130,6 @@ public class Changeset extends BasicPropertiesAware implements ModelObject { && Objects.equal(parents, other.parents) && Objects.equal(tags, other.tags) && Objects.equal(branches, other.branches) - && Objects.equal(modifications, other.modifications) && Objects.equal(properties, other.properties); //J+ } @@ -152,7 +144,7 @@ public class Changeset extends BasicPropertiesAware implements ModelObject { public int hashCode() { return Objects.hashCode(id, date, author, description, parents, tags, - branches, modifications, properties); + branches, properties); } /** @@ -184,11 +176,6 @@ public class Changeset extends BasicPropertiesAware implements ModelObject { out.append("branches: ").append(Util.toString(branches)).append("\n"); out.append("tags: ").append(Util.toString(tags)).append("\n"); - if (modifications != null) - { - out.append("modifications: \n").append(modifications); - } - return out.toString(); } @@ -285,21 +272,6 @@ public class Changeset extends BasicPropertiesAware implements ModelObject { } - /** - * Returns the file modifications, which was done with this changeset. - * - * - * @return file modifications - */ - public Modifications getModifications() - { - if (modifications == null) - { - modifications = new Modifications(); - } - - return modifications; - } /** * Return the ids of the parent changesets. @@ -402,17 +374,6 @@ public class Changeset extends BasicPropertiesAware implements ModelObject { this.id = id; } - /** - * Sets the file modification of the changeset. - * - * - * @param modifications file modifications - */ - public void setModifications(Modifications modifications) - { - this.modifications = modifications; - } - /** * Sets the parents of the changeset. * diff --git a/scm-core/src/main/java/sonia/scm/repository/EscapeUtil.java b/scm-core/src/main/java/sonia/scm/repository/EscapeUtil.java index a06472256d..979ea0056d 100644 --- a/scm-core/src/main/java/sonia/scm/repository/EscapeUtil.java +++ b/scm-core/src/main/java/sonia/scm/repository/EscapeUtil.java @@ -36,15 +36,13 @@ package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.collect.Lists; - import org.apache.commons.lang.StringEscapeUtils; - import sonia.scm.util.Util; -//~--- JDK imports ------------------------------------------------------------ - import java.util.List; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -200,4 +198,10 @@ public final class EscapeUtil return values; } + + public static void escape(Modifications modifications) { + modifications.setAdded(escapeList(modifications.getAdded())); + modifications.setModified(escapeList(modifications.getModified())); + modifications.setRemoved(escapeList(modifications.getRemoved())); + } } diff --git a/scm-core/src/main/java/sonia/scm/repository/Modifications.java b/scm-core/src/main/java/sonia/scm/repository/Modifications.java index 4079d8f574..a679b0429f 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Modifications.java +++ b/scm-core/src/main/java/sonia/scm/repository/Modifications.java @@ -67,7 +67,8 @@ public class Modifications implements Serializable * Constructs ... * */ - public Modifications() {} + public Modifications() { + } /** * Constructs ... @@ -218,6 +219,10 @@ public class Modifications implements Serializable return removed; } + public String getRevision() { + return revision; + } + //~--- set methods ---------------------------------------------------------- /** @@ -253,8 +258,14 @@ public class Modifications implements Serializable this.removed = removed; } + public void setRevision(String revision) { + this.revision = revision; + } + //~--- fields --------------------------------------------------------------- + private String revision; + /** list of added files */ @XmlElement(name = "added") @XmlElementWrapper(name = "added") diff --git a/scm-core/src/main/java/sonia/scm/repository/ModificationsPreProcessor.java b/scm-core/src/main/java/sonia/scm/repository/ModificationsPreProcessor.java new file mode 100644 index 0000000000..e5870e91aa --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/ModificationsPreProcessor.java @@ -0,0 +1,23 @@ +package sonia.scm.repository; + +import sonia.scm.plugin.ExtensionPoint; + + +/** + * A pre processor for {@link Modifications} objects. A pre processor is able to + * modify the object before it is delivered to the user interface. + * + * @author Mohamed Karray + * @since 2.0 + */ +@ExtensionPoint +public interface ModificationsPreProcessor extends PreProcessor { + + /** + * Process the given modifications. + * + * @param modifications modifications to process + */ + @Override + void process(Modifications modifications); +} diff --git a/scm-core/src/main/java/sonia/scm/repository/ModificationsPreProcessorFactory.java b/scm-core/src/main/java/sonia/scm/repository/ModificationsPreProcessorFactory.java new file mode 100644 index 0000000000..71a6a38efa --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/ModificationsPreProcessorFactory.java @@ -0,0 +1,26 @@ +package sonia.scm.repository; + +import sonia.scm.plugin.ExtensionPoint; + + +/** + * This factory create a {@link ModificationsPreProcessor} + * + * @author Mohamed Karray + * @since 2.0 + */ +@ExtensionPoint +public interface ModificationsPreProcessorFactory extends PreProcessorFactory { + + /** + * Create a new {@link ModificationsPreProcessor} for the given repository. + * + * + * @param repository repository + * + * @return {@link ModificationsPreProcessor} for the given repository + */ + @Override + ModificationsPreProcessor createPreProcessor(Repository repository); + +} diff --git a/scm-core/src/main/java/sonia/scm/repository/PreProcessorUtil.java b/scm-core/src/main/java/sonia/scm/repository/PreProcessorUtil.java index b44da13ad1..98730c2039 100644 --- a/scm-core/src/main/java/sonia/scm/repository/PreProcessorUtil.java +++ b/scm-core/src/main/java/sonia/scm/repository/PreProcessorUtil.java @@ -36,17 +36,15 @@ package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- import com.google.inject.Inject; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import sonia.scm.util.Util; -//~--- JDK imports ------------------------------------------------------------ - import java.util.Collection; import java.util.Set; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -73,14 +71,18 @@ public class PreProcessorUtil * @param fileObjectPreProcessorFactorySet * @param blameLinePreProcessorSet * @param blameLinePreProcessorFactorySet + * @param modificationsPreProcessorFactorySet + * @param modificationsPreProcessorSet */ @Inject public PreProcessorUtil(Set changesetPreProcessorSet, - Set changesetPreProcessorFactorySet, - Set fileObjectPreProcessorSet, - Set fileObjectPreProcessorFactorySet, - Set blameLinePreProcessorSet, - Set blameLinePreProcessorFactorySet) + Set changesetPreProcessorFactorySet, + Set fileObjectPreProcessorSet, + Set fileObjectPreProcessorFactorySet, + Set blameLinePreProcessorSet, + Set blameLinePreProcessorFactorySet, + Set modificationsPreProcessorFactorySet, + Set modificationsPreProcessorSet) { this.changesetPreProcessorSet = changesetPreProcessorSet; this.changesetPreProcessorFactorySet = changesetPreProcessorFactorySet; @@ -88,6 +90,8 @@ public class PreProcessorUtil this.fileObjectPreProcessorFactorySet = fileObjectPreProcessorFactorySet; this.blameLinePreProcessorSet = blameLinePreProcessorSet; this.blameLinePreProcessorFactorySet = blameLinePreProcessorFactorySet; + this.modificationsPreProcessorFactorySet = modificationsPreProcessorFactorySet; + this.modificationsPreProcessorSet = modificationsPreProcessorSet; } //~--- methods -------------------------------------------------------------- @@ -108,13 +112,7 @@ public class PreProcessorUtil } EscapeUtil.escape(blameLine); - - PreProcessorHandler handler = - new PreProcessorHandler(blameLinePreProcessorFactorySet, - blameLinePreProcessorSet, repository); - - handler.callPreProcessors(blameLine); - handler.callPreProcessorFactories(blameLine); + handlePreProcess(repository,blameLine,blameLinePreProcessorFactorySet, blameLinePreProcessorSet); } /** @@ -152,13 +150,7 @@ public class PreProcessorUtil { EscapeUtil.escape(blameResult); } - - PreProcessorHandler handler = - new PreProcessorHandler(blameLinePreProcessorFactorySet, - blameLinePreProcessorSet, repository); - - handler.callPreProcessors(blameResult.getBlameLines()); - handler.callPreProcessorFactories(blameResult.getBlameLines()); + handlePreProcessForIterable(repository, blameResult.getBlameLines(),blameLinePreProcessorFactorySet, blameLinePreProcessorSet); } /** @@ -183,26 +175,20 @@ public class PreProcessorUtil * * @since 1.35 */ - public void prepareForReturn(Repository repository, Changeset changeset, - boolean escape) - { - if (logger.isTraceEnabled()) - { - logger.trace("prepare changeset {} of repository {} for return", - changeset.getId(), repository.getName()); - } - - if (escape) - { + public void prepareForReturn(Repository repository, Changeset changeset, boolean escape){ + logger.trace("prepare changeset {} of repository {} for return", changeset.getId(), repository.getName()); + if (escape) { EscapeUtil.escape(changeset); } + handlePreProcess(repository, changeset, changesetPreProcessorFactorySet, changesetPreProcessorSet); + } - PreProcessorHandler handler = - new PreProcessorHandler(changesetPreProcessorFactorySet, - changesetPreProcessorSet, repository); - - handler.callPreProcessors(changeset); - handler.callPreProcessorFactories(changeset); + public void prepareForReturn(Repository repository, Modifications modifications, boolean escape) { + logger.trace("prepare modifications {} of repository {} for return", modifications, repository.getName()); + if (escape) { + EscapeUtil.escape(modifications); + } + handlePreProcess(repository, modifications, modificationsPreProcessorFactorySet, modificationsPreProcessorSet); } /** @@ -240,13 +226,7 @@ public class PreProcessorUtil { EscapeUtil.escape(result); } - - PreProcessorHandler handler = - new PreProcessorHandler(fileObjectPreProcessorFactorySet, - fileObjectPreProcessorSet, repository); - - handler.callPreProcessors(result); - handler.callPreProcessorFactories(result); + handlePreProcessForIterable(repository, result,fileObjectPreProcessorFactorySet, fileObjectPreProcessorSet); } /** @@ -272,13 +252,7 @@ public class PreProcessorUtil { EscapeUtil.escape(result); } - - PreProcessorHandler handler = - new PreProcessorHandler(changesetPreProcessorFactorySet, - changesetPreProcessorSet, repository); - - handler.callPreProcessors(result); - handler.callPreProcessorFactories(result); + handlePreProcessForIterable(repository,result,changesetPreProcessorFactorySet, changesetPreProcessorSet); } /** @@ -294,6 +268,23 @@ public class PreProcessorUtil prepareForReturn(repository, result, true); } + + private , P extends PreProcessor> void handlePreProcess(Repository repository, T processedObject, + Collection factories, + Collection

preProcessors) { + PreProcessorHandler handler = new PreProcessorHandler(factories, preProcessors, repository); + handler.callPreProcessors(processedObject); + handler.callPreProcessorFactories(processedObject); + } + + private , F extends PreProcessorFactory, P extends PreProcessor> void handlePreProcessForIterable(Repository repository, I processedObjects, + Collection factories, + Collection

preProcessors) { + PreProcessorHandler handler = new PreProcessorHandler(factories, preProcessors, repository); + handler.callPreProcessors(processedObjects); + handler.callPreProcessorFactories(processedObjects); + } + //~--- inner classes -------------------------------------------------------- /** @@ -454,6 +445,10 @@ public class PreProcessorUtil /** Field description */ private final Collection changesetPreProcessorSet; + private final Collection modificationsPreProcessorFactorySet; + + private final Collection modificationsPreProcessorSet; + /** Field description */ private final Collection fileObjectPreProcessorFactorySet; diff --git a/scm-core/src/main/java/sonia/scm/repository/api/Command.java b/scm-core/src/main/java/sonia/scm/repository/api/Command.java index ccb0d8c2c0..2f844cfbfb 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/Command.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/Command.java @@ -61,5 +61,11 @@ public enum Command /** * @since 1.43 */ - BUNDLE, UNBUNDLE; + BUNDLE, UNBUNDLE, + + /** + * @since 2.0 + */ + MODIFICATIONS + } diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ModificationsCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/ModificationsCommandBuilder.java new file mode 100644 index 0000000000..954e810a65 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/api/ModificationsCommandBuilder.java @@ -0,0 +1,114 @@ +package sonia.scm.repository.api; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; +import sonia.scm.cache.Cache; +import sonia.scm.repository.Modifications; +import sonia.scm.repository.PreProcessorUtil; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryCacheKey; +import sonia.scm.repository.RevisionNotFoundException; +import sonia.scm.repository.spi.ModificationsCommand; +import sonia.scm.repository.spi.ModificationsCommandRequest; + +import java.io.IOException; + +/** + * Get the modifications applied to files in a revision. + *

+ * Modifications are for example: Add, Update and Delete + * + * @author Mohamed Karray + * @since 2.0 + */ +@Slf4j +@AllArgsConstructor +@RequiredArgsConstructor +@Accessors(fluent = true) +public final class ModificationsCommandBuilder { + static final String CACHE_NAME = "sonia.cache.cmd.modifications"; + + private final ModificationsCommand modificationsCommand; + + private final ModificationsCommandRequest request = new ModificationsCommandRequest(); + + private final Repository repository; + + private final Cache cache; + + private final PreProcessorUtil preProcessorUtil; + + @Setter + private boolean disableEscaping = false; + + @Setter + private boolean disableCache = false; + + @Setter + private boolean disablePreProcessors = false; + + public ModificationsCommandBuilder revision(String revision){ + request.setRevision(revision); + return this; + } + + /** + * Reset each parameter to its default value. + * + * + * @return {@code this} + */ + public ModificationsCommandBuilder reset() { + request.reset(); + this.disableCache = false; + this.disablePreProcessors = false; + return this; + } + + public Modifications getModifications() throws IOException, RevisionNotFoundException { + Modifications modifications; + if (disableCache) { + log.info("Get modifications for {} with disabled cache", request); + modifications = modificationsCommand.getModifications(request); + } else { + ModificationsCommandBuilder.CacheKey key = new ModificationsCommandBuilder.CacheKey(repository.getId(), request); + if (cache.contains(key)) { + modifications = cache.get(key); + log.debug("Get modifications for {} from the cache", request); + } else { + log.info("Get modifications for {} with enabled cache", request); + modifications = modificationsCommand.getModifications(request); + if (modifications != null) { + cache.put(key, modifications); + log.debug("Modifications for {} added to the cache with key {}", request, key); + } + } + } + if (!disablePreProcessors && (modifications != null)) { + preProcessorUtil.prepareForReturn(repository, modifications, !disableEscaping); + } + return modifications; + } + + @AllArgsConstructor + @Getter + @Setter + @EqualsAndHashCode + @ToString + class CacheKey implements RepositoryCacheKey { + private final String repositoryId; + private final ModificationsCommandRequest request; + + @Override + public String getRepositoryId() { + return repositoryId; + } + } + +} diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java index 27eed6becd..90a6248b48 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java @@ -250,6 +250,18 @@ public final class RepositoryService implements Closeable { repository, preProcessorUtil); } + /** + * The modification command shows file modifications in a revision. + * + * @return instance of {@link ModificationsCommandBuilder} + * @throws CommandNotSupportedException if the command is not supported + * by the implementation of the repository service provider. + */ + public ModificationsCommandBuilder getModificationsCommand() { + logger.debug("create modifications command for repository {}", repository.getName()); + return new ModificationsCommandBuilder(provider.getModificationsCommand(),repository, cacheManager.getCache(ModificationsCommandBuilder.CACHE_NAME), preProcessorUtil); + } + /** * The outgoing command show {@link Changeset}s not found in a remote repository. * diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnModificationHandler.java b/scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommand.java similarity index 57% rename from scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnModificationHandler.java rename to scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommand.java index f7cb60e3df..e9b40e8a17 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnModificationHandler.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommand.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2010, Sebastian Sdorra * All rights reserved. * @@ -29,60 +29,25 @@ * */ +package sonia.scm.repository.spi; +import sonia.scm.repository.Modifications; +import sonia.scm.repository.RevisionNotFoundException; -package sonia.scm.repository; - -//~--- non-JDK imports -------------------------------------------------------- - -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.wc.admin.ISVNChangeEntryHandler; -import org.tmatesoft.svn.core.wc.admin.SVNChangeEntry; +import java.io.IOException; /** + * Command to get the modifications applied to files in a revision. * - * @author Sebastian Sdorra + * Modifications are for example: Add, Update, Delete + * + * @author Mohamed Karray + * @since 2.0 */ -public class SvnModificationHandler implements ISVNChangeEntryHandler -{ +public interface ModificationsCommand { - /** - * Constructs ... - * - * - * @param changeset - */ - public SvnModificationHandler(Changeset changeset) - { - this.changeset = changeset; - } + Modifications getModifications(String revision) throws IOException, RevisionNotFoundException; - //~--- methods -------------------------------------------------------------- + Modifications getModifications(ModificationsCommandRequest request) throws IOException, RevisionNotFoundException; - /** - * Method description - * - * - * @param entry - * - * @throws SVNException - */ - @Override - public void handleEntry(SVNChangeEntry entry) throws SVNException - { - Modifications modification = changeset.getModifications(); - - if (modification == null) - { - modification = new Modifications(); - changeset.setModifications(modification); - } - - SvnUtil.appendModification(modification, entry); - } - - //~--- fields --------------------------------------------------------------- - - /** Field description */ - private Changeset changeset; } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommandRequest.java b/scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommandRequest.java new file mode 100644 index 0000000000..8a910a3396 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommandRequest.java @@ -0,0 +1,24 @@ +package sonia.scm.repository.spi; + + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@ToString +@EqualsAndHashCode +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class ModificationsCommandRequest implements Resetable { + private String revision; + + @Override + public void reset() { + revision = null; + } +} diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java index 976f38fffb..2f436836cd 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java @@ -39,14 +39,13 @@ import sonia.scm.repository.Feature; import sonia.scm.repository.api.Command; import sonia.scm.repository.api.CommandNotSupportedException; -//~--- JDK imports ------------------------------------------------------------ - import java.io.Closeable; import java.io.IOException; - import java.util.Collections; import java.util.Set; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -173,6 +172,16 @@ public abstract class RepositoryServiceProvider implements Closeable throw new CommandNotSupportedException(Command.LOG); } + /** + * Get the corresponding {@link ModificationsCommand} implemented from the Plugins + * + * @return the corresponding {@link ModificationsCommand} implemented from the Plugins + * @throws CommandNotSupportedException if there is no Implementation + */ + public ModificationsCommand getModificationsCommand() { + throw new CommandNotSupportedException(Command.MODIFICATIONS); + } + /** * Method description * diff --git a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java index ecab36969c..a5d9575efa 100644 --- a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java +++ b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java @@ -19,6 +19,7 @@ public class VndMediaType { public static final String PERMISSION = PREFIX + "permission" + SUFFIX; public static final String CHANGESET = PREFIX + "changeset" + SUFFIX; public static final String CHANGESET_COLLECTION = PREFIX + "changesetCollection" + SUFFIX; + public static final String MODIFICATIONS = PREFIX + "modifications" + SUFFIX;; public static final String TAG = PREFIX + "tag" + SUFFIX; public static final String TAG_COLLECTION = PREFIX + "tagCollection" + SUFFIX; public static final String BRANCH = PREFIX + "branch" + SUFFIX; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetConverter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetConverter.java index a59e3b5754..6936c51269 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetConverter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetConverter.java @@ -37,32 +37,25 @@ package sonia.scm.repository; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; - -import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; -import org.eclipse.jgit.treewalk.EmptyTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import sonia.scm.util.Util; -//~--- JDK imports ------------------------------------------------------------ - import java.io.Closeable; import java.io.IOException; - import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -224,13 +217,6 @@ public class GitChangesetConverter implements Closeable changeset.setParents(parentList); } - Modifications modifications = createModifications(treeWalk, commit); - - if (modifications != null) - { - changeset.setModifications(modifications); - } - Collection tagCollection = tags.get(commit.getId()); if (Util.isNotEmpty(tagCollection)) @@ -245,108 +231,7 @@ public class GitChangesetConverter implements Closeable return changeset; } - /** - * TODO: copy and rename - * - * - * @param modifications - * @param entry - */ - private void appendModification(Modifications modifications, DiffEntry entry) - { - switch (entry.getChangeType()) - { - case ADD : - modifications.getAdded().add(entry.getNewPath()); - break; - - case MODIFY : - modifications.getModified().add(entry.getNewPath()); - - break; - - case DELETE : - modifications.getRemoved().add(entry.getOldPath()); - - break; - } - } - - /** - * Method description - * - * - * @param treeWalk - * @param commit - * - * @return - * - * @throws IOException - */ - private Modifications createModifications(TreeWalk treeWalk, RevCommit commit) - throws IOException - { - Modifications modifications = null; - - treeWalk.reset(); - treeWalk.setRecursive(true); - - if (commit.getParentCount() > 0) - { - RevCommit parent = commit.getParent(0); - RevTree tree = parent.getTree(); - - if ((tree == null) && (revWalk != null)) - { - revWalk.parseHeaders(parent); - tree = parent.getTree(); - } - - if (tree != null) - { - treeWalk.addTree(tree); - } - else - { - if (logger.isTraceEnabled()) - { - logger.trace("no parent tree at position 0 for commit {}", - commit.getName()); - } - - treeWalk.addTree(new EmptyTreeIterator()); - } - } - else - { - if (logger.isTraceEnabled()) - { - logger.trace("no parent available for commit {}", commit.getName()); - } - - treeWalk.addTree(new EmptyTreeIterator()); - } - - treeWalk.addTree(commit.getTree()); - - List entries = DiffEntry.scan(treeWalk); - - for (DiffEntry e : entries) - { - if (!e.getOldId().equals(e.getNewId())) - { - if (modifications == null) - { - modifications = new Modifications(); - } - - appendModification(modifications, e); - } - } - - return modifications; - } //~--- fields --------------------------------------------------------------- diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModificationsCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModificationsCommand.java new file mode 100644 index 0000000000..2b35ba74f6 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModificationsCommand.java @@ -0,0 +1,106 @@ +package sonia.scm.repository.spi; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTree; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.EmptyTreeIterator; +import org.eclipse.jgit.treewalk.TreeWalk; +import sonia.scm.repository.GitUtil; +import sonia.scm.repository.InternalRepositoryException; +import sonia.scm.repository.Modifications; +import sonia.scm.repository.Repository; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.List; + + +@Slf4j +public class GitModificationsCommand extends AbstractGitCommand implements ModificationsCommand { + + protected GitModificationsCommand(GitContext context, Repository repository) { + super(context, repository); + } + + private Modifications createModifications(TreeWalk treeWalk, RevCommit commit, RevWalk revWalk, String revision) + throws IOException, UnsupportedModificationTypeException { + treeWalk.reset(); + treeWalk.setRecursive(true); + if (commit.getParentCount() > 0) { + RevCommit parent = commit.getParent(0); + RevTree tree = parent.getTree(); + if ((tree == null) && (revWalk != null)) { + revWalk.parseHeaders(parent); + tree = parent.getTree(); + } + if (tree != null) { + treeWalk.addTree(tree); + } else { + log.trace("no parent tree at position 0 for commit {}", commit.getName()); + treeWalk.addTree(new EmptyTreeIterator()); + } + } else { + log.trace("no parent available for commit {}", commit.getName()); + treeWalk.addTree(new EmptyTreeIterator()); + } + treeWalk.addTree(commit.getTree()); + List entries = DiffEntry.scan(treeWalk); + Modifications modifications = new Modifications(); + for (DiffEntry e : entries) { + if (!e.getOldId().equals(e.getNewId())) { + appendModification(modifications, e); + } + } + modifications.setRevision(revision); + return modifications; + } + + @Override + public Modifications getModifications(String revision) { + org.eclipse.jgit.lib.Repository gitRepository = null; + RevWalk revWalk = null; + try { + gitRepository = open(); + if (!gitRepository.getAllRefs().isEmpty()) { + revWalk = new RevWalk(gitRepository); + ObjectId id = GitUtil.getRevisionId(gitRepository, revision); + RevCommit commit = revWalk.parseCommit(id); + TreeWalk treeWalk = new TreeWalk(gitRepository); + return createModifications(treeWalk, commit, revWalk, revision); + } + } catch (IOException ex) { + log.error("could not open repository", ex); + throw new InternalRepositoryException(ex); + + } catch (UnsupportedModificationTypeException ex) { + log.error("Unsupported modification type", ex); + throw new InternalRepositoryException(ex); + + } finally { + GitUtil.release(revWalk); + GitUtil.close(gitRepository); + } + return null; + } + + @Override + public Modifications getModifications(ModificationsCommandRequest request) { + return getModifications(request.getRevision()); + } + + private void appendModification(Modifications modifications, DiffEntry entry) throws UnsupportedModificationTypeException { + DiffEntry.ChangeType type = entry.getChangeType(); + if (type == DiffEntry.ChangeType.ADD) { + modifications.getAdded().add(entry.getNewPath()); + } else if (type == DiffEntry.ChangeType.MODIFY) { + modifications.getModified().add(entry.getNewPath()); + } else if (type == DiffEntry.ChangeType.DELETE) { + modifications.getRemoved().add(entry.getOldPath()); + } else { + throw new UnsupportedModificationTypeException(MessageFormat.format("The modification type: {0} is not supported.", type)); + } + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java index 7ea26de83f..29744a8e9b 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java @@ -36,17 +36,15 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.collect.ImmutableSet; - import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; -//~--- JDK imports ------------------------------------------------------------ - import java.io.IOException; - import java.util.Set; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -188,6 +186,11 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider return new GitLogCommand(context, repository); } + @Override + public ModificationsCommand getModificationsCommand() { + return new GitModificationsCommand(context,repository); + } + /** * Method description * diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/UnsupportedModificationTypeException.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/UnsupportedModificationTypeException.java new file mode 100644 index 0000000000..5081a29d21 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/UnsupportedModificationTypeException.java @@ -0,0 +1,9 @@ +package sonia.scm.repository.spi; + +import sonia.scm.repository.InternalRepositoryException; + +public class UnsupportedModificationTypeException extends InternalRepositoryException { + public UnsupportedModificationTypeException(String message) { + super(message); + } +} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java index e2a401bf7d..97e09c0708 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java @@ -85,14 +85,14 @@ public class AbstractRemoteCommandTestBase outgoingDirectory = tempFolder.newFile("outgoing"); outgoingDirectory.delete(); - incomgingRepository = new Repository("1", "git", "space", "incoming"); + incomingRepository = new Repository("1", "git", "space", "incoming"); outgoingRepository = new Repository("2", "git", "space", "outgoing"); incoming = Git.init().setDirectory(incomingDirectory).setBare(false).call(); outgoing = Git.init().setDirectory(outgoingDirectory).setBare(false).call(); handler = mock(GitRepositoryHandler.class); - when(handler.getDirectory(incomgingRepository)).thenReturn( + when(handler.getDirectory(incomingRepository)).thenReturn( incomingDirectory); when(handler.getDirectory(outgoingRepository)).thenReturn( outgoingDirectory); @@ -211,7 +211,7 @@ public class AbstractRemoteCommandTestBase protected GitRepositoryHandler handler; /** Field description */ - protected Repository incomgingRepository; + protected Repository incomingRepository; /** Field description */ protected Git incoming; diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java index 6aa852b12c..e3d36601e7 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java @@ -105,7 +105,7 @@ public class GitIncomingCommandTest commit(outgoing, "added a"); - GitPullCommand pull = new GitPullCommand(handler, new GitContext(incomingDirectory), incomgingRepository); + GitPullCommand pull = new GitPullCommand(handler, new GitContext(incomingDirectory), incomingRepository); PullCommandRequest req = new PullCommandRequest(); req.setRemoteRepository(outgoingRepository); pull.pull(req); @@ -192,6 +192,6 @@ public class GitIncomingCommandTest private GitIncomingCommand createCommand() { return new GitIncomingCommand(handler, new GitContext(incomingDirectory), - incomgingRepository); + incomingRepository); } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java index 51df1298e5..d6e6ac98d8 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java @@ -168,21 +168,23 @@ public class GitLogCommandTest extends AbstractGitCommandTestBase Changeset c = command.getChangeset("435df2f061add3589cb3"); assertNotNull(c); - assertEquals("435df2f061add3589cb326cc64be9b9c3897ceca", c.getId()); + String revision = "435df2f061add3589cb326cc64be9b9c3897ceca"; + assertEquals(revision, c.getId()); assertEquals("added a and b files", c.getDescription()); checkDate(c.getDate()); assertEquals("Douglas Adams", c.getAuthor().getName()); assertEquals("douglas.adams@hitchhiker.com", c.getAuthor().getMail()); assertEquals("added a and b files", c.getDescription()); - Modifications mods = c.getModifications(); + GitModificationsCommand gitModificationsCommand = new GitModificationsCommand(createContext(), repository); + Modifications modifications = gitModificationsCommand.getModifications(revision); - assertNotNull(mods); - assertTrue("modified list should be empty", mods.getModified().isEmpty()); - assertTrue("removed list should be empty", mods.getRemoved().isEmpty()); - assertFalse("added list should not be empty", mods.getAdded().isEmpty()); - assertEquals(2, mods.getAdded().size()); - assertThat(mods.getAdded(), contains("a.txt", "b.txt")); + assertNotNull(modifications); + assertTrue("modified list should be empty", modifications.getModified().isEmpty()); + assertTrue("removed list should be empty", modifications.getRemoved().isEmpty()); + assertFalse("added list should not be empty", modifications.getAdded().isEmpty()); + assertEquals(2, modifications.getAdded().size()); + assertThat(modifications.getAdded(), contains("a.txt", "b.txt")); } @Test diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java new file mode 100644 index 0000000000..de90d5a393 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java @@ -0,0 +1,126 @@ +package sonia.scm.repository.spi; + +import org.eclipse.jgit.revwalk.RevCommit; +import org.junit.Before; +import org.junit.Test; +import sonia.scm.repository.Modifications; + +import java.io.File; +import java.io.IOException; +import java.util.function.Consumer; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +public class GitModificationsCommandTest extends AbstractRemoteCommandTestBase { + + private GitModificationsCommand incomingModificationsCommand; + private GitModificationsCommand outgoingModificationsCommand; + + @Before + public void init() { + incomingModificationsCommand = new GitModificationsCommand(new GitContext(incomingDirectory), incomingRepository); + outgoingModificationsCommand = new GitModificationsCommand(new GitContext(outgoingDirectory), outgoingRepository); + } + + @Test + public void shouldReadAddedFiles() throws Exception { + write(outgoing, outgoingDirectory, "a.txt", "bal bla"); + RevCommit addedFileCommit = commit(outgoing, "add file"); + String revision = addedFileCommit.getName(); + Consumer assertModifications = assertAddedFiles("a.txt"); + assertModifications.accept(outgoingModificationsCommand.getModifications(revision)); + pushOutgoingAndPullIncoming(); + assertModifications.accept(incomingModificationsCommand.getModifications(revision)); + } + + @Test + public void shouldReadModifiedFiles() throws Exception { + write(outgoing, outgoingDirectory, "a.txt", "bal bla"); + commit(outgoing, "add file"); + write(outgoing, outgoingDirectory, "a.txt", "modified content"); + RevCommit modifiedFileCommit = commit(outgoing, "modify file"); + String revision = modifiedFileCommit.getName(); + Consumer assertModifications = assertModifiedFiles("a.txt"); + assertModifications.accept(outgoingModificationsCommand.getModifications(revision)); + pushOutgoingAndPullIncoming(); + assertModifications.accept(incomingModificationsCommand.getModifications(revision)); + } + + @Test + public void shouldReadRemovedFiles() throws Exception { + String fileName = "a.txt"; + write(outgoing, outgoingDirectory, fileName, "bal bla"); + commit(outgoing, "add file"); + File file = new File(outgoingDirectory, fileName); + file.delete(); + outgoing.add().setUpdate(true).addFilepattern(".").call(); + RevCommit removedFileCommit = commit(outgoing, "remove file"); + String revision = removedFileCommit.getName(); + Consumer assertModifications = assertRemovedFiles(fileName); + pushOutgoingAndPullIncoming(); + assertModifications.accept(incomingModificationsCommand.getModifications(revision)); + assertModifications.accept(outgoingModificationsCommand.getModifications(revision)); + } + + void pushOutgoingAndPullIncoming() throws IOException { + GitPushCommand cmd = new GitPushCommand(handler, new GitContext(outgoingDirectory), + outgoingRepository); + PushCommandRequest request = new PushCommandRequest(); + request.setRemoteRepository(incomingRepository); + cmd.push(request); + GitPullCommand pullCommand = new GitPullCommand(handler, new GitContext(incomingDirectory), + incomingRepository); + PullCommandRequest pullRequest = new PullCommandRequest(); + pullRequest.setRemoteRepository(incomingRepository); + pullCommand.pull(pullRequest); + } + + Consumer assertRemovedFiles(String fileName) { + return (modifications) -> { + assertThat(modifications).isNotNull(); + assertThat(modifications.getAdded()) + .as("added files modifications") + .hasSize(0); + assertThat(modifications.getModified()) + .as("modified files modifications") + .hasSize(0); + assertThat(modifications.getRemoved()) + .as("removed files modifications") + .hasSize(1) + .containsOnly(fileName); + }; + } + + + Consumer assertModifiedFiles(String file) { + return (modifications) -> { + assertThat(modifications).isNotNull(); + assertThat(modifications.getAdded()) + .as("added files modifications") + .hasSize(0); + assertThat(modifications.getModified()) + .as("modified files modifications") + .hasSize(1) + .containsOnly(file); + assertThat(modifications.getRemoved()) + .as("removed files modifications") + .hasSize(0); + }; + } + + Consumer assertAddedFiles(String file) { + return (modifications) -> { + assertThat(modifications).isNotNull(); + assertThat(modifications.getAdded()) + .as("added files modifications") + .hasSize(1) + .containsOnly(file); + assertThat(modifications.getModified()) + .as("modified files modifications") + .hasSize(0); + assertThat(modifications.getRemoved()) + .as("removed files modifications") + .hasSize(0); + }; + } +} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java index 58f70109ef..3510650fb4 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java @@ -78,7 +78,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase GitOutgoingCommand cmd = createCommand(); OutgoingCommandRequest request = new OutgoingCommandRequest(); - request.setRemoteRepository(incomgingRepository); + request.setRemoteRepository(incomingRepository); ChangesetPagingResult cpr = cmd.getOutgoingChangesets(request); @@ -98,7 +98,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase * @throws RepositoryException */ @Test - public void testGetOutgoingChangesetsWithAllreadyPushedChanges() + public void testGetOutgoingChangesetsWithAlreadyPushedChanges() throws IOException, GitAPIException { write(outgoing, outgoingDirectory, "a.txt", "content of a.txt"); @@ -110,7 +110,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase outgoingRepository); PushCommandRequest req = new PushCommandRequest(); - req.setRemoteRepository(incomgingRepository); + req.setRemoteRepository(incomingRepository); push.push(req); write(outgoing, outgoingDirectory, "b.txt", "content of b.txt"); @@ -120,7 +120,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase GitOutgoingCommand cmd = createCommand(); OutgoingCommandRequest request = new OutgoingCommandRequest(); - request.setRemoteRepository(incomgingRepository); + request.setRemoteRepository(incomingRepository); ChangesetPagingResult cpr = cmd.getOutgoingChangesets(request); @@ -144,7 +144,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase GitOutgoingCommand cmd = createCommand(); OutgoingCommandRequest request = new OutgoingCommandRequest(); - request.setRemoteRepository(incomgingRepository); + request.setRemoteRepository(incomingRepository); ChangesetPagingResult cpr = cmd.getOutgoingChangesets(request); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java index 91fad57880..4f3d7e933d 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java @@ -78,7 +78,7 @@ public class GitPushCommandTest extends AbstractRemoteCommandTestBase GitPushCommand cmd = createCommand(); PushCommandRequest request = new PushCommandRequest(); - request.setRemoteRepository(incomgingRepository); + request.setRemoteRepository(incomingRepository); PushResponse response = cmd.push(request); diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModificationsCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModificationsCommand.java new file mode 100644 index 0000000000..c67b9ff5d9 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModificationsCommand.java @@ -0,0 +1,32 @@ +package sonia.scm.repository.spi; + +import sonia.scm.repository.Modifications; +import sonia.scm.repository.Repository; +import sonia.scm.repository.spi.javahg.HgLogChangesetCommand; + +import java.text.MessageFormat; + +public class HgModificationsCommand extends AbstractCommand implements ModificationsCommand { + + HgModificationsCommand(HgCommandContext context, Repository repository) { + super(context, repository); + } + + + @Override + public Modifications getModifications(String revision) { + com.aragost.javahg.Repository repository = open(); + HgLogChangesetCommand hgLogChangesetCommand = HgLogChangesetCommand.on(repository, getContext().getConfig()); + int hgRevision = hgLogChangesetCommand.rev(revision).singleRevision(); + Modifications modifications = hgLogChangesetCommand.rev(MessageFormat.format("{0}:{0}", hgRevision)).extractModifications(); + modifications.setRevision(revision); + return modifications; + } + + @Override + public Modifications getModifications(ModificationsCommandRequest request) { + return getModifications(request.getRevision()); + } + + +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/AbstractChangesetCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/AbstractChangesetCommand.java index 827f86ded1..6466eb6d11 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/AbstractChangesetCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/AbstractChangesetCommand.java @@ -41,21 +41,18 @@ import com.aragost.javahg.internals.AbstractCommand; import com.aragost.javahg.internals.HgInputStream; import com.aragost.javahg.internals.RuntimeIOException; import com.aragost.javahg.internals.Utils; - import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; - import sonia.scm.repository.Changeset; import sonia.scm.repository.HgConfig; import sonia.scm.repository.Modifications; import sonia.scm.repository.Person; -//~--- JDK imports ------------------------------------------------------------ - import java.io.IOException; - import java.util.List; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -251,33 +248,14 @@ public abstract class AbstractChangesetCommand extends AbstractCommand changeset.getProperties().put(PROPERTY_CLOSE, "true"); } - Modifications modifications = changeset.getModifications(); - String line = in.textUpTo('\n'); - - while (line.length() > 0) - { - - if (line.startsWith("a ")) - { - modifications.getAdded().add(line.substring(2)); - } - else if (line.startsWith("m ")) - { - modifications.getModified().add(line.substring(2)); - } - else if (line.startsWith("d ")) - { - modifications.getRemoved().add(line.substring(2)); - } - else if (line.startsWith("t ")) + while (line.length() > 0) { + if (line.startsWith("t ")) { changeset.getTags().add(line.substring(2)); } - line = in.textUpTo('\n'); } - String message = in.textUpTo('\0'); changeset.setDescription(message); @@ -285,6 +263,36 @@ public abstract class AbstractChangesetCommand extends AbstractCommand return changeset; } + protected Modifications readModificationsFromStream(HgInputStream in) { + try { + boolean found = in.find(CHANGESET_PATTERN); + if (found) { + while (!in.match(CHANGESET_PATTERN)) { + return extractModifications(in); + } + } + } catch (IOException e) { + throw new RuntimeIOException(e); + } + return null; + } + + private Modifications extractModifications(HgInputStream in) throws IOException { + Modifications modifications = new Modifications(); + String line = in.textUpTo('\n'); + while (line.length() > 0) { + if (line.startsWith("a ")) { + modifications.getAdded().add(line.substring(2)); + } else if (line.startsWith("m ")) { + modifications.getModified().add(line.substring(2)); + } else if (line.startsWith("d ")) { + modifications.getRemoved().add(line.substring(2)); + } + line = in.textUpTo('\n'); + } + return modifications; + } + /** * Method description * diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/HgLogChangesetCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/HgLogChangesetCommand.java index 4c62fb4f93..f57c2a63d9 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/HgLogChangesetCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/HgLogChangesetCommand.java @@ -38,14 +38,14 @@ package sonia.scm.repository.spi.javahg; import com.aragost.javahg.Repository; import com.aragost.javahg.internals.HgInputStream; import com.aragost.javahg.internals.Utils; - import sonia.scm.repository.Changeset; import sonia.scm.repository.HgConfig; - -//~--- JDK imports ------------------------------------------------------------ +import sonia.scm.repository.Modifications; import java.util.List; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -106,11 +106,22 @@ public class HgLogChangesetCommand extends AbstractChangesetCommand */ public List execute(String... files) { - cmdAppend("--style", CHANGESET_EAGER_STYLE_PATH); + return readListFromStream(getHgInputStream(files, CHANGESET_EAGER_STYLE_PATH)); + } - HgInputStream stream = launchStream(files); + /** + * Extract Modifications from the Repository files + * + * @param files repo files + * @return modifications + */ + public Modifications extractModifications(String... files) { + return readModificationsFromStream(getHgInputStream(files, CHANGESET_EAGER_STYLE_PATH)); + } - return readListFromStream(stream); + HgInputStream getHgInputStream(String[] files, String changesetStylePath) { + cmdAppend("--style", changesetStylePath); + return launchStream(files); } /** @@ -138,11 +149,7 @@ public class HgLogChangesetCommand extends AbstractChangesetCommand */ public List loadRevisions(String... files) { - cmdAppend("--style", CHANGESET_LAZY_STYLE_PATH); - - HgInputStream stream = launchStream(files); - - return loadRevisionsFromStream(stream); + return loadRevisionsFromStream(getHgInputStream(files, CHANGESET_LAZY_STYLE_PATH)); } /** diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgCommitCommand.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgCommitCommand.java index aa611a8ba4..b8967ed15b 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgCommitCommand.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgCommitCommand.java @@ -32,11 +32,11 @@ package sonia.scm.repository.client.spi; import com.aragost.javahg.Repository; import com.google.common.collect.Lists; -import java.io.IOException; import sonia.scm.repository.Changeset; -import sonia.scm.repository.Modifications; import sonia.scm.repository.Person; +import java.io.IOException; + /** * Mercurial implementation of the {@link CommitCommand}. * @@ -70,9 +70,6 @@ public class HgCommitCommand implements CommitCommand changeset.setBranches(Lists.newArrayList(c.getBranch())); changeset.setTags(c.tags()); - changeset.setModifications( - new Modifications(c.getAddedFiles(), c.getModifiedFiles(), c.getDeletedFiles()) - ); return changeset; } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgLogCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgLogCommandTest.java index c4d49ba8b5..99e9fc191a 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgLogCommandTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgLogCommandTest.java @@ -39,6 +39,9 @@ import org.junit.Test; import sonia.scm.repository.Changeset; import sonia.scm.repository.ChangesetPagingResult; import sonia.scm.repository.Modifications; +import sonia.scm.repository.RevisionNotFoundException; + +import java.io.IOException; import static org.hamcrest.Matchers.contains; import static org.junit.Assert.assertEquals; @@ -133,27 +136,28 @@ public class HgLogCommandTest extends AbstractHgCommandTestBase } @Test - public void testGetCommit() { + public void testGetCommit() throws IOException, RevisionNotFoundException { HgLogCommand command = createComamnd(); + String revision = "a9bacaf1b7fa0cebfca71fed4e59ed69a6319427"; Changeset c = - command.getChangeset("a9bacaf1b7fa0cebfca71fed4e59ed69a6319427"); + command.getChangeset(revision); assertNotNull(c); - assertEquals("a9bacaf1b7fa0cebfca71fed4e59ed69a6319427", c.getId()); + assertEquals(revision, c.getId()); assertEquals("added a and b files", c.getDescription()); checkDate(c.getDate()); assertEquals("Douglas Adams", c.getAuthor().getName()); assertEquals("douglas.adams@hitchhiker.com", c.getAuthor().getMail()); assertEquals("added a and b files", c.getDescription()); + ModificationsCommand modificationsCommand = new HgModificationsCommand(cmdContext, repository); + Modifications modifications = modificationsCommand.getModifications(revision); - Modifications mods = c.getModifications(); - - assertNotNull(mods); - assertTrue("modified list should be empty", mods.getModified().isEmpty()); - assertTrue("removed list should be empty", mods.getRemoved().isEmpty()); - assertFalse("added list should not be empty", mods.getAdded().isEmpty()); - assertEquals(2, mods.getAdded().size()); - assertThat(mods.getAdded(), contains("a.txt", "b.txt")); + assertNotNull(modifications); + assertTrue("modified list should be empty", modifications.getModified().isEmpty()); + assertTrue("removed list should be empty", modifications.getRemoved().isEmpty()); + assertFalse("added list should not be empty", modifications.getAdded().isEmpty()); + assertEquals(2, modifications.getAdded().size()); + assertThat(modifications.getAdded(), contains("a.txt", "b.txt")); } @Test diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModificationsCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModificationsCommandTest.java new file mode 100644 index 0000000000..eae8319b89 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModificationsCommandTest.java @@ -0,0 +1,111 @@ +package sonia.scm.repository.spi; + +import com.aragost.javahg.Changeset; +import com.aragost.javahg.commands.RemoveCommand; +import org.junit.Before; +import org.junit.Test; +import sonia.scm.repository.HgTestUtil; +import sonia.scm.repository.Modifications; + +import java.io.File; +import java.util.function.Consumer; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +public class HgModificationsCommandTest extends IncomingOutgoingTestBase { + + + private HgModificationsCommand outgoingModificationsCommand; + + @Before + public void init() { + HgCommandContext outgoingContext = new HgCommandContext(HgTestUtil.createHookManager(), handler, outgoingRepository, outgoingDirectory); + outgoingModificationsCommand = new HgModificationsCommand(outgoingContext, outgoingRepository); + } + + @Test + public void shouldReadAddedFiles() throws Exception { + String fileName = "a.txt"; + writeNewFile(outgoing, outgoingDirectory, fileName, "bal bla"); + Changeset changeset = commit(outgoing, "added a.txt"); + String revision = String.valueOf(changeset.getRevision()); + Consumer assertModifications = assertAddedFile(fileName); + assertModifications.accept(outgoingModificationsCommand.getModifications(revision)); + } + + @Test + public void shouldReadModifiedFiles() throws Exception { + String fileName = "a.txt"; + writeNewFile(outgoing, outgoingDirectory, fileName, "bal bla"); + commit(outgoing, "added a.txt"); + writeNewFile(outgoing, outgoingDirectory, fileName, "new content"); + Changeset changeset = commit(outgoing, "modified a.txt"); + String revision = String.valueOf(changeset.getRevision()); + Consumer assertModifications = assertModifiedFiles(fileName); + assertModifications.accept(outgoingModificationsCommand.getModifications(revision)); + } + + @Test + public void shouldReadRemovedFiles() throws Exception { + String fileName = "a.txt"; + writeNewFile(outgoing, outgoingDirectory, fileName, "bal bla"); + commit(outgoing, "added a.txt"); + File file = new File(outgoingDirectory, fileName); + file.delete(); + RemoveCommand.on(outgoing).execute(file); + Changeset changeset = commit(outgoing, "removed a.txt"); + String revision = String.valueOf(changeset.getRevision()); + Consumer assertModifications = assertRemovedFiles(fileName); + assertModifications.accept(outgoingModificationsCommand.getModifications(revision)); + } + + + Consumer assertRemovedFiles(String fileName) { + return (modifications) -> { + assertThat(modifications).isNotNull(); + assertThat(modifications.getAdded()) + .as("added files modifications") + .hasSize(0); + assertThat(modifications.getModified()) + .as("modified files modifications") + .hasSize(0); + assertThat(modifications.getRemoved()) + .as("removed files modifications") + .hasSize(1) + .containsOnly(fileName); + }; + } + + + Consumer assertModifiedFiles(String file) { + return (modifications) -> { + assertThat(modifications).isNotNull(); + assertThat(modifications.getAdded()) + .as("added files modifications") + .hasSize(0); + assertThat(modifications.getModified()) + .as("modified files modifications") + .hasSize(1) + .containsOnly(file); + assertThat(modifications.getRemoved()) + .as("removed files modifications") + .hasSize(0); + }; + } + + Consumer assertAddedFile(String addedFile) { + return (modifications) -> { + assertThat(modifications).isNotNull(); + assertThat(modifications.getAdded()) + .as("added files modifications") + .hasSize(1) + .containsOnly(addedFile); + assertThat(modifications.getModified()) + .as("modified files modifications") + .hasSize(0); + assertThat(modifications.getRemoved()) + .as("removed files modifications") + .hasSize(0); + }; + } +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java index eb613e6144..480026c27a 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java @@ -49,7 +49,6 @@ import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil; import org.tmatesoft.svn.core.internal.util.SVNXMLUtil; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.wc.SVNClientManager; -import org.tmatesoft.svn.core.wc.admin.SVNChangeEntry; import sonia.scm.util.HttpUtil; import sonia.scm.util.Util; @@ -103,30 +102,37 @@ public final class SvnUtil //~--- methods -------------------------------------------------------------- - /** - * TODO: type replaced - * - * - * @param modifications - * @param entry - */ - public static void appendModification(Modifications modifications, - SVNLogEntryPath entry) - { - appendModification(modifications, entry.getType(), entry.getPath()); + public static long parseRevision(String v) throws RevisionNotFoundException { + long result = -1l; + + if (!Strings.isNullOrEmpty(v)) + { + try + { + result = Long.parseLong(v); + } + catch (NumberFormatException ex) + { + throw new RevisionNotFoundException(v); + } + } + + return result; } - /** - * Method description - * - * - * @param modifications - * @param entry - */ - public static void appendModification(Modifications modifications, - SVNChangeEntry entry) - { - appendModification(modifications, entry.getType(), entry.getPath()); + + public static Modifications createModifications(SVNLogEntry entry, String revision) { + Modifications modifications = new Modifications(); + modifications.setRevision(revision); + Map changeMap = entry.getChangedPaths(); + + if (Util.isNotEmpty(changeMap)) { + + for (SVNLogEntryPath e : changeMap.values()) { + appendModification(modifications, e.getType(), e.getPath()); + } + } + return modifications; } /** @@ -210,19 +216,6 @@ public final class SvnUtil { changeset.getParents().add(String.valueOf(revision - 1)); } - - Map changeMap = entry.getChangedPaths(); - - if (Util.isNotEmpty(changeMap)) - { - Modifications modifications = changeset.getModifications(); - - for (SVNLogEntryPath e : changeMap.values()) - { - appendModification(modifications, e); - } - } - return changeset; } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnLogCommand.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnLogCommand.java index ededb4e1f0..332dcb55a6 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnLogCommand.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnLogCommand.java @@ -54,6 +54,8 @@ import sonia.scm.util.Util; import java.util.Collection; import java.util.List; +import static sonia.scm.repository.SvnUtil.parseRevision; + //~--- JDK imports ------------------------------------------------------------ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand @@ -144,25 +146,6 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand return changesets; } - //~--- methods -------------------------------------------------------------- - - private long parseRevision(String v) throws RevisionNotFoundException { - long result = -1l; - - if (!Strings.isNullOrEmpty(v)) - { - try - { - result = Long.parseLong(v); - } - catch (NumberFormatException ex) - { - throw new RevisionNotFoundException(v); - } - } - - return result; - } //~--- get methods ---------------------------------------------------------- diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnModificationsCommand.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnModificationsCommand.java new file mode 100644 index 0000000000..e6cedc8ebf --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnModificationsCommand.java @@ -0,0 +1,50 @@ +package sonia.scm.repository.spi; + +import lombok.extern.slf4j.Slf4j; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNLogEntry; +import org.tmatesoft.svn.core.io.SVNRepository; +import sonia.scm.repository.InternalRepositoryException; +import sonia.scm.repository.Modifications; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RevisionNotFoundException; +import sonia.scm.repository.SvnUtil; +import sonia.scm.util.Util; + +import java.io.IOException; +import java.util.Collection; + +@Slf4j +public class SvnModificationsCommand extends AbstractSvnCommand implements ModificationsCommand { + + SvnModificationsCommand(SvnContext context, Repository repository) { + super(context, repository); + } + + + @Override + @SuppressWarnings("unchecked") + public Modifications getModifications(String revision) throws IOException, RevisionNotFoundException { + Modifications modifications = null; + log.debug("get modifications {}", revision); + try { + long revisionNumber = SvnUtil.parseRevision(revision); + SVNRepository repo = open(); + Collection entries = repo.log(null, null, revisionNumber, + revisionNumber, true, true); + if (Util.isNotEmpty(entries)) { + modifications = SvnUtil.createModifications(entries.iterator().next(), revision); + } + } catch (SVNException ex) { + throw new InternalRepositoryException("could not open repository", ex); + } + return modifications; + } + + @Override + public Modifications getModifications(ModificationsCommandRequest request) throws IOException, RevisionNotFoundException { + return getModifications(request.getRevision()); + } + + +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnPreReceiveHookChangesetProvier.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnPreReceiveHookChangesetProvier.java index 93fb88f841..e4efdb71ab 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnPreReceiveHookChangesetProvier.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnPreReceiveHookChangesetProvier.java @@ -37,22 +37,19 @@ package sonia.scm.repository.spi; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.tmatesoft.svn.core.SVNLogEntry; import org.tmatesoft.svn.core.wc.ISVNOptions; import org.tmatesoft.svn.core.wc.SVNClientManager; import org.tmatesoft.svn.core.wc.SVNWCUtil; import org.tmatesoft.svn.core.wc.admin.SVNLookClient; - import sonia.scm.repository.Changeset; import sonia.scm.repository.RepositoryHookType; -import sonia.scm.repository.SvnModificationHandler; import sonia.scm.repository.SvnUtil; -//~--- JDK imports ------------------------------------------------------------ - import java.io.File; +//~--- JDK imports ------------------------------------------------------------ + /** * * @author Sebastian Sdorra @@ -123,10 +120,6 @@ public class SvnPreReceiveHookChangesetProvier { changeset = SvnUtil.createChangeset(entry); changeset.setId(SvnUtil.createTransactionEntryId(transaction)); - - clientManager.doGetChanged(repositoryDirectory, transaction, - new SvnModificationHandler(changeset), true); - } else if (logger.isWarnEnabled()) { diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnLogCommandTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnLogCommandTest.java index 941687190c..a55138f151 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnLogCommandTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnLogCommandTest.java @@ -40,6 +40,8 @@ import sonia.scm.repository.ChangesetPagingResult; import sonia.scm.repository.Modifications; import sonia.scm.repository.RevisionNotFoundException; +import java.io.IOException; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -128,7 +130,7 @@ public class SvnLogCommandTest extends AbstractSvnCommandTestBase } @Test - public void testGetCommit() throws RevisionNotFoundException { + public void testGetCommit() throws RevisionNotFoundException, IOException { Changeset c = createCommand().getChangeset("3"); assertNotNull(c); @@ -137,15 +139,15 @@ public class SvnLogCommandTest extends AbstractSvnCommandTestBase checkDate(c.getDate()); assertEquals("perfect", c.getAuthor().getName()); assertNull("douglas.adams@hitchhiker.com", c.getAuthor().getMail()); + SvnModificationsCommand modificationsCommand = new SvnModificationsCommand(createContext(), repository); + Modifications modifications = modificationsCommand.getModifications("3"); - Modifications mods = c.getModifications(); - - assertNotNull(mods); - assertEquals(1, mods.getModified().size()); - assertEquals(1, mods.getRemoved().size()); - assertTrue("added list should be empty", mods.getAdded().isEmpty()); - assertEquals("a.txt", mods.getModified().get(0)); - assertEquals("b.txt", mods.getRemoved().get(0)); + assertNotNull(modifications); + assertEquals(1, modifications.getModified().size()); + assertEquals(1, modifications.getRemoved().size()); + assertTrue("added list should be empty", modifications.getAdded().isEmpty()); + assertEquals("a.txt", modifications.getModified().get(0)); + assertEquals("b.txt", modifications.getRemoved().get(0)); } @Test diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/IllegalArgumentExceptionMapper.java b/scm-webapp/src/main/java/sonia/scm/api/rest/IllegalArgumentExceptionMapper.java index 4a8a5854f0..44d4d9194d 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/IllegalArgumentExceptionMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/IllegalArgumentExceptionMapper.java @@ -45,7 +45,8 @@ import javax.ws.rs.ext.Provider; * @author Sebastian Sdorra * @since 1.36 */ -@Provider @Slf4j +@Provider +@Slf4j public class IllegalArgumentExceptionMapper implements ExceptionMapper { diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java index f047e3bbaa..aa71e6bced 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java @@ -65,7 +65,8 @@ public abstract class ChangesetToChangesetDtoMapper extends BaseMapper { + + public InternalRepositoryExceptionMapper() { + super(InternalRepositoryException.class, Response.Status.INTERNAL_SERVER_ERROR); + } +} 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 9cadbfb6ff..bebd7def23 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 @@ -34,6 +34,7 @@ public class MapperModule extends AbstractModule { bind(TagToTagDtoMapper.class).to(Mappers.getMapper(TagToTagDtoMapper.class).getClass()); bind(FileObjectToFileObjectDtoMapper.class).to(Mappers.getMapper(FileObjectToFileObjectDtoMapper.class).getClass()); + bind(ModificationsToDtoMapper.class).to(Mappers.getMapper(ModificationsToDtoMapper.class).getClass()); // no mapstruct required bind(UIPluginDtoMapper.class); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsDto.java new file mode 100644 index 0000000000..a6b1c84f1a --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsDto.java @@ -0,0 +1,45 @@ +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; + +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +public class ModificationsDto extends HalRepresentation { + + + private String revision; + /** + * list of added files + */ + private List added; + + /** + * list of modified files + */ + private List modified; + + /** + * list of removed files + */ + private List removed; + + @Override + @SuppressWarnings("squid:S1185") // We want to have this method available in this package + protected HalRepresentation add(Links links) { + return super.add(links); + } + + @SuppressWarnings("squid:S1185") // We want to have this method available in this package + protected HalRepresentation withEmbedded(String rel, List halRepresentations) { + return super.withEmbedded(rel, halRepresentations); + } + + +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsRootResource.java new file mode 100644 index 0000000000..f30163dac2 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsRootResource.java @@ -0,0 +1,70 @@ +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.repository.InternalRepositoryException; +import sonia.scm.repository.Modifications; +import sonia.scm.repository.NamespaceAndName; +import sonia.scm.repository.RepositoryNotFoundException; +import sonia.scm.repository.RevisionNotFoundException; +import sonia.scm.repository.api.RepositoryService; +import sonia.scm.repository.api.RepositoryServiceFactory; +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.io.IOException; + +public class ModificationsRootResource { + + private final RepositoryServiceFactory serviceFactory; + private final ModificationsToDtoMapper modificationsToDtoMapper; + + @Inject + public ModificationsRootResource(RepositoryServiceFactory serviceFactory, ModificationsToDtoMapper modificationsToDtoMapper) { + this.serviceFactory = serviceFactory; + this.modificationsToDtoMapper = modificationsToDtoMapper; + } + + /** + * Get the file modifications related to a revision. + * file modifications are for example: Modified, Added or Removed. + * + * @param namespace + * @param name + * @param revision + * @return + * @throws IOException + * @throws RevisionNotFoundException + * @throws RepositoryNotFoundException + */ + @GET + @StatusCodes({ + @ResponseCode(code = 200, condition = "success"), + @ResponseCode(code = 401, condition = "not authenticated / invalid credentials"), + @ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the changeset"), + @ResponseCode(code = 404, condition = "not found, no changeset with the specified id is available in the repository"), + @ResponseCode(code = 500, condition = "internal server error") + }) + @Produces(VndMediaType.MODIFICATIONS) + @TypeHint(ModificationsDto.class) + @Path("{revision}") + public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision) throws IOException, RevisionNotFoundException, RepositoryNotFoundException , InternalRepositoryException { + try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) { + Modifications modifications = repositoryService.getModificationsCommand() + .revision(revision) + .getModifications(); + ModificationsDto output = modificationsToDtoMapper.map(modifications, repositoryService.getRepository()); + if (modifications != null ) { + return Response.ok(output).build(); + } else { + return Response.status(Response.Status.NOT_FOUND).build(); + } + } + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsToDtoMapper.java new file mode 100644 index 0000000000..19242b7ea6 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsToDtoMapper.java @@ -0,0 +1,31 @@ +package sonia.scm.api.v2.resources; + +import de.otto.edison.hal.Links; +import org.mapstruct.AfterMapping; +import org.mapstruct.Context; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import sonia.scm.repository.Modifications; +import sonia.scm.repository.Repository; + +import javax.inject.Inject; + +import static de.otto.edison.hal.Links.linkingTo; + +@Mapper +public abstract class ModificationsToDtoMapper extends BaseMapper { + + @Inject + private ResourceLinks resourceLinks; + + @Mapping(target = "attributes", ignore = true) // We do not map HAL attributes + public abstract ModificationsDto map(Modifications modifications, @Context Repository repository); + + @AfterMapping + void appendLinks(@MappingTarget ModificationsDto target, @Context Repository repository) { + Links.Builder linksBuilder = linkingTo() + .self(resourceLinks.modifications().self(repository.getNamespace(), repository.getName(), target.getRevision())); + target.add(linksBuilder.build()); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java index c47fc4f3d1..6208fa32bf 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java @@ -40,6 +40,7 @@ public class RepositoryResource { private final Provider contentResource; private final Provider permissionRootResource; private final Provider diffRootResource; + private final Provider modificationsRootResource; @Inject public RepositoryResource( @@ -50,7 +51,7 @@ public class RepositoryResource { Provider changesetRootResource, Provider sourceRootResource, Provider contentResource, Provider permissionRootResource, - Provider diffRootResource) { + Provider diffRootResource, Provider modificationsRootResource) { this.dtoToRepositoryMapper = dtoToRepositoryMapper; this.manager = manager; this.repositoryToDtoMapper = repositoryToDtoMapper; @@ -62,6 +63,7 @@ public class RepositoryResource { this.contentResource = contentResource; this.permissionRootResource = permissionRootResource; this.diffRootResource = diffRootResource; + this.modificationsRootResource = modificationsRootResource; } /** @@ -180,6 +182,9 @@ public class RepositoryResource { return permissionRootResource.get(); } + @Path("modifications/") + public ModificationsRootResource modifications() {return modificationsRootResource.get(); } + private Optional handleNotArchived(Throwable throwable) { if (throwable instanceof RepositoryIsNotArchivedException) { return Optional.of(Response.status(Response.Status.PRECONDITION_FAILED).build()); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java index f72e9fdd6d..e406c7a17c 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java @@ -307,6 +307,21 @@ class ResourceLinks { } } + public ModificationsLinks modifications() { + return new ModificationsLinks(uriInfoStore.get()); + } + + static class ModificationsLinks { + private final LinkBuilder modificationsLinkBuilder; + + ModificationsLinks(UriInfo uriInfo) { + modificationsLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, ModificationsRootResource.class); + } + String self(String namespace, String name, String revision) { + return modificationsLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("modifications").parameters().method("get").parameters(revision).href(); + } + } + public SourceLinks source() { return new SourceLinks(uriInfoStore.get()); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java index e23d3dc39b..0a209e905f 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java @@ -92,7 +92,7 @@ public class BranchRootResourceTest { changesetCollectionToDtoMapper = new ChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks); BranchCollectionToDtoMapper branchCollectionToDtoMapper = new BranchCollectionToDtoMapper(branchToDtoMapper, resourceLinks); branchRootResource = new BranchRootResource(serviceFactory, branchToDtoMapper, branchCollectionToDtoMapper, changesetCollectionToDtoMapper); - RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(new RepositoryResource(null, null, null, null, MockProvider.of(branchRootResource), null, null, null, null, null)), null); + RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(new RepositoryResource(null, null, null, null, MockProvider.of(branchRootResource), null, null, null, null, null, null)), null); dispatcher.getRegistry().addSingletonResource(repositoryRootResource); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java index 40aa61852a..4ea08b4102 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java @@ -81,7 +81,7 @@ public class ChangesetRootResourceTest { changesetRootResource = new ChangesetRootResource(serviceFactory, changesetCollectionToDtoMapper, changesetToChangesetDtoMapper); RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider .of(new RepositoryResource(null, null, null, null, null, - MockProvider.of(changesetRootResource), null, null, null, null)), null); + MockProvider.of(changesetRootResource), null, null, null, null, null)), null); dispatcher.getRegistry().addSingletonResource(repositoryRootResource); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService); when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java new file mode 100644 index 0000000000..a93543bb2c --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java @@ -0,0 +1,151 @@ +package sonia.scm.api.v2.resources; + +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.subject.support.SubjectThreadState; +import org.apache.shiro.util.ThreadContext; +import org.apache.shiro.util.ThreadState; +import org.assertj.core.util.Lists; +import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.mock.MockDispatcherFactory; +import org.jboss.resteasy.mock.MockHttpRequest; +import org.jboss.resteasy.mock.MockHttpResponse; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import sonia.scm.api.rest.AuthorizationExceptionMapper; +import sonia.scm.repository.InternalRepositoryException; +import sonia.scm.repository.Modifications; +import sonia.scm.repository.NamespaceAndName; +import sonia.scm.repository.Repository; +import sonia.scm.repository.api.ModificationsCommandBuilder; +import sonia.scm.repository.api.RepositoryService; +import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.web.VndMediaType; + +import java.net.URI; +import java.text.MessageFormat; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@Slf4j +@RunWith(MockitoJUnitRunner.Silent.class) +public class ModificationsResourceTest { + + + public static final String MODIFICATIONS_PATH = "space/repo/modifications/"; + public static final String MODIFICATIONS_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + MODIFICATIONS_PATH; + private final Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + + private final URI baseUri = URI.create("/"); + private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); + + @Mock + private RepositoryServiceFactory serviceFactory; + + @Mock + private RepositoryService repositoryService; + + @Mock + private ModificationsCommandBuilder modificationsCommandBuilder; + + @InjectMocks + private ModificationsToDtoMapperImpl modificationsToDtoMapper; + + private ModificationsRootResource modificationsRootResource; + + + private final Subject subject = mock(Subject.class); + private final ThreadState subjectThreadState = new SubjectThreadState(subject); + + + @Before + public void prepareEnvironment() throws Exception { + modificationsRootResource = new ModificationsRootResource(serviceFactory, modificationsToDtoMapper); + RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider + .of(new RepositoryResource(null, null, null, null, null, + null, null, null, null, null, MockProvider.of(modificationsRootResource))), null); + dispatcher.getRegistry().addSingletonResource(repositoryRootResource); + when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService); + when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService); + when(repositoryService.getRepository()).thenReturn(new Repository("repoId", "git", "space", "repo")); + dispatcher.getProviderFactory().registerProvider(NotFoundExceptionMapper.class); + dispatcher.getProviderFactory().registerProvider(AuthorizationExceptionMapper.class); + dispatcher.getProviderFactory().registerProvider(InternalRepositoryExceptionMapper.class); + when(repositoryService.getModificationsCommand()).thenReturn(modificationsCommandBuilder); + subjectThreadState.bind(); + ThreadContext.bind(subject); + when(subject.isPermitted(any(String.class))).thenReturn(true); + } + + @After + public void cleanupContext() { + ThreadContext.unbindSubject(); + } + + @Test + public void shouldGet404OnMissingModifications() throws Exception { + when(modificationsCommandBuilder.revision(any())).thenReturn(modificationsCommandBuilder); + when(modificationsCommandBuilder.getModifications()).thenReturn(null); + + MockHttpRequest request = MockHttpRequest + .get(MODIFICATIONS_URL + "not_existing_revision") + .accept(VndMediaType.MODIFICATIONS); + MockHttpResponse response = new MockHttpResponse(); + dispatcher.invoke(request, response); + assertEquals(404, response.getStatus()); + } + + @Test + public void shouldGet500OnModificationsCommandError() throws Exception { + when(modificationsCommandBuilder.revision(any())).thenReturn(modificationsCommandBuilder); + when(modificationsCommandBuilder.getModifications()).thenThrow(InternalRepositoryException.class); + + MockHttpRequest request = MockHttpRequest + .get(MODIFICATIONS_URL + "revision") + .accept(VndMediaType.MODIFICATIONS); + MockHttpResponse response = new MockHttpResponse(); + dispatcher.invoke(request, response); + assertEquals(500, response.getStatus()); + } + + + @Test + public void shouldGetModifications() throws Exception { + Modifications modifications = new Modifications(); + String revision = "revision"; + String addedFile_1 = "a.txt"; + String addedFile_2 = "b.txt"; + String modifiedFile_1 = "d.txt"; + String modifiedFile_2 = "c.txt"; + String removedFile_1 = "e.txt"; + String removedFile_2 = "f.txt"; + modifications.setRevision(revision); + modifications.setAdded(Lists.newArrayList(addedFile_1, addedFile_2)); + modifications.setModified(Lists.newArrayList(modifiedFile_1, modifiedFile_2)); + modifications.setRemoved(Lists.newArrayList(removedFile_1, removedFile_2)); + when(modificationsCommandBuilder.getModifications()).thenReturn(modifications); + when(modificationsCommandBuilder.revision(eq(revision))).thenReturn(modificationsCommandBuilder); + + MockHttpRequest request = MockHttpRequest + .get(MODIFICATIONS_URL + revision) + .accept(VndMediaType.MODIFICATIONS); + MockHttpResponse response = new MockHttpResponse(); + dispatcher.invoke(request, response); + assertEquals(200, response.getStatus()); + log.info("the content: ", response.getContentAsString()); + assertTrue(response.getContentAsString().contains(String.format("\"revision\":\"%s\"", revision))); + assertTrue(response.getContentAsString().contains(MessageFormat.format("\"added\":[\"{0}\",\"{1}\"]", addedFile_1, addedFile_2))); + assertTrue(response.getContentAsString().contains(MessageFormat.format("\"modified\":[\"{0}\",\"{1}\"]", modifiedFile_1, modifiedFile_2))); + assertTrue(response.getContentAsString().contains(MessageFormat.format("\"removed\":[\"{0}\",\"{1}\"]", removedFile_1, removedFile_2))); + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java index 8d05c1f455..3f2ea9b317 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java @@ -138,7 +138,7 @@ public class PermissionRootResourceTest { permissionCollectionToDtoMapper = new PermissionCollectionToDtoMapper(permissionToPermissionDtoMapper, resourceLinks); permissionRootResource = new PermissionRootResource(permissionDtoToPermissionMapper, permissionToPermissionDtoMapper, permissionCollectionToDtoMapper, resourceLinks, repositoryManager); RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider - .of(new RepositoryResource(null, null, null, null, null, null, null, null, MockProvider.of(permissionRootResource), null)), null); + .of(new RepositoryResource(null, null, null, null, null, null, null, null, MockProvider.of(permissionRootResource), null, null)), null); dispatcher = createDispatcher(repositoryRootResource); subjectThreadState.bind(); ThreadContext.bind(subject); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index 539d469445..48ca62089f 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -79,7 +79,7 @@ public class RepositoryRootResourceTest { @Before public void prepareEnvironment() { initMocks(this); - RepositoryResource repositoryResource = new RepositoryResource(repositoryToDtoMapper, dtoToRepositoryMapper, repositoryManager, null, null, null, null, null, null, null); + RepositoryResource repositoryResource = new RepositoryResource(repositoryToDtoMapper, dtoToRepositoryMapper, repositoryManager, null, null, null, null, null, null, null, null); RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks); RepositoryCollectionResource repositoryCollectionResource = new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks); RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(repositoryResource), MockProvider.of(repositoryCollectionResource)); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java index f9ace9f8f6..5b1f1490a3 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java @@ -27,6 +27,7 @@ public class ResourceLinksMock { when(resourceLinks.config()).thenReturn(new ResourceLinks.ConfigLinks(uriInfo)); when(resourceLinks.branch()).thenReturn(new ResourceLinks.BranchLinks(uriInfo)); when(resourceLinks.diff()).thenReturn(new ResourceLinks.DiffLinks(uriInfo)); + 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.uiPluginCollection()).thenReturn(new ResourceLinks.UIPluginCollectionLinks(uriInfo)); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java index a59ed0c103..5f35ce9cf2 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java @@ -1,7 +1,6 @@ package sonia.scm.api.v2.resources; import org.jboss.resteasy.core.Dispatcher; -import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; @@ -74,6 +73,7 @@ public class SourceRootResourceTest { MockProvider.of(sourceRootResource), null, null, + null, null)), null); dispatcher = createDispatcher(repositoryRootResource); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java index 92d11b3895..ad4b396101 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java @@ -74,7 +74,7 @@ public class TagRootResourceTest { tagRootResource = new TagRootResource(serviceFactory, tagCollectionToDtoMapper, tagToTagDtoMapper); RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider .of(new RepositoryResource(null, null, null, MockProvider.of(tagRootResource), null, - null, null, null, null, null)), null); + null, null, null, null, null, null)), null); dispatcher.getRegistry().addSingletonResource(repositoryRootResource); when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService); when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService); From 188d2d8cefbdba9ac8044711a49da47c176ad918 Mon Sep 17 00:00:00 2001 From: Mohamed Karray Date: Thu, 13 Sep 2018 17:29:52 +0200 Subject: [PATCH 41/58] integration tests for modifications --- .../sonia/scm/it/RepositoryAccessITCase.java | 163 ++++++++++++++++++ .../java/sonia/scm/it/RepositoryRequests.java | 46 ++++- .../java/sonia/scm/it/RepositoryUtil.java | 46 ++++- .../spi/GitModificationsCommandTest.java | 2 +- .../spi/HgRepositoryServiceProvider.java | 11 ++ .../spi/SvnRepositoryServiceProvider.java | 4 + .../client/spi/SvnChangeWorker.java | 14 +- 7 files changed, 277 insertions(+), 9 deletions(-) diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java index fc095828b3..398921a692 100644 --- a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java @@ -3,6 +3,8 @@ package sonia.scm.it; import io.restassured.response.ExtractableResponse; import io.restassured.response.Response; import org.apache.http.HttpStatus; +import org.assertj.core.util.Lists; +import org.assertj.core.util.Maps; import org.junit.Assume; import org.junit.Before; import org.junit.Rule; @@ -17,8 +19,11 @@ import sonia.scm.web.VndMediaType; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static java.lang.Thread.sleep; import static org.assertj.core.api.Assertions.assertThat; @@ -312,5 +317,163 @@ public class RepositoryAccessITCase { } ); } + + @Test + @SuppressWarnings("unchecked") + public void shouldFindAddedModifications() throws IOException { + RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder); + String fileName = "a.txt"; + Changeset changeset = RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName, "a"); + String revision = changeset.getId(); + repositoryGetRequest + .usingRepositoryResponse() + .requestChangesets() + .assertStatusCode(HttpStatus.SC_OK) + .usingChangesetsResponse() + .requestModifications(revision) + .assertStatusCode(HttpStatus.SC_OK) + .usingModificationsResponse() + .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision)) + .assertAdded(addedFiles -> assertThat(addedFiles) + .hasSize(1) + .containsExactly(fileName)) + .assertRemoved(removedFiles -> assertThat(removedFiles) + .hasSize(0)) + .assertModified(files -> assertThat(files) + .hasSize(0)); + } + + @Test + @SuppressWarnings("unchecked") + public void shouldFindRemovedModifications() throws IOException { + RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder); + String fileName = "a.txt"; + RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName, "a"); + Changeset changeset = RepositoryUtil.removeAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName); + + String revision = changeset.getId(); + repositoryGetRequest + .usingRepositoryResponse() + .requestChangesets() + .assertStatusCode(HttpStatus.SC_OK) + .usingChangesetsResponse() + .requestModifications(revision) + .assertStatusCode(HttpStatus.SC_OK) + .usingModificationsResponse() + .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision)) + .assertRemoved(removedFiles -> assertThat(removedFiles) + .hasSize(1) + .containsExactly(fileName)) + .assertAdded(addedFiles -> assertThat(addedFiles) + .hasSize(0)) + .assertModified(files -> assertThat(files) + .hasSize(0)); + } + + @Test + @SuppressWarnings("unchecked") + public void shouldFindUpdateModifications() throws IOException { + RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder); + String fileName = "a.txt"; + RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName, "a"); + Changeset changeset = RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName, "new Content"); + + String revision = changeset.getId(); + repositoryGetRequest + .usingRepositoryResponse() + .requestChangesets() + .assertStatusCode(HttpStatus.SC_OK) + .usingChangesetsResponse() + .requestModifications(revision) + .assertStatusCode(HttpStatus.SC_OK) + .usingModificationsResponse() + .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision)) + .assertModified(modifiedFiles -> assertThat(modifiedFiles) + .hasSize(1) + .containsExactly(fileName)) + .assertRemoved(removedFiles -> assertThat(removedFiles) + .hasSize(0)) + .assertAdded(addedFiles -> assertThat(addedFiles) + .hasSize(0)); + } + + @Test + @SuppressWarnings("unchecked") + public void shouldFindMultipleModifications() throws IOException { + RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder); + RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "b.txt", "b"); + RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "c.txt", "c"); + RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "d.txt", "d"); + Map addedFiles = new HashMap() + {{ + put("a.txt", "bla bla"); + }}; + Map modifiedFiles = new HashMap() + {{ + put("b.txt", "new content"); + }}; + ArrayList removedFiles = Lists.newArrayList("c.txt", "d.txt"); + Changeset changeset = RepositoryUtil.commitMultipleFileModifications(repositoryClient, ADMIN_USERNAME, addedFiles, modifiedFiles, removedFiles); + + String revision = changeset.getId(); + repositoryGetRequest + .usingRepositoryResponse() + .requestChangesets() + .assertStatusCode(HttpStatus.SC_OK) + .usingChangesetsResponse() + .requestModifications(revision) + .assertStatusCode(HttpStatus.SC_OK) + .usingModificationsResponse() + .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision)) + .assertAdded(a -> assertThat(a) + .hasSize(1) + .containsExactly("a.txt")) + .assertModified(m-> assertThat(m) + .hasSize(1) + .containsExactly("b.txt")) + .assertRemoved(r -> assertThat(r) + .hasSize(2) + .containsExactly("c.txt", "d.txt")); + } + + @Test + @SuppressWarnings("unchecked") + public void svnShouldCreateOneModificationPerFolder() throws IOException { + Assume.assumeThat(repositoryType, equalTo("svn")); + RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder); + RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "bbb/bb/b.txt", "b"); + RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "ccc/cc/c.txt", "c"); + RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "ddd/dd/d.txt", "d"); + Map addedFiles = new HashMap() + {{ + put("aaa/aa/a.txt", "bla bla"); + }}; + Map modifiedFiles = new HashMap() + {{ + put("bbb/bb/b.txt", "new content"); + }}; + ArrayList removedFiles = Lists.newArrayList("ccc/cc/c.txt", "ddd/dd/d.txt"); + Changeset changeset = RepositoryUtil.commitMultipleFileModifications(repositoryClient, ADMIN_USERNAME, addedFiles, modifiedFiles, removedFiles); + + String revision = changeset.getId(); + repositoryGetRequest + .usingRepositoryResponse() + .requestChangesets() + .assertStatusCode(HttpStatus.SC_OK) + .usingChangesetsResponse() + .requestModifications(revision) + .assertStatusCode(HttpStatus.SC_OK) + .usingModificationsResponse() + .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision)) + .assertAdded(a -> assertThat(a) + .hasSize(3) + .containsExactly("aaa/aa/a.txt", "aaa", "aaa/aa")) + .assertModified(m-> assertThat(m) + .hasSize(1) + .containsExactly("bbb/bb/b.txt")) + .assertRemoved(r -> assertThat(r) + .hasSize(2) + .containsExactly("ccc/cc/c.txt", "ddd/dd/d.txt")); + } } diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryRequests.java b/scm-it/src/test/java/sonia/scm/it/RepositoryRequests.java index 41fa2a6a3d..79300d7b45 100644 --- a/scm-it/src/test/java/sonia/scm/it/RepositoryRequests.java +++ b/scm-it/src/test/java/sonia/scm/it/RepositoryRequests.java @@ -156,7 +156,7 @@ public class RepositoryRequests { return new AppliedGetSourcesRequest(getResponseFromLink(repositoryResponse, "_links.sources.href")); } - AppliedGetChangesetsRequest requestChangesets(String fileName) { + AppliedGetChangesetsRequest requestChangesets() { return new AppliedGetChangesetsRequest(getResponseFromLink(repositoryResponse, "_links.changesets.href")); } } @@ -189,6 +189,9 @@ public class RepositoryRequests { return new AppliedGetDiffRequest(getResponseFromLink(changesetsResponse, "_embedded.changesets.find{it.id=='" + revision + "'}._links.diff.href")); } + public AppliedGetModificationsRequest requestModifications(String revision) { + return new AppliedGetModificationsRequest(getResponseFromLink(changesetsResponse, "_embedded.changesets.find{it.id=='" + revision + "'}._links.modifications.href")); + } } class AppliedGetSourcesRequest extends AppliedGetRequest { @@ -246,4 +249,45 @@ public class RepositoryRequests { return new GivenWithUrlAndAuth(); } } + + class AppliedGetModificationsRequest extends AppliedGetRequest { + public AppliedGetModificationsRequest(Response response) { super(response); } + ModificationsResponse usingModificationsResponse() { + return new ModificationsResponse(super.response); + } + + } + + class ModificationsResponse { + private Response resource; + + public ModificationsResponse(Response resource) { + this.resource = resource; + } + + ModificationsResponse assertRevision(Consumer assertRevision) { + String revision = resource.then().extract().path("revision"); + assertRevision.accept(revision); + return this; + } + + ModificationsResponse assertAdded(Consumer> assertAdded) { + List added = resource.then().extract().path("added"); + assertAdded.accept(added); + return this; + } + + ModificationsResponse assertRemoved(Consumer> assertRemoved) { + List removed = resource.then().extract().path("removed"); + assertRemoved.accept(removed); + return this; + } + + ModificationsResponse assertModified(Consumer> assertModified) { + List modified = resource.then().extract().path("modified"); + assertModified.accept(modified); + return this; + } + + } } diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java b/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java index 0e2eb24ca9..96b92a0bed 100644 --- a/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java +++ b/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java @@ -14,6 +14,8 @@ import sonia.scm.repository.client.api.RepositoryClientFactory; import java.io.File; import java.io.IOException; +import java.util.List; +import java.util.Map; import java.util.UUID; public class RepositoryUtil { @@ -42,11 +44,53 @@ public class RepositoryUtil { } static Changeset createAndCommitFile(RepositoryClient repositoryClient, String username, String fileName, String content) throws IOException { + writeAndAddFile(repositoryClient, fileName, content); + return commit(repositoryClient, username, "added " + fileName); + } + + /** + * Bundle multiple File modification in one changeset + * + * @param repositoryClient + * @param username + * @param addedFiles map.key: path of the file, value: the file content + * @param modifiedFiles map.key: path of the file, value: the file content + * @param removedFiles list of file paths to be removed + * @return the changeset with all modifications + * @throws IOException + */ + static Changeset commitMultipleFileModifications(RepositoryClient repositoryClient, String username, Map addedFiles, Map modifiedFiles, List removedFiles) throws IOException { + for (String fileName : addedFiles.keySet()) { + writeAndAddFile(repositoryClient, fileName, addedFiles.get(fileName)); + } + for (String fileName : modifiedFiles.keySet()) { + writeAndAddFile(repositoryClient, fileName, modifiedFiles.get(fileName)); + } + for (String fileName : removedFiles) { + deleteFileAndApplyRemoveCommand(repositoryClient, fileName); + } + return commit(repositoryClient, username, "multiple file modifications" ); + } + + private static File writeAndAddFile(RepositoryClient repositoryClient, String fileName, String content) throws IOException { File file = new File(repositoryClient.getWorkingCopy(), fileName); Files.createParentDirs(file); Files.write(content, file, Charsets.UTF_8); addWithParentDirectories(repositoryClient, file); - return commit(repositoryClient, username, "added " + fileName); + return file; + } + + static Changeset removeAndCommitFile(RepositoryClient repositoryClient, String username, String fileName) throws IOException { + deleteFileAndApplyRemoveCommand(repositoryClient, fileName); + return commit(repositoryClient, username, "removed " + fileName); + } + + private static void deleteFileAndApplyRemoveCommand(RepositoryClient repositoryClient, String fileName) throws IOException { + File file = new File(repositoryClient.getWorkingCopy(), fileName); + if (repositoryClient.isCommandSupported(ClientCommand.REMOVE)) { + repositoryClient.getRemoveCommand().remove(fileName); + } + file.delete(); } private static String addWithParentDirectories(RepositoryClient repositoryClient, File file) throws IOException { diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java index de90d5a393..fb982f6f0c 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java @@ -53,7 +53,7 @@ public class GitModificationsCommandTest extends AbstractRemoteCommandTestBase { commit(outgoing, "add file"); File file = new File(outgoingDirectory, fileName); file.delete(); - outgoing.add().setUpdate(true).addFilepattern(".").call(); + outgoing.rm().addFilepattern(fileName).call(); RevCommit removedFileCommit = commit(outgoing, "remove file"); String revision = removedFileCommit.getName(); Consumer assertModifications = assertRemovedFiles(fileName); diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java index 4295bf45e4..7749b7e40a 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java @@ -42,6 +42,7 @@ import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.Repository; import sonia.scm.repository.api.Command; +import sonia.scm.repository.api.CommandNotSupportedException; //~--- JDK imports ------------------------------------------------------------ @@ -201,6 +202,16 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider return new HgLogCommand(context, repository); } + /** + * Get the corresponding {@link ModificationsCommand} implemented from the Plugins + * + * @return the corresponding {@link ModificationsCommand} implemented from the Plugins + * @throws CommandNotSupportedException if there is no Implementation + */ + public ModificationsCommand getModificationsCommand() { + return new HgModificationsCommand(context,repository); + } + /** * Method description * diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java index 24180bfe9e..1fda21f0d8 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java @@ -167,6 +167,10 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider return new SvnLogCommand(context, repository); } + public ModificationsCommand getModificationsCommand() { + return new SvnModificationsCommand(context, repository); + } + /** * Method description * diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/client/spi/SvnChangeWorker.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/client/spi/SvnChangeWorker.java index b54e51c4d6..302ef3e8aa 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/client/spi/SvnChangeWorker.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/client/spi/SvnChangeWorker.java @@ -70,13 +70,15 @@ class SvnChangeWorker { SVNWCClient wClient = client.getWCClient(); // add files - try { - wClient.doAdd(addedFiles.toArray(new File[0]), true, false, false, - SVNDepth.INFINITY, false, false, false); - addedFiles.clear(); + if (!addedFiles.isEmpty()){ + try { + wClient.doAdd(addedFiles.toArray(new File[0]), true, false, false, + SVNDepth.INFINITY, false, false, false); + addedFiles.clear(); - } catch (SVNException ex) { - throw new RepositoryClientException("failed to add files", ex); + } catch (SVNException ex) { + throw new RepositoryClientException("failed to add files", ex); + } } // remove files From a075962a66e8c56faeb4d8f1a241175103fcaaaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 14 Sep 2018 08:49:09 +0200 Subject: [PATCH 42/58] Introduce extension point for scm http requests --- .../spi/ScmProviderHttpServletFactory.java | 7 ++++++ .../main/java/sonia/scm/util/Decorators.java | 1 - .../src/main/java/sonia/scm/web/Git.java | 14 ++++++++++++ .../web/GitScmProtocolProviderWrapper.java | 3 ++- .../java/sonia/scm/web/GitServletModule.java | 3 +++ .../sonia/scm/web/ScmGitServletProvider.java | 22 +++++++++++++++++++ 6 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletFactory.java rename {scm-webapp => scm-core}/src/main/java/sonia/scm/util/Decorators.java (99%) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/Git.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletFactory.java b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletFactory.java new file mode 100644 index 0000000000..1f49dec4ba --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletFactory.java @@ -0,0 +1,7 @@ +package sonia.scm.repository.spi; + +import sonia.scm.DecoratorFactory; +import sonia.scm.plugin.ExtensionPoint; + +@ExtensionPoint +public interface ScmProviderHttpServletFactory extends DecoratorFactory {} diff --git a/scm-webapp/src/main/java/sonia/scm/util/Decorators.java b/scm-core/src/main/java/sonia/scm/util/Decorators.java similarity index 99% rename from scm-webapp/src/main/java/sonia/scm/util/Decorators.java rename to scm-core/src/main/java/sonia/scm/util/Decorators.java index 41c75660a9..6465631d03 100644 --- a/scm-webapp/src/main/java/sonia/scm/util/Decorators.java +++ b/scm-core/src/main/java/sonia/scm/util/Decorators.java @@ -37,7 +37,6 @@ package sonia.scm.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import sonia.scm.DecoratorFactory; /** diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/Git.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/Git.java new file mode 100644 index 0000000000..8bcf85c8f0 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/Git.java @@ -0,0 +1,14 @@ +package sonia.scm.web; + +import com.google.inject.BindingAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@BindingAnnotation +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +@interface Git { +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java index 3df7bcce3f..2924a27915 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java @@ -4,6 +4,7 @@ import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.plugin.Extension; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import javax.inject.Inject; import javax.inject.Provider; @@ -13,7 +14,7 @@ import javax.inject.Singleton; @Extension public class GitScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public GitScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + public GitScmProtocolProviderWrapper(@Git Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java index e731e01a62..8c7b30572f 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java @@ -41,6 +41,7 @@ import org.mapstruct.factory.Mappers; import sonia.scm.api.v2.resources.GitConfigDtoToGitConfigMapper; import sonia.scm.api.v2.resources.GitConfigToGitConfigDtoMapper; import sonia.scm.plugin.Extension; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.web.lfs.LfsBlobStoreFactory; /** @@ -63,5 +64,7 @@ public class GitServletModule extends ServletModule bind(GitConfigDtoToGitConfigMapper.class).to(Mappers.getMapper(GitConfigDtoToGitConfigMapper.class).getClass()); bind(GitConfigToGitConfigDtoMapper.class).to(Mappers.getMapper(GitConfigToGitConfigDtoMapper.class).getClass()); + + bind(ScmProviderHttpServlet.class).annotatedWith(Git.class).toProvider(ScmGitServletProvider.class); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java new file mode 100644 index 0000000000..2c7c8b19f9 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java @@ -0,0 +1,22 @@ +package sonia.scm.web; + +import com.google.inject.Inject; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletFactory; +import sonia.scm.util.Decorators; + +import javax.inject.Provider; +import java.util.Set; + +public class ScmGitServletProvider implements Provider { + + @Inject + private Provider scmGitServlet; + @Inject(optional = true) + private Set decoratorFactories; + + @Override + public ScmProviderHttpServlet get() { + return Decorators.decorate(scmGitServlet.get(), decoratorFactories); + } +} From 6ab5f58fe95b85fc3f5b86ed93bb8b6dbe932c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 14 Sep 2018 09:15:46 +0200 Subject: [PATCH 43/58] Generalize servlet decorator structure --- .../spi/ScmProviderHttpServletDecorator.java | 28 +++++++++++++++++++ ...cmProviderHttpServletDecoratorFactory.java | 15 ++++++++++ .../spi/ScmProviderHttpServletFactory.java | 7 ----- .../sonia/scm/web/ScmGitServletProvider.java | 12 ++------ .../web/ScmProviderHttpServletProvider.java | 24 ++++++++++++++++ 5 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletDecorator.java create mode 100644 scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletDecoratorFactory.java delete mode 100644 scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletFactory.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmProviderHttpServletProvider.java diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletDecorator.java b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletDecorator.java new file mode 100644 index 0000000000..c5dd55d277 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletDecorator.java @@ -0,0 +1,28 @@ +package sonia.scm.repository.spi; + +import sonia.scm.repository.Repository; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class ScmProviderHttpServletDecorator implements ScmProviderHttpServlet { + + private final ScmProviderHttpServlet object; + + public ScmProviderHttpServletDecorator(ScmProviderHttpServlet object) { + this.object = object; + } + + @Override + public void service(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException { + object.service(request, response, repository); + } + + @Override + public void init(ServletConfig config) throws ServletException { + object.init(config); + } +} diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletDecoratorFactory.java b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletDecoratorFactory.java new file mode 100644 index 0000000000..531a25e91d --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletDecoratorFactory.java @@ -0,0 +1,15 @@ +package sonia.scm.repository.spi; + +import sonia.scm.DecoratorFactory; +import sonia.scm.plugin.ExtensionPoint; + +@ExtensionPoint +public interface ScmProviderHttpServletDecoratorFactory extends DecoratorFactory { + /** + * Has to return true if this factory provides a decorator for the given scm type (eg. "git", "hg" or + * "svn"). + * @param type The current scm type this factory can provide a decorator for. + * @return true when the provided decorator should be used for the given scm type. + */ + boolean handlesScmType(String type); +} diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletFactory.java b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletFactory.java deleted file mode 100644 index 1f49dec4ba..0000000000 --- a/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletFactory.java +++ /dev/null @@ -1,7 +0,0 @@ -package sonia.scm.repository.spi; - -import sonia.scm.DecoratorFactory; -import sonia.scm.plugin.ExtensionPoint; - -@ExtensionPoint -public interface ScmProviderHttpServletFactory extends DecoratorFactory {} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java index 2c7c8b19f9..b8eb38de6d 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java @@ -1,22 +1,16 @@ package sonia.scm.web; import com.google.inject.Inject; -import sonia.scm.repository.spi.ScmProviderHttpServlet; -import sonia.scm.repository.spi.ScmProviderHttpServletFactory; -import sonia.scm.util.Decorators; import javax.inject.Provider; -import java.util.Set; -public class ScmGitServletProvider implements Provider { +public class ScmGitServletProvider extends ScmProviderHttpServletProvider { @Inject private Provider scmGitServlet; - @Inject(optional = true) - private Set decoratorFactories; @Override - public ScmProviderHttpServlet get() { - return Decorators.decorate(scmGitServlet.get(), decoratorFactories); + protected ScmGitServlet getRootServlet() { + return scmGitServlet.get(); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmProviderHttpServletProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmProviderHttpServletProvider.java new file mode 100644 index 0000000000..a9369d8f4e --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmProviderHttpServletProvider.java @@ -0,0 +1,24 @@ +package sonia.scm.web; + +import com.google.inject.Inject; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; +import sonia.scm.util.Decorators; + +import javax.inject.Provider; +import java.util.Set; + +import static java.util.stream.Collectors.toList; + +public abstract class ScmProviderHttpServletProvider implements Provider { + + @Inject(optional = true) + private Set decoratorFactories; + + @Override + public ScmProviderHttpServlet get() { + return Decorators.decorate(getRootServlet(), decoratorFactories.stream().filter(d -> d.handlesScmType("git")).collect(toList())); + } + + protected abstract ScmProviderHttpServlet getRootServlet(); +} From 7de9f690613a626f322ae90d8606b63487b55e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 14 Sep 2018 09:36:56 +0200 Subject: [PATCH 44/58] Add servlet decorators for hg and svn --- .../spi}/ScmProviderHttpServletProvider.java | 12 ++++++---- .../sonia/scm/web/ScmGitServletProvider.java | 12 +++++++--- .../src/main/java/sonia/scm/web/Hg.java | 14 ++++++++++++ .../sonia/scm/web/HgCGIServletProvider.java | 22 +++++++++++++++++++ .../scm/web/HgScmProtocolProviderWrapper.java | 3 ++- .../java/sonia/scm/web/HgServletModule.java | 3 +++ .../src/main/java/sonia/scm/web/Svn.java | 14 ++++++++++++ .../sonia/scm/web/SvnDAVServletProvider.java | 22 +++++++++++++++++++ .../web/SvnScmProtocolProviderWrapper.java | 2 +- .../java/sonia/scm/web/SvnServletModule.java | 3 +++ 10 files changed, 98 insertions(+), 9 deletions(-) rename {scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web => scm-core/src/main/java/sonia/scm/repository/spi}/ScmProviderHttpServletProvider.java (71%) create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/Hg.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServletProvider.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/Svn.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServletProvider.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmProviderHttpServletProvider.java b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletProvider.java similarity index 71% rename from scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmProviderHttpServletProvider.java rename to scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletProvider.java index a9369d8f4e..991728e72c 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmProviderHttpServletProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletProvider.java @@ -1,8 +1,6 @@ -package sonia.scm.web; +package sonia.scm.repository.spi; import com.google.inject.Inject; -import sonia.scm.repository.spi.ScmProviderHttpServlet; -import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; import sonia.scm.util.Decorators; import javax.inject.Provider; @@ -15,9 +13,15 @@ public abstract class ScmProviderHttpServletProvider implements Provider decoratorFactories; + private final String type; + + protected ScmProviderHttpServletProvider(String type) { + this.type = type; + } + @Override public ScmProviderHttpServlet get() { - return Decorators.decorate(getRootServlet(), decoratorFactories.stream().filter(d -> d.handlesScmType("git")).collect(toList())); + return Decorators.decorate(getRootServlet(), decoratorFactories.stream().filter(d -> d.handlesScmType(type)).collect(toList())); } protected abstract ScmProviderHttpServlet getRootServlet(); diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java index b8eb38de6d..5e8ef80d3d 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java @@ -1,16 +1,22 @@ package sonia.scm.web; import com.google.inject.Inject; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletProvider; import javax.inject.Provider; public class ScmGitServletProvider extends ScmProviderHttpServletProvider { @Inject - private Provider scmGitServlet; + private Provider servletProvider; + + public ScmGitServletProvider() { + super("git"); + } @Override - protected ScmGitServlet getRootServlet() { - return scmGitServlet.get(); + protected ScmProviderHttpServlet getRootServlet() { + return servletProvider.get(); } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/Hg.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/Hg.java new file mode 100644 index 0000000000..e4fe39e724 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/Hg.java @@ -0,0 +1,14 @@ +package sonia.scm.web; + +import com.google.inject.BindingAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@BindingAnnotation +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +@interface Hg { +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServletProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServletProvider.java new file mode 100644 index 0000000000..d17479b399 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServletProvider.java @@ -0,0 +1,22 @@ +package sonia.scm.web; + +import com.google.inject.Inject; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletProvider; + +import javax.inject.Provider; + +public class HgCGIServletProvider extends ScmProviderHttpServletProvider { + + @Inject + private Provider servletProvider; + + public HgCGIServletProvider() { + super("hg"); + } + + @Override + protected ScmProviderHttpServlet getRootServlet() { + return servletProvider.get(); + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java index 5ea8e66501..1d75e63332 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java @@ -4,6 +4,7 @@ import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.plugin.Extension; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import javax.inject.Inject; import javax.inject.Provider; @@ -13,7 +14,7 @@ import javax.inject.Singleton; @Extension public class HgScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public HgScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + public HgScmProtocolProviderWrapper(@Hg Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java index ba9ae3a0b9..6949be2ea9 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java @@ -46,6 +46,7 @@ import sonia.scm.plugin.Extension; import sonia.scm.repository.HgContext; import sonia.scm.repository.HgContextProvider; import sonia.scm.repository.HgHookManager; +import sonia.scm.repository.spi.ScmProviderHttpServlet; /** * @@ -79,6 +80,8 @@ public class HgServletModule extends ServletModule bind(HgConfigPackagesToDtoMapper.class).to(Mappers.getMapper(HgConfigPackagesToDtoMapper.class).getClass()); bind(HgConfigInstallationsToDtoMapper.class); + bind(ScmProviderHttpServlet.class).annotatedWith(Hg.class).toProvider(HgCGIServletProvider.class); + // bind servlets serve(MAPPING_HOOK).with(HgHookCallbackServlet.class); } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/Svn.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/Svn.java new file mode 100644 index 0000000000..744c1a0939 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/Svn.java @@ -0,0 +1,14 @@ +package sonia.scm.web; + +import com.google.inject.BindingAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@BindingAnnotation +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +@interface Svn { +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServletProvider.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServletProvider.java new file mode 100644 index 0000000000..586b277673 --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServletProvider.java @@ -0,0 +1,22 @@ +package sonia.scm.web; + +import com.google.inject.Inject; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletProvider; + +import javax.inject.Provider; + +public class SvnDAVServletProvider extends ScmProviderHttpServletProvider { + + @Inject + private Provider servletProvider; + + public SvnDAVServletProvider() { + super("svn"); + } + + @Override + protected ScmProviderHttpServlet getRootServlet() { + return servletProvider.get(); + } +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java index 14b946acc7..ed47791793 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -26,7 +26,7 @@ public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWr } @Inject - public SvnScmProtocolProviderWrapper(Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + public SvnScmProtocolProviderWrapper(@Svn Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java index 8526d6380a..cd47a2fa44 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java @@ -38,6 +38,7 @@ import org.mapstruct.factory.Mappers; import sonia.scm.api.v2.resources.SvnConfigDtoToSvnConfigMapper; import sonia.scm.api.v2.resources.SvnConfigToSvnConfigDtoMapper; import sonia.scm.plugin.Extension; +import sonia.scm.repository.spi.ScmProviderHttpServlet; /** * @@ -50,5 +51,7 @@ public class SvnServletModule extends ServletModule { protected void configureServlets() { bind(SvnConfigDtoToSvnConfigMapper.class).to(Mappers.getMapper(SvnConfigDtoToSvnConfigMapper.class).getClass()); bind(SvnConfigToSvnConfigDtoMapper.class).to(Mappers.getMapper(SvnConfigToSvnConfigDtoMapper.class).getClass()); + + bind(ScmProviderHttpServlet.class).annotatedWith(Svn.class).toProvider(SvnDAVServletProvider.class); } } From e88639ab814420983517f6eb86cc77dbf6b4ff00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 14 Sep 2018 10:21:00 +0200 Subject: [PATCH 45/58] Implement permission filters as decorator for servlets --- .../InitializingHttpScmProtocolWrapper.java | 11 ++----- .../spi/ScmProviderHttpServletProvider.java | 7 +++- .../scm/web/filter/PermissionFilter.java | 19 +++++------ ...nitializingHttpScmProtocolWrapperTest.java | 33 +------------------ .../sonia/scm/web/GitPermissionFilter.java | 7 ++-- .../scm/web/GitPermissionFilterFactory.java | 29 ++++++++++++++++ .../web/GitScmProtocolProviderWrapper.java | 4 +-- .../scm/web/GitPermissionFilterTest.java | 3 +- .../sonia/scm/web/HgPermissionFilter.java | 7 ++-- .../scm/web/HgPermissionFilterFactory.java | 29 ++++++++++++++++ .../scm/web/HgScmProtocolProviderWrapper.java | 4 +-- .../sonia/scm/web/SvnPermissionFilter.java | 7 ++-- .../scm/web/SvnPermissionFilterFactory.java | 29 ++++++++++++++++ .../web/SvnScmProtocolProviderWrapper.java | 4 +-- 14 files changed, 122 insertions(+), 71 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilterFactory.java create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilterFactory.java diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 6e59470c5e..69ff0a83f5 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -6,7 +6,6 @@ import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; import sonia.scm.repository.api.ScmProtocolProvider; -import sonia.scm.web.filter.PermissionFilter; import javax.inject.Provider; import javax.servlet.ServletConfig; @@ -24,16 +23,14 @@ public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolP private static final Logger logger = LoggerFactory.getLogger(InitializingHttpScmProtocolWrapper.class); private final Provider delegateProvider; - private final Provider permissionFilterProvider; private final Provider uriInfoStore; private final ScmConfiguration scmConfiguration; private volatile boolean isInitialized = false; - protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider permissionFilterProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { this.delegateProvider = delegateProvider; - this.permissionFilterProvider = permissionFilterProvider; this.uriInfoStore = uriInfoStore; this.scmConfiguration = scmConfiguration; } @@ -89,11 +86,7 @@ public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolP } } - permissionFilterProvider.get().executeIfPermitted( - request, - response, - repository, - () -> delegateProvider.get().service(request, response, repository)); + delegateProvider.get().service(request, response, repository); } } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletProvider.java b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletProvider.java index 991728e72c..3793d4b935 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/ScmProviderHttpServletProvider.java @@ -4,6 +4,7 @@ import com.google.inject.Inject; import sonia.scm.util.Decorators; import javax.inject.Provider; +import java.util.List; import java.util.Set; import static java.util.stream.Collectors.toList; @@ -21,7 +22,11 @@ public abstract class ScmProviderHttpServletProvider implements Provider d.handlesScmType(type)).collect(toList())); + return Decorators.decorate(getRootServlet(), getDecoratorsForType()); + } + + private List getDecoratorsForType() { + return decoratorFactories.stream().filter(d -> d.handlesScmType(type)).collect(toList()); } protected abstract ScmProviderHttpServlet getRootServlet(); diff --git a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java index a01875fed0..328494a626 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/PermissionFilter.java @@ -42,6 +42,8 @@ import sonia.scm.SCMContext; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryPermissions; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletDecorator; import sonia.scm.security.Role; import sonia.scm.security.ScmSecurityException; import sonia.scm.util.HttpUtil; @@ -56,7 +58,7 @@ import java.io.IOException; * * @author Sebastian Sdorra */ -public abstract class PermissionFilter +public abstract class PermissionFilter extends ScmProviderHttpServletDecorator { /** the logger for PermissionFilter */ @@ -72,8 +74,9 @@ public abstract class PermissionFilter * * @since 1.21 */ - protected PermissionFilter(ScmConfiguration configuration) + protected PermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate) { + super(delegate); this.configuration = configuration; } @@ -102,8 +105,9 @@ public abstract class PermissionFilter * @throws IOException * @throws ServletException */ - public void executeIfPermitted(HttpServletRequest request, - HttpServletResponse response, Repository repository, ContinuationServlet continuation) + @Override + public void service(HttpServletRequest request, + HttpServletResponse response, Repository repository) throws IOException, ServletException { Subject subject = SecurityUtils.getSubject(); @@ -118,7 +122,7 @@ public abstract class PermissionFilter getActionAsString(writeRequest), repository.getName(), getUserName(subject)); - continuation.doService(); + super.service(request, response, repository); } else { @@ -258,9 +262,4 @@ public abstract class PermissionFilter /** scm-manager global configuration */ private final ScmConfiguration configuration; - - @FunctionalInterface - public interface ContinuationServlet { - void doService() throws ServletException, IOException; - } } diff --git a/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java b/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java index 6d01232fe3..8c910f92a9 100644 --- a/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapperTest.java @@ -5,13 +5,11 @@ import com.google.inject.util.Providers; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; -import org.mockito.stubbing.Answer; import org.mockito.stubbing.OngoingStubbing; import sonia.scm.api.v2.resources.ScmPathInfo; import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; -import sonia.scm.web.filter.PermissionFilter; import javax.inject.Provider; import javax.servlet.ServletConfig; @@ -22,12 +20,7 @@ import java.io.IOException; import java.net.URI; import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -40,8 +33,6 @@ public class InitializingHttpScmProtocolWrapperTest { @Mock private ScmProviderHttpServlet delegateServlet; @Mock - private PermissionFilter permissionFilter; - @Mock private ScmPathInfoStore pathInfoStore; @Mock private ScmConfiguration scmConfiguration; @@ -62,7 +53,7 @@ public class InitializingHttpScmProtocolWrapperTest { pathInfoStoreProvider = mock(Provider.class); when(pathInfoStoreProvider.get()).thenReturn(pathInfoStore); - wrapper = new InitializingHttpScmProtocolWrapper(Providers.of(this.delegateServlet), Providers.of(permissionFilter), pathInfoStoreProvider, scmConfiguration) { + wrapper = new InitializingHttpScmProtocolWrapper(Providers.of(this.delegateServlet), pathInfoStoreProvider, scmConfiguration) { @Override public String getType() { return "git"; @@ -98,8 +89,6 @@ public class InitializingHttpScmProtocolWrapperTest { @Test public void shouldInitializeAndDelegateRequestThroughFilter() throws ServletException, IOException { - doAnswer(proceedInvocation()). - when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any()); HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); httpScmProtocol.serve(request, response, servletConfig); @@ -108,21 +97,8 @@ public class InitializingHttpScmProtocolWrapperTest { verify(delegateServlet).service(request, response, REPOSITORY); } - @Test - public void shouldNotDelegateRequestWhenFilterBlocks() throws ServletException, IOException { - doNothing(). - when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any()); - HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); - - httpScmProtocol.serve(request, response, servletConfig); - - verify(delegateServlet, never()).service(request, response, REPOSITORY); - } - @Test public void shouldInitializeOnlyOnce() throws ServletException, IOException { - doAnswer(proceedInvocation()). - when(permissionFilter).executeIfPermitted(same(request), same(response), same(REPOSITORY), any()); HttpScmProtocol httpScmProtocol = wrapper.get(REPOSITORY); httpScmProtocol.serve(request, response, servletConfig); @@ -137,13 +113,6 @@ public class InitializingHttpScmProtocolWrapperTest { HttpScmProtocol httpScmProtocol = wrapper.get(new Repository("", "other", "space", "name")); } - private Answer proceedInvocation() { - return invocation -> { - ((PermissionFilter.ContinuationServlet) invocation.getArgument(3)).doService(); - return null; - }; - } - private OngoingStubbing mockSetPathInfo() { return when(pathInfoStore.get()).thenReturn(() -> URI.create("http://example.com/scm/api/rest/")); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java index e183555b3b..e38f26a309 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java @@ -34,11 +34,11 @@ package sonia.scm.web; import com.google.common.annotations.VisibleForTesting; -import com.google.inject.Inject; import org.eclipse.jgit.http.server.GitSmartHttpTools; import sonia.scm.ClientMessages; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.GitUtil; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.web.filter.PermissionFilter; import javax.servlet.http.HttpServletRequest; @@ -70,9 +70,8 @@ public class GitPermissionFilter extends PermissionFilter * * @param configuration scm main configuration */ - @Inject - public GitPermissionFilter(ScmConfiguration configuration) { - super(configuration); + public GitPermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate) { + super(configuration, delegate); } @Override diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilterFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilterFactory.java new file mode 100644 index 0000000000..4ef76bdea1 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilterFactory.java @@ -0,0 +1,29 @@ +package sonia.scm.web; + +import sonia.scm.config.ScmConfiguration; +import sonia.scm.plugin.Extension; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; + +import javax.inject.Inject; + +@Extension +public class GitPermissionFilterFactory implements ScmProviderHttpServletDecoratorFactory { + + private final ScmConfiguration configuration; + + @Inject + public GitPermissionFilterFactory(ScmConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public boolean handlesScmType(String type) { + return "git".equals(type); + } + + @Override + public ScmProviderHttpServlet createDecorator(ScmProviderHttpServlet delegate) { + return new GitPermissionFilter(configuration, delegate); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java index 2924a27915..073969ce91 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java @@ -14,8 +14,8 @@ import javax.inject.Singleton; @Extension public class GitScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public GitScmProtocolProviderWrapper(@Git Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { - super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); + public GitScmProtocolProviderWrapper(@Git Provider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + super(servletProvider, uriInfoStore, scmConfiguration); } @Override diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java index 8e7ff3d954..831402261b 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java @@ -5,6 +5,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import sonia.scm.config.ScmConfiguration; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.util.HttpUtil; import javax.servlet.ServletOutputStream; @@ -28,7 +29,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class GitPermissionFilterTest { - private final GitPermissionFilter permissionFilter = new GitPermissionFilter(new ScmConfiguration()); + private final GitPermissionFilter permissionFilter = new GitPermissionFilter(new ScmConfiguration(), mock(ScmProviderHttpServlet.class)); @Mock private HttpServletResponse response; diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java index a2dccb30c9..7f92cc0357 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilter.java @@ -34,8 +34,8 @@ package sonia.scm.web; import com.google.common.collect.ImmutableSet; -import com.google.inject.Inject; import sonia.scm.config.ScmConfiguration; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.web.filter.PermissionFilter; import javax.servlet.http.HttpServletRequest; @@ -51,10 +51,9 @@ public class HgPermissionFilter extends PermissionFilter private static final Set READ_METHODS = ImmutableSet.of("GET", "HEAD", "OPTIONS", "TRACE"); - @Inject - public HgPermissionFilter(ScmConfiguration configuration) + public HgPermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate) { - super(configuration); + super(configuration, delegate); } @Override diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java new file mode 100644 index 0000000000..584a8113ab --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java @@ -0,0 +1,29 @@ +package sonia.scm.web; + +import sonia.scm.config.ScmConfiguration; +import sonia.scm.plugin.Extension; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; + +import javax.inject.Inject; + +@Extension +public class HgPermissionFilterFactory implements ScmProviderHttpServletDecoratorFactory { + + private final ScmConfiguration configuration; + + @Inject + public HgPermissionFilterFactory(ScmConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public boolean handlesScmType(String type) { + return "hg".equals(type); + } + + @Override + public ScmProviderHttpServlet createDecorator(ScmProviderHttpServlet delegate) { + return new HgPermissionFilter(configuration, delegate); + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java index 1d75e63332..fcd80a880c 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java @@ -14,8 +14,8 @@ import javax.inject.Singleton; @Extension public class HgScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper { @Inject - public HgScmProtocolProviderWrapper(@Hg Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { - super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); + public HgScmProtocolProviderWrapper(@Hg Provider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + super(servletProvider, uriInfoStore, scmConfiguration); } @Override diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java index 8918b8fa90..2c0a1e65ff 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilter.java @@ -34,11 +34,11 @@ package sonia.scm.web; import com.google.common.collect.ImmutableSet; -import com.google.inject.Inject; import sonia.scm.ClientMessages; import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.ScmSvnErrorCode; import sonia.scm.repository.SvnUtil; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.web.filter.PermissionFilter; import javax.servlet.http.HttpServletRequest; @@ -65,10 +65,9 @@ public class SvnPermissionFilter extends PermissionFilter * * @param configuration */ - @Inject - public SvnPermissionFilter(ScmConfiguration configuration) + public SvnPermissionFilter(ScmConfiguration configuration, ScmProviderHttpServlet delegate) { - super(configuration); + super(configuration, delegate); } //~--- methods -------------------------------------------------------------- diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilterFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilterFactory.java new file mode 100644 index 0000000000..cd4a7600aa --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilterFactory.java @@ -0,0 +1,29 @@ +package sonia.scm.web; + +import sonia.scm.config.ScmConfiguration; +import sonia.scm.plugin.Extension; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; + +import javax.inject.Inject; + +@Extension +public class SvnPermissionFilterFactory implements ScmProviderHttpServletDecoratorFactory { + + private final ScmConfiguration configuration; + + @Inject + public SvnPermissionFilterFactory(ScmConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public boolean handlesScmType(String type) { + return "svn".equals(type); + } + + @Override + public ScmProviderHttpServlet createDecorator(ScmProviderHttpServlet delegate) { + return new SvnPermissionFilter(configuration, delegate); + } +} diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java index ed47791793..dbb8d5a84d 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -26,8 +26,8 @@ public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWr } @Inject - public SvnScmProtocolProviderWrapper(@Svn Provider servletProvider, Provider permissionFilter, Provider uriInfoStore, ScmConfiguration scmConfiguration) { - super(servletProvider, permissionFilter, uriInfoStore, scmConfiguration); + public SvnScmProtocolProviderWrapper(@Svn Provider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) { + super(servletProvider, uriInfoStore, scmConfiguration); } @Override From 4d60ebd54eb894f711140e38143e24142fd41a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 14 Sep 2018 10:31:16 +0200 Subject: [PATCH 46/58] Use constants for repository types --- .../scm/repository/spi/GitRepositoryServiceResolver.java | 4 +--- .../main/java/sonia/scm/web/GitPermissionFilterFactory.java | 3 ++- .../java/sonia/scm/web/GitScmProtocolProviderWrapper.java | 3 ++- .../src/main/java/sonia/scm/web/ScmGitServletProvider.java | 3 ++- .../sonia/scm/repository/spi/HgRepositoryServiceResolver.java | 4 +--- .../src/main/java/sonia/scm/web/HgCGIServletProvider.java | 3 ++- .../main/java/sonia/scm/web/HgPermissionFilterFactory.java | 3 ++- .../main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java | 3 ++- .../scm/repository/spi/SvnRepositoryServiceResolver.java | 4 +--- .../src/main/java/sonia/scm/web/SvnDAVServletProvider.java | 3 ++- .../main/java/sonia/scm/web/SvnPermissionFilterFactory.java | 3 ++- .../java/sonia/scm/web/SvnScmProtocolProviderWrapper.java | 3 ++- 12 files changed, 21 insertions(+), 18 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java index b1e9143afd..deca141556 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceResolver.java @@ -46,8 +46,6 @@ import sonia.scm.repository.Repository; @Extension public class GitRepositoryServiceResolver implements RepositoryServiceResolver { - public static final String TYPE = "git"; - private final GitRepositoryHandler handler; @Inject @@ -59,7 +57,7 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver { public GitRepositoryServiceProvider resolve(Repository repository) { GitRepositoryServiceProvider provider = null; - if (TYPE.equalsIgnoreCase(repository.getType())) { + if (GitRepositoryHandler.TYPE_NAME.equalsIgnoreCase(repository.getType())) { provider = new GitRepositoryServiceProvider(handler, repository); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilterFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilterFactory.java index 4ef76bdea1..c358da5fb1 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilterFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilterFactory.java @@ -2,6 +2,7 @@ package sonia.scm.web; import sonia.scm.config.ScmConfiguration; import sonia.scm.plugin.Extension; +import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; @@ -19,7 +20,7 @@ public class GitPermissionFilterFactory implements ScmProviderHttpServletDecorat @Override public boolean handlesScmType(String type) { - return "git".equals(type); + return GitRepositoryHandler.TYPE_NAME.equals(type); } @Override diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java index 073969ce91..8273f3950e 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java @@ -3,6 +3,7 @@ package sonia.scm.web; import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.plugin.Extension; +import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import sonia.scm.repository.spi.ScmProviderHttpServlet; @@ -20,6 +21,6 @@ public class GitScmProtocolProviderWrapper extends InitializingHttpScmProtocolWr @Override public String getType() { - return "git"; + return GitRepositoryHandler.TYPE_NAME; } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java index 5e8ef80d3d..56a9e358be 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/ScmGitServletProvider.java @@ -1,6 +1,7 @@ package sonia.scm.web; import com.google.inject.Inject; +import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.repository.spi.ScmProviderHttpServletProvider; @@ -12,7 +13,7 @@ public class ScmGitServletProvider extends ScmProviderHttpServletProvider { private Provider servletProvider; public ScmGitServletProvider() { - super("git"); + super(GitRepositoryHandler.TYPE_NAME); } @Override diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java index f80dcd5ba8..d6d04ee017 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java @@ -47,8 +47,6 @@ import sonia.scm.repository.Repository; public class HgRepositoryServiceResolver implements RepositoryServiceResolver { - private static final String TYPE = "hg"; - private HgRepositoryHandler handler; private HgHookManager hookManager; @@ -64,7 +62,7 @@ public class HgRepositoryServiceResolver implements RepositoryServiceResolver public HgRepositoryServiceProvider resolve(Repository repository) { HgRepositoryServiceProvider provider = null; - if (TYPE.equalsIgnoreCase(repository.getType())) { + if (HgRepositoryHandler.TYPE_NAME.equalsIgnoreCase(repository.getType())) { provider = new HgRepositoryServiceProvider(handler, hookManager, repository); } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServletProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServletProvider.java index d17479b399..db7a6be7b3 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServletProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServletProvider.java @@ -1,6 +1,7 @@ package sonia.scm.web; import com.google.inject.Inject; +import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.repository.spi.ScmProviderHttpServletProvider; @@ -12,7 +13,7 @@ public class HgCGIServletProvider extends ScmProviderHttpServletProvider { private Provider servletProvider; public HgCGIServletProvider() { - super("hg"); + super(HgRepositoryHandler.TYPE_NAME); } @Override diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java index 584a8113ab..90f53a1fea 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgPermissionFilterFactory.java @@ -2,6 +2,7 @@ package sonia.scm.web; import sonia.scm.config.ScmConfiguration; import sonia.scm.plugin.Extension; +import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; @@ -19,7 +20,7 @@ public class HgPermissionFilterFactory implements ScmProviderHttpServletDecorato @Override public boolean handlesScmType(String type) { - return "hg".equals(type); + return HgRepositoryHandler.TYPE_NAME.equals(type); } @Override diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java index fcd80a880c..72382f16bc 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java @@ -3,6 +3,7 @@ package sonia.scm.web; import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.plugin.Extension; +import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import sonia.scm.repository.spi.ScmProviderHttpServlet; @@ -20,6 +21,6 @@ public class HgScmProtocolProviderWrapper extends InitializingHttpScmProtocolWra @Override public String getType() { - return "hg"; + return HgRepositoryHandler.TYPE_NAME; } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java index c674a7827a..763b5f445e 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java @@ -40,8 +40,6 @@ import sonia.scm.repository.SvnRepositoryHandler; @Extension public class SvnRepositoryServiceResolver implements RepositoryServiceResolver { - public static final String TYPE = "svn"; - private SvnRepositoryHandler handler; @Inject @@ -53,7 +51,7 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver { public SvnRepositoryServiceProvider resolve(Repository repository) { SvnRepositoryServiceProvider provider = null; - if (TYPE.equalsIgnoreCase(repository.getType())) { + if (SvnRepositoryHandler.TYPE_NAME.equalsIgnoreCase(repository.getType())) { provider = new SvnRepositoryServiceProvider(handler, repository); } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServletProvider.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServletProvider.java index 586b277673..d221504256 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServletProvider.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnDAVServletProvider.java @@ -1,6 +1,7 @@ package sonia.scm.web; import com.google.inject.Inject; +import sonia.scm.repository.SvnRepositoryHandler; import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.repository.spi.ScmProviderHttpServletProvider; @@ -12,7 +13,7 @@ public class SvnDAVServletProvider extends ScmProviderHttpServletProvider { private Provider servletProvider; public SvnDAVServletProvider() { - super("svn"); + super(SvnRepositoryHandler.TYPE_NAME); } @Override diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilterFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilterFactory.java index cd4a7600aa..882cb8c54f 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilterFactory.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnPermissionFilterFactory.java @@ -2,6 +2,7 @@ package sonia.scm.web; import sonia.scm.config.ScmConfiguration; import sonia.scm.plugin.Extension; +import sonia.scm.repository.SvnRepositoryHandler; import sonia.scm.repository.spi.ScmProviderHttpServlet; import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; @@ -19,7 +20,7 @@ public class SvnPermissionFilterFactory implements ScmProviderHttpServletDecorat @Override public boolean handlesScmType(String type) { - return "svn".equals(type); + return SvnRepositoryHandler.TYPE_NAME.equals(type); } @Override diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java index dbb8d5a84d..fb7d921742 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java @@ -3,6 +3,7 @@ package sonia.scm.web; import sonia.scm.api.v2.resources.ScmPathInfoStore; import sonia.scm.config.ScmConfiguration; import sonia.scm.plugin.Extension; +import sonia.scm.repository.SvnRepositoryHandler; import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper; import sonia.scm.repository.spi.ScmProviderHttpServlet; @@ -22,7 +23,7 @@ public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWr @Override public String getType() { - return "svn"; + return SvnRepositoryHandler.TYPE_NAME; } @Inject From 8ccd0c1b2d46d02139bb942be6910214b21f54ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 14 Sep 2018 11:01:25 +0200 Subject: [PATCH 47/58] Implement gzip filter for svn as extension --- .../java/sonia/scm/web/SvnGZipFilter.java | 58 ++++++++++++------- .../sonia/scm/web/SvnGZipFilterFactory.java | 28 +++++++++ 2 files changed, 66 insertions(+), 20 deletions(-) create mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilterFactory.java diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilter.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilter.java index 65afefbb28..7cc78180ff 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilter.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilter.java @@ -34,38 +34,34 @@ package sonia.scm.web; //~--- non-JDK imports -------------------------------------------------------- -import com.google.inject.Inject; -import com.google.inject.Singleton; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import sonia.scm.filter.GZipFilter; +import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.IOException; +import sonia.scm.repository.spi.ScmProviderHttpServlet; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; +import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +//~--- JDK imports ------------------------------------------------------------ /** * * @author Sebastian Sdorra */ -@Singleton -public class SvnGZipFilter extends GZipFilter +public class SvnGZipFilter extends GZipFilter implements ScmProviderHttpServlet { - /** - * the logger for SvnGZipFilter - */ - private static final Logger logger = - LoggerFactory.getLogger(SvnGZipFilter.class); + private static final Logger logger = LoggerFactory.getLogger(SvnGZipFilter.class); + + private final SvnRepositoryHandler handler; + private final ScmProviderHttpServlet delegate; //~--- constructors --------------------------------------------------------- @@ -75,10 +71,10 @@ public class SvnGZipFilter extends GZipFilter * * @param handler */ - @Inject - public SvnGZipFilter(SvnRepositoryHandler handler) + public SvnGZipFilter(SvnRepositoryHandler handler, ScmProviderHttpServlet delegate) { this.handler = handler; + this.delegate = delegate; } //~--- methods -------------------------------------------------------------- @@ -134,8 +130,30 @@ public class SvnGZipFilter extends GZipFilter } } - //~--- fields --------------------------------------------------------------- + @Override + public void service(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException { + if (handler.getConfig().isEnabledGZip()) + { + if (logger.isTraceEnabled()) + { + logger.trace("encode svn request with gzip"); + } - /** Field description */ - private SvnRepositoryHandler handler; + super.doFilter(request, response, (servletRequest, servletResponse) -> delegate.service((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse, repository)); + } + else + { + if (logger.isTraceEnabled()) + { + logger.trace("skip gzip encoding"); + } + + delegate.service(request, response, repository); + } + } + + @Override + public void init(ServletConfig config) throws ServletException { + delegate.init(config); + } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilterFactory.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilterFactory.java new file mode 100644 index 0000000000..e2774106fa --- /dev/null +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnGZipFilterFactory.java @@ -0,0 +1,28 @@ +package sonia.scm.web; + +import com.google.inject.Inject; +import sonia.scm.plugin.Extension; +import sonia.scm.repository.SvnRepositoryHandler; +import sonia.scm.repository.spi.ScmProviderHttpServlet; +import sonia.scm.repository.spi.ScmProviderHttpServletDecoratorFactory; + +@Extension +public class SvnGZipFilterFactory implements ScmProviderHttpServletDecoratorFactory { + + private final SvnRepositoryHandler handler; + + @Inject + public SvnGZipFilterFactory(SvnRepositoryHandler handler) { + this.handler = handler; + } + + @Override + public boolean handlesScmType(String type) { + return SvnRepositoryHandler.TYPE_NAME.equals(type); + } + + @Override + public ScmProviderHttpServlet createDecorator(ScmProviderHttpServlet delegate) { + return new SvnGZipFilter(handler, delegate); + } +} From cd344664aafe87e230218eb3f7a31b5b3d0f2274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 14 Sep 2018 11:30:05 +0200 Subject: [PATCH 48/58] Test permission filter --- .../scm/web/filter/PermissionFilterTest.java | 74 +++++++++++++++++++ .../src/test/resources/sonia/scm/shiro.ini | 8 +- 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 scm-core/src/test/java/sonia/scm/web/filter/PermissionFilterTest.java diff --git a/scm-core/src/test/java/sonia/scm/web/filter/PermissionFilterTest.java b/scm-core/src/test/java/sonia/scm/web/filter/PermissionFilterTest.java new file mode 100644 index 0000000000..9fa65d51b8 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/web/filter/PermissionFilterTest.java @@ -0,0 +1,74 @@ +package sonia.scm.web.filter; + +import com.github.sdorra.shiro.ShiroRule; +import com.github.sdorra.shiro.SubjectAware; +import org.junit.Rule; +import org.junit.Test; +import sonia.scm.config.ScmConfiguration; +import sonia.scm.repository.Repository; +import sonia.scm.repository.spi.ScmProviderHttpServlet; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +@SubjectAware(configuration = "classpath:sonia/scm/shiro.ini") +public class PermissionFilterTest { + + public static final Repository REPOSITORY = new Repository("1", "git", "space", "name"); + + @Rule + public final ShiroRule shiroRule = new ShiroRule(); + + private final ScmProviderHttpServlet delegateServlet = mock(ScmProviderHttpServlet.class); + + private final PermissionFilter permissionFilter = new PermissionFilter(new ScmConfiguration(), delegateServlet) { + @Override + protected boolean isWriteRequest(HttpServletRequest request) { + return writeRequest; + } + }; + + private final HttpServletRequest request = mock(HttpServletRequest.class); + private final HttpServletResponse response = mock(HttpServletResponse.class); + + private boolean writeRequest = false; + + @Test + @SubjectAware(username = "reader", password = "secret") + public void shouldPassForReaderOnReadRequest() throws IOException, ServletException { + writeRequest = false; + + permissionFilter.service(request, response, REPOSITORY); + + verify(delegateServlet).service(request, response, REPOSITORY); + } + + @Test + @SubjectAware(username = "reader", password = "secret") + public void shouldBlockForReaderOnWriteRequest() throws IOException, ServletException { + writeRequest = true; + + permissionFilter.service(request, response, REPOSITORY); + + verify(response).sendError(eq(401), anyString()); + verify(delegateServlet, never()).service(request, response, REPOSITORY); + } + + @Test + @SubjectAware(username = "writer", password = "secret") + public void shouldPassForWriterOnWriteRequest() throws IOException, ServletException { + writeRequest = true; + + permissionFilter.service(request, response, REPOSITORY); + + verify(delegateServlet).service(request, response, REPOSITORY); + } +} diff --git a/scm-core/src/test/resources/sonia/scm/shiro.ini b/scm-core/src/test/resources/sonia/scm/shiro.ini index e87c81b097..fbdd35ba50 100644 --- a/scm-core/src/test/resources/sonia/scm/shiro.ini +++ b/scm-core/src/test/resources/sonia/scm/shiro.ini @@ -1,6 +1,12 @@ [users] trillian = secret, user +admin = secret, admin +writer = secret, repo_write +reader = secret, repo_read +unpriv = secret [roles] admin = * -user = something:* \ No newline at end of file +user = something:* +repo_read = "repository:read:1" +repo_write = "repository:push:1" From 37ea231340c62307fafe1358b4af24b2f6aad18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 14 Sep 2018 12:11:07 +0200 Subject: [PATCH 49/58] Cleanup smells --- .../sonia/scm/repository/RepositoryNotFoundException.java | 8 ++++---- .../java/sonia/scm/repository/api/RepositoryService.java | 2 +- .../spi/InitializingHttpScmProtocolWrapper.java | 6 +++--- .../api/v2/resources/RepositoryToRepositoryDtoMapper.java | 6 ++---- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryNotFoundException.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryNotFoundException.java index 1208596348..9dd866daa4 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryNotFoundException.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryNotFoundException.java @@ -44,8 +44,8 @@ import sonia.scm.NotFoundException; public class RepositoryNotFoundException extends NotFoundException { - /** Field description */ private static final long serialVersionUID = -6583078808900520166L; + private static final String TYPE_REPOSITORY = "repository"; //~--- constructors --------------------------------------------------------- @@ -55,14 +55,14 @@ public class RepositoryNotFoundException extends NotFoundException * */ public RepositoryNotFoundException(Repository repository) { - super("repository", repository.getName() + "/" + repository.getNamespace()); + super(TYPE_REPOSITORY, repository.getName() + "/" + repository.getNamespace()); } public RepositoryNotFoundException(String repositoryId) { - super("repository", repositoryId); + super(TYPE_REPOSITORY, repositoryId); } public RepositoryNotFoundException(NamespaceAndName namespaceAndName) { - super("repository", namespaceAndName.toString()); + super(TYPE_REPOSITORY, namespaceAndName.toString()); } } diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java index b9e1cb2a5d..452203dd09 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java @@ -363,7 +363,7 @@ public final class RepositoryService implements Closeable { public Stream getSupportedProtocols() { return protocolProviders.stream() - .filter(provider -> provider.getType().equals(getRepository().getType())) + .filter(protocolProvider -> protocolProvider.getType().equals(getRepository().getType())) .map(this::createProviderInstanceForRepository); } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java index 69ff0a83f5..0a94b1e6bf 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java @@ -44,7 +44,7 @@ public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolP if (!repository.getType().equals(getType())) { throw new IllegalArgumentException("cannot handle repository with type " + repository.getType() + " with protocol for type " + getType()); } - return new ProtocolWrapper(repository); + return new ProtocolWrapper(repository, computeBasePath()); } private String computeBasePath() { @@ -70,8 +70,8 @@ public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolP private class ProtocolWrapper extends HttpScmProtocol { - public ProtocolWrapper(Repository repository) { - super(repository, computeBasePath()); + public ProtocolWrapper(Repository repository, String basePath) { + super(repository, basePath); } @Override diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java index 6675caac88..29a4107aad 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapper.java @@ -29,8 +29,6 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper protocolLinks = repositoryService.getSupportedProtocols() - .map(protocol -> createProtocolLink(protocol, repository)) + .map(this::createProtocolLink) .collect(toList()); linksBuilder.array(protocolLinks); } @@ -63,7 +61,7 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper Date: Fri, 14 Sep 2018 15:00:09 +0200 Subject: [PATCH 50/58] Introduce interface to be used by dto mappers with Instant fields --- .../main/java/sonia/scm/api/v2/resources/BaseMapper.java | 8 +------- .../scm/api/v2/resources/InstantAttributeMapper.java | 9 +++++++++ .../api/v2/resources/ChangesetToChangesetDtoMapper.java | 2 +- .../scm/api/v2/resources/ChangesetToParentDtoMapper.java | 2 +- .../v2/resources/FileObjectToFileObjectDtoMapper.java | 2 +- 5 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/api/v2/resources/InstantAttributeMapper.java diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java index e4cf8ecb5d..d7f299d989 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java @@ -3,14 +3,8 @@ package sonia.scm.api.v2.resources; import de.otto.edison.hal.HalRepresentation; import org.mapstruct.Mapping; -import java.time.Instant; - -public abstract class BaseMapper { +public abstract class BaseMapper implements InstantAttributeMapper { @Mapping(target = "attributes", ignore = true) // We do not map HAL attributes public abstract D map(T modelObject); - - protected Instant mapTime(Long epochMilli) { - return epochMilli == null? null: Instant.ofEpochMilli(epochMilli); - } } diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/InstantAttributeMapper.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/InstantAttributeMapper.java new file mode 100644 index 0000000000..468bdfc137 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/InstantAttributeMapper.java @@ -0,0 +1,9 @@ +package sonia.scm.api.v2.resources; + +import java.time.Instant; + +public interface InstantAttributeMapper { + default Instant mapTime(Long epochMilli) { + return epochMilli == null? null: Instant.ofEpochMilli(epochMilli); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java index aa71e6bced..a189dcec97 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java @@ -23,7 +23,7 @@ import static de.otto.edison.hal.Link.link; import static de.otto.edison.hal.Links.linkingTo; @Mapper -public abstract class ChangesetToChangesetDtoMapper extends BaseMapper { +public abstract class ChangesetToChangesetDtoMapper implements InstantAttributeMapper { @Inject private RepositoryServiceFactory serviceFactory; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToParentDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToParentDtoMapper.java index 611f5e6cbb..a644058881 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToParentDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToParentDtoMapper.java @@ -16,7 +16,7 @@ import static de.otto.edison.hal.Link.link; import static de.otto.edison.hal.Links.linkingTo; @Mapper -public abstract class ChangesetToParentDtoMapper extends BaseMapper { +public abstract class ChangesetToParentDtoMapper { @Inject private ResourceLinks resourceLinks; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java index 01085958f8..97c90ace4f 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java @@ -14,7 +14,7 @@ import javax.inject.Inject; import static de.otto.edison.hal.Link.link; @Mapper -public abstract class FileObjectToFileObjectDtoMapper extends BaseMapper { +public abstract class FileObjectToFileObjectDtoMapper implements InstantAttributeMapper { @Inject private ResourceLinks resourceLinks; From 7372f7a2ab940fc45fb6b3ed52565c1925e018df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 14 Sep 2018 15:00:09 +0200 Subject: [PATCH 51/58] Introduce interface to be used by dto mappers with Instant fields --- .../scm/api/v2/resources/BaseMapper.java | 8 +-- .../v2/resources/InstantAttributeMapper.java | 9 +++ .../resources/BasicCollectionToDtoMapper.java | 56 +--------------- .../ChangesetCollectionToDtoMapper.java | 5 +- .../ChangesetToChangesetDtoMapper.java | 2 +- .../resources/ChangesetToParentDtoMapper.java | 2 +- .../FileObjectToFileObjectDtoMapper.java | 4 +- .../resources/PagedCollectionToDtoMapper.java | 64 +++++++++++++++++++ .../RepositoryCollectionToDtoMapper.java | 2 - .../resources/UserCollectionToDtoMapper.java | 2 - 10 files changed, 84 insertions(+), 70 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/api/v2/resources/InstantAttributeMapper.java create mode 100644 scm-webapp/src/main/java/sonia/scm/api/v2/resources/PagedCollectionToDtoMapper.java diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java index e4cf8ecb5d..d7f299d989 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java @@ -3,14 +3,8 @@ package sonia.scm.api.v2.resources; import de.otto.edison.hal.HalRepresentation; import org.mapstruct.Mapping; -import java.time.Instant; - -public abstract class BaseMapper { +public abstract class BaseMapper implements InstantAttributeMapper { @Mapping(target = "attributes", ignore = true) // We do not map HAL attributes public abstract D map(T modelObject); - - protected Instant mapTime(Long epochMilli) { - return epochMilli == null? null: Instant.ofEpochMilli(epochMilli); - } } diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/InstantAttributeMapper.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/InstantAttributeMapper.java new file mode 100644 index 0000000000..468bdfc137 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/InstantAttributeMapper.java @@ -0,0 +1,9 @@ +package sonia.scm.api.v2.resources; + +import java.time.Instant; + +public interface InstantAttributeMapper { + default Instant mapTime(Long epochMilli) { + return epochMilli == null? null: Instant.ofEpochMilli(epochMilli); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BasicCollectionToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BasicCollectionToDtoMapper.java index b189a22d1c..011c78b413 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BasicCollectionToDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BasicCollectionToDtoMapper.java @@ -1,73 +1,21 @@ package sonia.scm.api.v2.resources; -import de.otto.edison.hal.Embedded; import de.otto.edison.hal.HalRepresentation; -import de.otto.edison.hal.Links; -import de.otto.edison.hal.paging.NumberedPaging; -import de.otto.edison.hal.paging.PagingRel; import sonia.scm.ModelObject; import sonia.scm.PageResult; -import javax.inject.Inject; -import java.util.EnumSet; -import java.util.List; import java.util.Optional; -import java.util.function.Function; -import static com.damnhandy.uri.template.UriTemplate.fromTemplate; -import static de.otto.edison.hal.Embedded.embeddedBuilder; -import static de.otto.edison.hal.Link.link; -import static de.otto.edison.hal.Links.linkingTo; -import static de.otto.edison.hal.paging.NumberedPaging.zeroBasedNumberedPaging; -import static java.util.stream.Collectors.toList; - -abstract class BasicCollectionToDtoMapper> { - - private final String collectionName; +public class BasicCollectionToDtoMapper> extends PagedCollectionToDtoMapper { private final M entityToDtoMapper; - @Inject public BasicCollectionToDtoMapper(String collectionName, M entityToDtoMapper) { - this.collectionName = collectionName; + super(collectionName); this.entityToDtoMapper = entityToDtoMapper; } CollectionDto map(int pageNumber, int pageSize, PageResult pageResult, String selfLink, Optional createLink) { return map(pageNumber, pageSize, pageResult, selfLink, createLink, entityToDtoMapper::map); } - - CollectionDto map(int pageNumber, int pageSize, PageResult pageResult, String selfLink, Optional createLink, Function mapper) { - NumberedPaging paging = zeroBasedNumberedPaging(pageNumber, pageSize, pageResult.getOverallCount()); - List dtos = pageResult.getEntities().stream().map(mapper).collect(toList()); - CollectionDto collectionDto = new CollectionDto( - createLinks(paging, selfLink, createLink), - embedDtos(dtos)); - collectionDto.setPage(pageNumber); - collectionDto.setPageTotal(computePageTotal(pageSize, pageResult)); - return collectionDto; - } - - private int computePageTotal(int pageSize, PageResult pageResult) { - if (pageResult.getOverallCount() % pageSize > 0) { - return pageResult.getOverallCount() / pageSize + 1; - } else { - return pageResult.getOverallCount() / pageSize; - } - } - - private Links createLinks(NumberedPaging page, String selfLink, Optional createLink) { - Links.Builder linksBuilder = linkingTo() - .with(page.links( - fromTemplate(selfLink + "{?page,pageSize}"), - EnumSet.allOf(PagingRel.class))); - createLink.ifPresent(link -> linksBuilder.single(link("create", link))); - return linksBuilder.build(); - } - - private Embedded embedDtos(List dtos) { - return embeddedBuilder() - .with(collectionName, dtos) - .build(); - } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetCollectionToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetCollectionToDtoMapper.java index 3af3a1d15a..2f7ac86e14 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetCollectionToDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetCollectionToDtoMapper.java @@ -8,14 +8,14 @@ import javax.inject.Inject; import java.util.Optional; import java.util.function.Supplier; -public class ChangesetCollectionToDtoMapper extends BasicCollectionToDtoMapper { +public class ChangesetCollectionToDtoMapper extends PagedCollectionToDtoMapper { private final ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper; protected final ResourceLinks resourceLinks; @Inject public ChangesetCollectionToDtoMapper(ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper, ResourceLinks resourceLinks) { - super("changesets", changesetToChangesetDtoMapper); + super("changesets"); this.changesetToChangesetDtoMapper = changesetToChangesetDtoMapper; this.resourceLinks = resourceLinks; } @@ -32,3 +32,4 @@ public class ChangesetCollectionToDtoMapper extends BasicCollectionToDtoMapper { +public abstract class ChangesetToChangesetDtoMapper implements InstantAttributeMapper { @Inject private RepositoryServiceFactory serviceFactory; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToParentDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToParentDtoMapper.java index 611f5e6cbb..a644058881 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToParentDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToParentDtoMapper.java @@ -16,7 +16,7 @@ import static de.otto.edison.hal.Link.link; import static de.otto.edison.hal.Links.linkingTo; @Mapper -public abstract class ChangesetToParentDtoMapper extends BaseMapper { +public abstract class ChangesetToParentDtoMapper { @Inject private ResourceLinks resourceLinks; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java index 01085958f8..365c0ad4cb 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java @@ -4,6 +4,7 @@ import de.otto.edison.hal.Links; import org.mapstruct.AfterMapping; import org.mapstruct.Context; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; import sonia.scm.repository.FileObject; import sonia.scm.repository.NamespaceAndName; @@ -14,11 +15,12 @@ import javax.inject.Inject; import static de.otto.edison.hal.Link.link; @Mapper -public abstract class FileObjectToFileObjectDtoMapper extends BaseMapper { +public abstract class FileObjectToFileObjectDtoMapper implements InstantAttributeMapper { @Inject private ResourceLinks resourceLinks; + @Mapping(target = "attributes", ignore = true) // We do not map HAL attributes protected abstract FileObjectDto map(FileObject fileObject, @Context NamespaceAndName namespaceAndName, @Context String revision); abstract SubRepositoryDto mapSubrepository(SubRepository subRepository); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PagedCollectionToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PagedCollectionToDtoMapper.java new file mode 100644 index 0000000000..c05ec0b1f3 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PagedCollectionToDtoMapper.java @@ -0,0 +1,64 @@ +package sonia.scm.api.v2.resources; + +import de.otto.edison.hal.Embedded; +import de.otto.edison.hal.HalRepresentation; +import de.otto.edison.hal.Links; +import de.otto.edison.hal.paging.NumberedPaging; +import de.otto.edison.hal.paging.PagingRel; +import sonia.scm.ModelObject; +import sonia.scm.PageResult; + +import java.util.EnumSet; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +import static com.damnhandy.uri.template.UriTemplate.fromTemplate; +import static de.otto.edison.hal.Embedded.embeddedBuilder; +import static de.otto.edison.hal.Link.link; +import static de.otto.edison.hal.Links.linkingTo; +import static de.otto.edison.hal.paging.NumberedPaging.zeroBasedNumberedPaging; +import static java.util.stream.Collectors.toList; + +abstract class PagedCollectionToDtoMapper { + + private final String collectionName; + + PagedCollectionToDtoMapper(String collectionName) { + this.collectionName = collectionName; + } + + CollectionDto map(int pageNumber, int pageSize, PageResult pageResult, String selfLink, Optional createLink, Function mapper) { + NumberedPaging paging = zeroBasedNumberedPaging(pageNumber, pageSize, pageResult.getOverallCount()); + List dtos = pageResult.getEntities().stream().map(mapper).collect(toList()); + CollectionDto collectionDto = new CollectionDto( + createLinks(paging, selfLink, createLink), + embedDtos(dtos)); + collectionDto.setPage(pageNumber); + collectionDto.setPageTotal(computePageTotal(pageSize, pageResult)); + return collectionDto; + } + + private int computePageTotal(int pageSize, PageResult pageResult) { + if (pageResult.getOverallCount() % pageSize > 0) { + return pageResult.getOverallCount() / pageSize + 1; + } else { + return pageResult.getOverallCount() / pageSize; + } + } + + private Links createLinks(NumberedPaging page, String selfLink, Optional createLink) { + Links.Builder linksBuilder = linkingTo() + .with(page.links( + fromTemplate(selfLink + "{?page,pageSize}"), + EnumSet.allOf(PagingRel.class))); + createLink.ifPresent(link -> linksBuilder.single(link("create", link))); + return linksBuilder.build(); + } + + private Embedded embedDtos(List dtos) { + return embeddedBuilder() + .with(collectionName, dtos) + .build(); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionToDtoMapper.java index 77674270d7..4e52ca29ac 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionToDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryCollectionToDtoMapper.java @@ -10,8 +10,6 @@ import java.util.Optional; import static java.util.Optional.empty; import static java.util.Optional.of; -// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection. -@SuppressWarnings("squid:S3306") public class RepositoryCollectionToDtoMapper extends BasicCollectionToDtoMapper { private final ResourceLinks resourceLinks; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapper.java index c70bd268ff..464da8ee23 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapper.java @@ -10,8 +10,6 @@ import java.util.Optional; import static java.util.Optional.empty; import static java.util.Optional.of; -// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection. -@SuppressWarnings("squid:S3306") public class UserCollectionToDtoMapper extends BasicCollectionToDtoMapper { private final ResourceLinks resourceLinks; From 9a207d33135097f2f42897cf6e2e6d7846ea17b3 Mon Sep 17 00:00:00 2001 From: Mohamed Karray Date: Fri, 14 Sep 2018 16:36:02 +0200 Subject: [PATCH 52/58] review --- .../repository/api/ModificationsCommandBuilder.java | 1 - .../sonia/scm/repository/api/RepositoryService.java | 2 +- .../sonia/scm/api/v2/resources/ModificationsDto.java | 6 ------ .../api/v2/resources/ModificationsRootResource.java | 10 +--------- .../scm/api/v2/resources/ModificationsToDtoMapper.java | 2 +- ...sourceTest.java => BranchRootResourceTestBase.java} | 2 +- ...rceTest.java => ChangesetRootResourceTestBase.java} | 2 +- ...DiffResourceTest.java => DiffResourceTestBase.java} | 2 +- ...ourceTest.java => FileHistoryResourceTestBase.java} | 2 +- ...rceTest.java => ModificationsResourceTestBase.java} | 2 +- ...ceTest.java => PermissionRootResourceTestBase.java} | 2 +- ...ceTest.java => RepositoryRootResourceTestBase.java} | 2 +- ...BaseRepositoryTest.java => RepositoryTestBase.java} | 2 +- ...sourceTest.java => SourceRootResourceTestBase.java} | 2 +- ...tResourceTest.java => TagRootResourceTestBase.java} | 2 +- 15 files changed, 13 insertions(+), 28 deletions(-) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{BranchRootResourceTest.java => BranchRootResourceTestBase.java} (98%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{ChangesetRootResourceTest.java => ChangesetRootResourceTestBase.java} (99%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{DiffResourceTest.java => DiffResourceTestBase.java} (98%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{FileHistoryResourceTest.java => FileHistoryResourceTestBase.java} (99%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{ModificationsResourceTest.java => ModificationsResourceTestBase.java} (98%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{PermissionRootResourceTest.java => PermissionRootResourceTestBase.java} (99%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{RepositoryRootResourceTest.java => RepositoryRootResourceTestBase.java} (99%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{BaseRepositoryTest.java => RepositoryTestBase.java} (97%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{SourceRootResourceTest.java => SourceRootResourceTestBase.java} (98%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{TagRootResourceTest.java => TagRootResourceTestBase.java} (99%) diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ModificationsCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/ModificationsCommandBuilder.java index 954e810a65..d81088bd33 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/ModificationsCommandBuilder.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/ModificationsCommandBuilder.java @@ -28,7 +28,6 @@ import java.io.IOException; * @since 2.0 */ @Slf4j -@AllArgsConstructor @RequiredArgsConstructor @Accessors(fluent = true) public final class ModificationsCommandBuilder { diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java index 90a6248b48..9eb7427a4f 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java @@ -258,7 +258,7 @@ public final class RepositoryService implements Closeable { * by the implementation of the repository service provider. */ public ModificationsCommandBuilder getModificationsCommand() { - logger.debug("create modifications command for repository {}", repository.getName()); + logger.debug("create modifications command for repository {}",repository.getNamespaceAndName()); return new ModificationsCommandBuilder(provider.getModificationsCommand(),repository, cacheManager.getCache(ModificationsCommandBuilder.CACHE_NAME), preProcessorUtil); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsDto.java index a6b1c84f1a..9ea0359157 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsDto.java @@ -36,10 +36,4 @@ public class ModificationsDto extends HalRepresentation { return super.add(links); } - @SuppressWarnings("squid:S1185") // We want to have this method available in this package - protected HalRepresentation withEmbedded(String rel, List halRepresentations) { - return super.withEmbedded(rel, halRepresentations); - } - - } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsRootResource.java index f30163dac2..28f855f40c 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsRootResource.java @@ -34,20 +34,12 @@ public class ModificationsRootResource { /** * Get the file modifications related to a revision. * file modifications are for example: Modified, Added or Removed. - * - * @param namespace - * @param name - * @param revision - * @return - * @throws IOException - * @throws RevisionNotFoundException - * @throws RepositoryNotFoundException */ @GET @StatusCodes({ @ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 401, condition = "not authenticated / invalid credentials"), - @ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the changeset"), + @ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the modifications"), @ResponseCode(code = 404, condition = "not found, no changeset with the specified id is available in the repository"), @ResponseCode(code = 500, condition = "internal server error") }) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsToDtoMapper.java index 19242b7ea6..422d8fc4d9 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsToDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsToDtoMapper.java @@ -14,7 +14,7 @@ import javax.inject.Inject; import static de.otto.edison.hal.Links.linkingTo; @Mapper -public abstract class ModificationsToDtoMapper extends BaseMapper { +public abstract class ModificationsToDtoMapper { @Inject private ResourceLinks resourceLinks; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTestBase.java similarity index 98% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTestBase.java index e0e851c581..dbd409a23b 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTestBase.java @@ -44,7 +44,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) @Slf4j -public class BranchRootResourceTest extends BaseRepositoryTest { +public class BranchRootResourceTestBase extends RepositoryTestBase { public static final String BRANCH_PATH = "space/repo/branches/master"; public static final String BRANCH_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + BRANCH_PATH; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTestBase.java similarity index 99% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTestBase.java index 9adb53976c..a9d2541f36 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTestBase.java @@ -44,7 +44,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) @Slf4j -public class ChangesetRootResourceTest extends BaseRepositoryTest{ +public class ChangesetRootResourceTestBase extends RepositoryTestBase { public static final String CHANGESET_PATH = "space/repo/changesets/"; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTestBase.java similarity index 98% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTestBase.java index 020a099fe9..9d2c5c9e85 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTestBase.java @@ -37,7 +37,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) @Slf4j -public class DiffResourceTest extends BaseRepositoryTest { +public class DiffResourceTestBase extends RepositoryTestBase { public static final String DIFF_PATH = "space/repo/diff/"; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTestBase.java similarity index 99% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTestBase.java index 7dcf2acbd3..700534af98 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTestBase.java @@ -47,7 +47,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) @Slf4j -public class FileHistoryResourceTest extends BaseRepositoryTest { +public class FileHistoryResourceTestBase extends RepositoryTestBase { public static final String FILE_HISTORY_PATH = "space/repo/history/"; public static final String FILE_HISTORY_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + FILE_HISTORY_PATH; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTestBase.java similarity index 98% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTestBase.java index 7dfcda2578..3b4f275346 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTestBase.java @@ -39,7 +39,7 @@ import static org.mockito.Mockito.when; @Slf4j @RunWith(MockitoJUnitRunner.Silent.class) -public class ModificationsResourceTest extends BaseRepositoryTest { +public class ModificationsResourceTestBase extends RepositoryTestBase { public static final String MODIFICATIONS_PATH = "space/repo/modifications/"; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTestBase.java similarity index 99% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTestBase.java index d25cfe0a71..ef416608bb 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTestBase.java @@ -64,7 +64,7 @@ import static sonia.scm.api.v2.resources.PermissionDto.GROUP_PREFIX; password = "secret", configuration = "classpath:sonia/scm/repository/shiro.ini" ) -public class PermissionRootResourceTest extends BaseRepositoryTest { +public class PermissionRootResourceTestBase extends RepositoryTestBase { private static final String REPOSITORY_NAMESPACE = "repo_namespace"; private static final String REPOSITORY_NAME = "repo"; private static final String PERMISSION_WRITE = "repository:permissionWrite:" + REPOSITORY_NAME; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTestBase.java similarity index 99% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTestBase.java index fcc3c50058..83ed8e8356 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTestBase.java @@ -55,7 +55,7 @@ import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; password = "secret", configuration = "classpath:sonia/scm/repository/shiro.ini" ) -public class RepositoryRootResourceTest extends BaseRepositoryTest { +public class RepositoryRootResourceTestBase extends RepositoryTestBase { private Dispatcher dispatcher; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BaseRepositoryTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java similarity index 97% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/BaseRepositoryTest.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java index a219681ea5..c3cc56958a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BaseRepositoryTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java @@ -4,7 +4,7 @@ import sonia.scm.repository.RepositoryManager; import javax.inject.Provider; -public class BaseRepositoryTest { +public abstract class RepositoryTestBase { protected RepositoryToRepositoryDtoMapper repositoryToDtoMapper; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTestBase.java similarity index 98% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTestBase.java index 855ae2a861..4709ca26c3 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTestBase.java @@ -32,7 +32,7 @@ import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @RunWith(MockitoJUnitRunner.Silent.class) -public class SourceRootResourceTest extends BaseRepositoryTest { +public class SourceRootResourceTestBase extends RepositoryTestBase { private Dispatcher dispatcher; private final URI baseUri = URI.create("/"); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTestBase.java similarity index 99% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTestBase.java index ec225b782b..7192954280 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTestBase.java @@ -38,7 +38,7 @@ import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @Slf4j @RunWith(MockitoJUnitRunner.Silent.class) -public class TagRootResourceTest extends BaseRepositoryTest { +public class TagRootResourceTestBase extends RepositoryTestBase { public static final String TAG_PATH = "space/repo/tags/"; public static final String TAG_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + TAG_PATH; From 9b6a5cb96d870c655cf73a642279c7edbd6dc603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 14 Sep 2018 17:05:54 +0200 Subject: [PATCH 53/58] Rename test classes back to ...Test --- ...nchRootResourceTestBase.java => BranchRootResourceTest.java} | 2 +- ...RootResourceTestBase.java => ChangesetRootResourceTest.java} | 2 +- .../{DiffResourceTestBase.java => DiffResourceTest.java} | 2 +- ...istoryResourceTestBase.java => FileHistoryResourceTest.java} | 2 +- ...ionsResourceTestBase.java => ModificationsResourceTest.java} | 2 +- ...ootResourceTestBase.java => PermissionRootResourceTest.java} | 2 +- ...ootResourceTestBase.java => RepositoryRootResourceTest.java} | 2 +- ...rceRootResourceTestBase.java => SourceRootResourceTest.java} | 2 +- .../{TagRootResourceTestBase.java => TagRootResourceTest.java} | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{BranchRootResourceTestBase.java => BranchRootResourceTest.java} (98%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{ChangesetRootResourceTestBase.java => ChangesetRootResourceTest.java} (99%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{DiffResourceTestBase.java => DiffResourceTest.java} (98%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{FileHistoryResourceTestBase.java => FileHistoryResourceTest.java} (99%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{ModificationsResourceTestBase.java => ModificationsResourceTest.java} (98%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{PermissionRootResourceTestBase.java => PermissionRootResourceTest.java} (99%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{RepositoryRootResourceTestBase.java => RepositoryRootResourceTest.java} (99%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{SourceRootResourceTestBase.java => SourceRootResourceTest.java} (98%) rename scm-webapp/src/test/java/sonia/scm/api/v2/resources/{TagRootResourceTestBase.java => TagRootResourceTest.java} (99%) diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java similarity index 98% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTestBase.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java index dbd409a23b..c8d25ae82d 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTestBase.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java @@ -44,7 +44,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) @Slf4j -public class BranchRootResourceTestBase extends RepositoryTestBase { +public class BranchRootResourceTest extends RepositoryTestBase { public static final String BRANCH_PATH = "space/repo/branches/master"; public static final String BRANCH_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + BRANCH_PATH; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java similarity index 99% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTestBase.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java index a9d2541f36..e4e991a7d4 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTestBase.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java @@ -44,7 +44,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) @Slf4j -public class ChangesetRootResourceTestBase extends RepositoryTestBase { +public class ChangesetRootResourceTest extends RepositoryTestBase { public static final String CHANGESET_PATH = "space/repo/changesets/"; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java similarity index 98% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTestBase.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java index 9d2c5c9e85..f6a8fa4e09 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTestBase.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java @@ -37,7 +37,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) @Slf4j -public class DiffResourceTestBase extends RepositoryTestBase { +public class DiffResourceTest extends RepositoryTestBase { public static final String DIFF_PATH = "space/repo/diff/"; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java similarity index 99% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTestBase.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java index 700534af98..778682f62d 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTestBase.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java @@ -47,7 +47,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.Silent.class) @Slf4j -public class FileHistoryResourceTestBase extends RepositoryTestBase { +public class FileHistoryResourceTest extends RepositoryTestBase { public static final String FILE_HISTORY_PATH = "space/repo/history/"; public static final String FILE_HISTORY_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + FILE_HISTORY_PATH; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java similarity index 98% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTestBase.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java index 3b4f275346..f8b555f180 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTestBase.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java @@ -39,7 +39,7 @@ import static org.mockito.Mockito.when; @Slf4j @RunWith(MockitoJUnitRunner.Silent.class) -public class ModificationsResourceTestBase extends RepositoryTestBase { +public class ModificationsResourceTest extends RepositoryTestBase { public static final String MODIFICATIONS_PATH = "space/repo/modifications/"; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java similarity index 99% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTestBase.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java index ef416608bb..ac5ad07cf8 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTestBase.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java @@ -64,7 +64,7 @@ import static sonia.scm.api.v2.resources.PermissionDto.GROUP_PREFIX; password = "secret", configuration = "classpath:sonia/scm/repository/shiro.ini" ) -public class PermissionRootResourceTestBase extends RepositoryTestBase { +public class PermissionRootResourceTest extends RepositoryTestBase { private static final String REPOSITORY_NAMESPACE = "repo_namespace"; private static final String REPOSITORY_NAME = "repo"; private static final String PERMISSION_WRITE = "repository:permissionWrite:" + REPOSITORY_NAME; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java similarity index 99% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTestBase.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index 83ed8e8356..7c6deedf65 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTestBase.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -55,7 +55,7 @@ import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; password = "secret", configuration = "classpath:sonia/scm/repository/shiro.ini" ) -public class RepositoryRootResourceTestBase extends RepositoryTestBase { +public class RepositoryRootResourceTest extends RepositoryTestBase { private Dispatcher dispatcher; diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java similarity index 98% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTestBase.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java index 4709ca26c3..4759e1ebd7 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTestBase.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java @@ -32,7 +32,7 @@ import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @RunWith(MockitoJUnitRunner.Silent.class) -public class SourceRootResourceTestBase extends RepositoryTestBase { +public class SourceRootResourceTest extends RepositoryTestBase { private Dispatcher dispatcher; private final URI baseUri = URI.create("/"); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java similarity index 99% rename from scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTestBase.java rename to scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java index 7192954280..c5beaa457b 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTestBase.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java @@ -38,7 +38,7 @@ import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher; @Slf4j @RunWith(MockitoJUnitRunner.Silent.class) -public class TagRootResourceTestBase extends RepositoryTestBase { +public class TagRootResourceTest extends RepositoryTestBase { public static final String TAG_PATH = "space/repo/tags/"; public static final String TAG_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + TAG_PATH; From d2839dee86298621438d2620201c256a52de2e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 14 Sep 2018 17:17:35 +0200 Subject: [PATCH 54/58] Fix mistaken delete --- .../java/sonia/scm/api/v2/resources/TagRootResourceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java index a0e51c1066..3149182d98 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java @@ -54,7 +54,7 @@ public class TagRootResourceTest extends RepositoryTestBase { private RepositoryService repositoryService; @Mock - private TagsCommandBuilder tagsCommandBuilder + private TagsCommandBuilder tagsCommandBuilder; private TagCollectionToDtoMapper tagCollectionToDtoMapper; @InjectMocks From 37ce4fbabef4e0572af632e86c7821a6fb34ee3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 17 Sep 2018 09:15:40 +0200 Subject: [PATCH 55/58] Cleanup names, dead code and logging --- .../scm/api/v2/resources/LinkBuilder.java | 16 ++-- .../InitializingHttpScmProtocolWrapper.java | 2 +- .../resources/RepositoryRootResource.java | 40 +-------- .../scm/api/v2/resources/ResourceLinks.java | 82 +++++++++---------- .../repository/DefaultRepositoryManager.java | 3 - .../DefaultRepositoryManagerPerfTest.java | 2 - .../DefaultRepositoryManagerTest.java | 7 +- 7 files changed, 53 insertions(+), 99 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkBuilder.java b/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkBuilder.java index 13ae04b093..0797134c9f 100644 --- a/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkBuilder.java +++ b/scm-core/src/main/java/sonia/scm/api/v2/resources/LinkBuilder.java @@ -13,7 +13,7 @@ import java.util.Arrays; * builder for each method. * *

- * LinkBuilder builder = new LinkBuilder(uriInfo, MainResource.class, SubResource.class);
+ * LinkBuilder builder = new LinkBuilder(pathInfo, MainResource.class, SubResource.class);
  * Link link = builder
  *     .method("sub")
  *     .parameters("param")
@@ -24,16 +24,16 @@ import java.util.Arrays;
  */
 @SuppressWarnings("WeakerAccess") // Non-public will result in IllegalAccessError for plugins
 public class LinkBuilder {
-  private final ScmPathInfo uriInfo;
+  private final ScmPathInfo pathInfo;
   private final Class[] classes;
   private final ImmutableList calls;
 
-  public LinkBuilder(ScmPathInfo uriInfo, Class... classes) {
-    this(uriInfo, classes, ImmutableList.of());
+  public LinkBuilder(ScmPathInfo pathInfo, Class... classes) {
+    this(pathInfo, classes, ImmutableList.of());
   }
 
-  private LinkBuilder(ScmPathInfo uriInfo, Class[] classes, ImmutableList calls) {
-    this.uriInfo = uriInfo;
+  private LinkBuilder(ScmPathInfo pathInfo, Class[] classes, ImmutableList calls) {
+    this.pathInfo = pathInfo;
     this.classes = classes;
     this.calls = calls;
   }
@@ -50,7 +50,7 @@ public class LinkBuilder {
       throw new IllegalStateException("not enough methods for all classes");
     }
 
-    URI baseUri = uriInfo.getApiRestUri();
+    URI baseUri = pathInfo.getApiRestUri();
     URI relativeUri = createRelativeUri();
     return baseUri.resolve(relativeUri);
   }
@@ -60,7 +60,7 @@ public class LinkBuilder {
   }
 
   private LinkBuilder add(String method, String[] parameters) {
-    return new LinkBuilder(uriInfo, classes, appendNewCall(method, parameters));
+    return new LinkBuilder(pathInfo, classes, appendNewCall(method, parameters));
   }
 
   private ImmutableList appendNewCall(String method, String[] parameters) {
diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java
index 0a94b1e6bf..57de407edc 100644
--- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java
+++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java
@@ -64,7 +64,7 @@ public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolP
   }
 
   private String getPathFromConfiguration() {
-    logger.debug("using base path from configuration: " + scmConfiguration.getBaseUrl());
+    logger.debug("using base path from configuration: {}", scmConfiguration.getBaseUrl());
     return scmConfiguration.getBaseUrl();
   }
 
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java
index 6ad9b6257e..d5ea6c88de 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryRootResource.java
@@ -42,7 +42,6 @@ import sonia.scm.repository.Repository;
 import sonia.scm.repository.RepositoryManager;
 import sonia.scm.repository.RepositoryTypePredicate;
 import sonia.scm.template.Viewable;
-import sonia.scm.util.HttpUtil;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.GET;
@@ -98,13 +97,12 @@ public class RepositoryRootResource
   @Produces(MediaType.TEXT_HTML)
   public Viewable renderRepositoriesRoot(@Context HttpServletRequest request, @PathParam("type") final String type)
   {
-    String baseUrl = HttpUtil.getCompleteUrl(request);
     //J-
     Collection unsortedRepositories =
       Collections2.transform( 
         Collections2.filter(
             repositoryManager.getAll(), new RepositoryTypePredicate(type))
-        , new RepositoryTransformFunction(baseUrl)
+        , new RepositoryTransformFunction()
       );
     
     List repositories = Ordering.from(
@@ -130,17 +128,9 @@ public class RepositoryRootResource
   public static class RepositoryTemplateElement
   {
 
-    /**
-     * Constructs ...
-     *
-     *
-     * @param repository
-     * @param baseUrl
-     */
-    public RepositoryTemplateElement(Repository repository, String baseUrl)
+    public RepositoryTemplateElement(Repository repository)
     {
       this.repository = repository;
-      this.baseUrl = baseUrl;
     }
 
     //~--- get methods --------------------------------------------------------
@@ -169,9 +159,6 @@ public class RepositoryRootResource
 
     //~--- fields -------------------------------------------------------------
 
-    /** Field description */
-    private String baseUrl;
-
     /** Field description */
     private Repository repository;
 
@@ -217,31 +204,10 @@ public class RepositoryRootResource
   private static class RepositoryTransformFunction
     implements Function
   {
-
-    public RepositoryTransformFunction(String baseUrl)
-    {
-      this.baseUrl = baseUrl;
-    }
-
-    //~--- methods ------------------------------------------------------------
-
-    /**
-     * Method description
-     *
-     *
-     * @param repository
-     *
-     * @return
-     */
     @Override
     public RepositoryTemplateElement apply(Repository repository)
     {
-      return new RepositoryTemplateElement(repository, baseUrl);
+      return new RepositoryTemplateElement(repository);
     }
-
-    //~--- fields -------------------------------------------------------------
-
-    /** Field description */
-    private String baseUrl;
   }
 }
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java
index 59d7ccaa27..35444bb715 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java
@@ -26,8 +26,8 @@ class ResourceLinks {
   static class GroupLinks {
     private final LinkBuilder groupLinkBuilder;
 
-    GroupLinks(ScmPathInfo uriInfo) {
-      groupLinkBuilder = new LinkBuilder(uriInfo, GroupRootResource.class, GroupResource.class);
+    GroupLinks(ScmPathInfo pathInfo) {
+      groupLinkBuilder = new LinkBuilder(pathInfo, GroupRootResource.class, GroupResource.class);
     }
 
     String self(String name) {
@@ -50,8 +50,8 @@ class ResourceLinks {
   static class GroupCollectionLinks {
     private final LinkBuilder collectionLinkBuilder;
 
-    GroupCollectionLinks(ScmPathInfo uriInfo) {
-      collectionLinkBuilder = new LinkBuilder(uriInfo, GroupRootResource.class, GroupCollectionResource.class);
+    GroupCollectionLinks(ScmPathInfo pathInfo) {
+      collectionLinkBuilder = new LinkBuilder(pathInfo, GroupRootResource.class, GroupCollectionResource.class);
     }
 
     String self() {
@@ -70,8 +70,8 @@ class ResourceLinks {
   static class UserLinks {
     private final LinkBuilder userLinkBuilder;
 
-    UserLinks(ScmPathInfo uriInfo) {
-      userLinkBuilder = new LinkBuilder(uriInfo, UserRootResource.class, UserResource.class);
+    UserLinks(ScmPathInfo pathInfo) {
+      userLinkBuilder = new LinkBuilder(pathInfo, UserRootResource.class, UserResource.class);
     }
 
     String self(String name) {
@@ -94,8 +94,8 @@ class ResourceLinks {
   static class UserCollectionLinks {
     private final LinkBuilder collectionLinkBuilder;
 
-    UserCollectionLinks(ScmPathInfo uriInfo) {
-      collectionLinkBuilder = new LinkBuilder(uriInfo, UserRootResource.class, UserCollectionResource.class);
+    UserCollectionLinks(ScmPathInfo pathInfo) {
+      collectionLinkBuilder = new LinkBuilder(pathInfo, UserRootResource.class, UserCollectionResource.class);
     }
 
     String self() {
@@ -114,8 +114,8 @@ class ResourceLinks {
   static class ConfigLinks {
     private final LinkBuilder configLinkBuilder;
 
-    ConfigLinks(ScmPathInfo uriInfo) {
-      configLinkBuilder = new LinkBuilder(uriInfo, ConfigResource.class);
+    ConfigLinks(ScmPathInfo pathInfo) {
+      configLinkBuilder = new LinkBuilder(pathInfo, ConfigResource.class);
     }
 
     String self() {
@@ -133,11 +133,9 @@ class ResourceLinks {
 
   static class RepositoryLinks {
     private final LinkBuilder repositoryLinkBuilder;
-    private final ScmPathInfo uriInfo;
 
-    RepositoryLinks(ScmPathInfo uriInfo) {
-      repositoryLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class);
-      this.uriInfo = uriInfo;
+    RepositoryLinks(ScmPathInfo pathInfo) {
+      repositoryLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class);
     }
 
     String self(String namespace, String name) {
@@ -160,8 +158,8 @@ class ResourceLinks {
   static class RepositoryCollectionLinks {
     private final LinkBuilder collectionLinkBuilder;
 
-    RepositoryCollectionLinks(ScmPathInfo uriInfo) {
-      collectionLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryCollectionResource.class);
+    RepositoryCollectionLinks(ScmPathInfo pathInfo) {
+      collectionLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryCollectionResource.class);
     }
 
     String self() {
@@ -180,8 +178,8 @@ class ResourceLinks {
   static class RepositoryTypeLinks {
     private final LinkBuilder repositoryTypeLinkBuilder;
 
-    RepositoryTypeLinks(ScmPathInfo uriInfo) {
-      repositoryTypeLinkBuilder = new LinkBuilder(uriInfo, RepositoryTypeRootResource.class, RepositoryTypeResource.class);
+    RepositoryTypeLinks(ScmPathInfo pathInfo) {
+      repositoryTypeLinkBuilder = new LinkBuilder(pathInfo, RepositoryTypeRootResource.class, RepositoryTypeResource.class);
     }
 
     String self(String name) {
@@ -196,8 +194,8 @@ class ResourceLinks {
   static class RepositoryTypeCollectionLinks {
     private final LinkBuilder collectionLinkBuilder;
 
-    RepositoryTypeCollectionLinks(ScmPathInfo uriInfo) {
-      collectionLinkBuilder = new LinkBuilder(uriInfo, RepositoryTypeRootResource.class, RepositoryTypeCollectionResource.class);
+    RepositoryTypeCollectionLinks(ScmPathInfo pathInfo) {
+      collectionLinkBuilder = new LinkBuilder(pathInfo, RepositoryTypeRootResource.class, RepositoryTypeCollectionResource.class);
     }
 
     String self() {
@@ -213,8 +211,8 @@ class ResourceLinks {
   static class TagCollectionLinks {
     private final LinkBuilder tagLinkBuilder;
 
-    TagCollectionLinks(ScmPathInfo uriInfo) {
-      tagLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, TagRootResource.class);
+    TagCollectionLinks(ScmPathInfo pathInfo) {
+      tagLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, TagRootResource.class);
     }
 
     String self(String namespace, String name, String tagName) {
@@ -233,8 +231,8 @@ class ResourceLinks {
   static class DiffLinks {
     private final LinkBuilder diffLinkBuilder;
 
-    DiffLinks(ScmPathInfo uriInfo) {
-      diffLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, DiffRootResource.class);
+    DiffLinks(ScmPathInfo pathInfo) {
+      diffLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, DiffRootResource.class);
     }
 
     String self(String namespace, String name, String id) {
@@ -253,8 +251,8 @@ class ResourceLinks {
   static class BranchLinks {
     private final LinkBuilder branchLinkBuilder;
 
-    BranchLinks(ScmPathInfo uriInfo) {
-      branchLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, BranchRootResource.class);
+    BranchLinks(ScmPathInfo pathInfo) {
+      branchLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, BranchRootResource.class);
     }
 
     String self(NamespaceAndName namespaceAndName, String branch) {
@@ -273,8 +271,8 @@ class ResourceLinks {
   static class BranchCollectionLinks {
     private final LinkBuilder branchLinkBuilder;
 
-    BranchCollectionLinks(ScmPathInfo uriInfo) {
-      branchLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, BranchRootResource.class);
+    BranchCollectionLinks(ScmPathInfo pathInfo) {
+      branchLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, BranchRootResource.class);
     }
 
     String self(String namespace, String name) {
@@ -289,8 +287,8 @@ class ResourceLinks {
   static class ChangesetLinks {
     private final LinkBuilder changesetLinkBuilder;
 
-    ChangesetLinks(ScmPathInfo uriInfo) {
-      changesetLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, ChangesetRootResource.class);
+    ChangesetLinks(ScmPathInfo pathInfo) {
+      changesetLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, ChangesetRootResource.class);
     }
 
     String self(String namespace, String name, String changesetId) {
@@ -313,8 +311,8 @@ class ResourceLinks {
   static class ModificationsLinks {
     private final LinkBuilder modificationsLinkBuilder;
 
-    ModificationsLinks(ScmPathInfo uriInfo) {
-      modificationsLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, ModificationsRootResource.class);
+    ModificationsLinks(ScmPathInfo pathInfo) {
+      modificationsLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, ModificationsRootResource.class);
     }
     String self(String namespace, String name, String revision) {
       return modificationsLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("modifications").parameters().method("get").parameters(revision).href();
@@ -328,8 +326,8 @@ class ResourceLinks {
   static class FileHistoryLinks {
     private final LinkBuilder fileHistoryLinkBuilder;
 
-    FileHistoryLinks(ScmPathInfo uriInfo) {
-      fileHistoryLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, FileHistoryRootResource.class);
+    FileHistoryLinks(ScmPathInfo pathInfo) {
+      fileHistoryLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, FileHistoryRootResource.class);
     }
 
     String self(String namespace, String name, String changesetId, String path) {
@@ -345,8 +343,8 @@ class ResourceLinks {
   static class SourceLinks {
     private final LinkBuilder sourceLinkBuilder;
 
-    SourceLinks(ScmPathInfo uriInfo) {
-      sourceLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, SourceRootResource.class);
+    SourceLinks(ScmPathInfo pathInfo) {
+      sourceLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, SourceRootResource.class);
     }
 
     String self(String namespace, String name, String revision) {
@@ -378,8 +376,8 @@ class ResourceLinks {
   static class PermissionLinks {
     private final LinkBuilder permissionLinkBuilder;
 
-    PermissionLinks(ScmPathInfo uriInfo) {
-      permissionLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, PermissionRootResource.class);
+    PermissionLinks(ScmPathInfo pathInfo) {
+      permissionLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, PermissionRootResource.class);
     }
 
     String all(String namespace, String name) {
@@ -415,8 +413,8 @@ class ResourceLinks {
   static class UIPluginLinks {
     private final LinkBuilder uiPluginLinkBuilder;
 
-    UIPluginLinks(ScmPathInfo uriInfo) {
-      uiPluginLinkBuilder = new LinkBuilder(uriInfo, UIRootResource.class, UIPluginResource.class);
+    UIPluginLinks(ScmPathInfo pathInfo) {
+      uiPluginLinkBuilder = new LinkBuilder(pathInfo, UIRootResource.class, UIPluginResource.class);
     }
 
     String self(String id) {
@@ -431,8 +429,8 @@ class ResourceLinks {
   static class UIPluginCollectionLinks {
     private final LinkBuilder uiPluginCollectionLinkBuilder;
 
-    UIPluginCollectionLinks(ScmPathInfo uriInfo) {
-      uiPluginCollectionLinkBuilder = new LinkBuilder(uriInfo, UIRootResource.class, UIPluginResource.class);
+    UIPluginCollectionLinks(ScmPathInfo pathInfo) {
+      uiPluginCollectionLinkBuilder = new LinkBuilder(pathInfo, UIRootResource.class, UIPluginResource.class);
     }
 
     String self() {
diff --git a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java
index 1ddfb4a3d3..8cb325b818 100644
--- a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java
+++ b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java
@@ -82,7 +82,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
   private final KeyGenerator keyGenerator;
   private final RepositoryDAO repositoryDAO;
   private final Set types;
-  private RepositoryMatcher repositoryMatcher;
   private NamespaceStrategy namespaceStrategy;
   private final ManagerDaoAdapter managerDaoAdapter;
 
@@ -91,12 +90,10 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
   public DefaultRepositoryManager(ScmConfiguration configuration,
                                   SCMContextProvider contextProvider, KeyGenerator keyGenerator,
                                   RepositoryDAO repositoryDAO, Set handlerSet,
-                                  RepositoryMatcher repositoryMatcher,
                                   NamespaceStrategy namespaceStrategy) {
     this.configuration = configuration;
     this.keyGenerator = keyGenerator;
     this.repositoryDAO = repositoryDAO;
-    this.repositoryMatcher = repositoryMatcher;
     this.namespaceStrategy = namespaceStrategy;
 
     ThreadFactory factory = new ThreadFactoryBuilder()
diff --git a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerPerfTest.java b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerPerfTest.java
index 5f4ea2fa72..448c2561f3 100644
--- a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerPerfTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerPerfTest.java
@@ -54,7 +54,6 @@ import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 import sonia.scm.SCMContextProvider;
-import sonia.scm.Type;
 import sonia.scm.cache.GuavaCacheManager;
 import sonia.scm.config.ScmConfiguration;
 import sonia.scm.security.AuthorizationCollector;
@@ -120,7 +119,6 @@ public class DefaultRepositoryManagerPerfTest {
       keyGenerator, 
       repositoryDAO,
       handlerSet, 
-      repositoryMatcher,
       namespaceStrategy
     );
     
diff --git a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java
index d85ce12014..b7d231cf38 100644
--- a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java
@@ -61,7 +61,6 @@ import sonia.scm.store.ConfigurationStoreFactory;
 import sonia.scm.store.JAXBConfigurationStoreFactory;
 
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.Stack;
@@ -441,7 +440,7 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase {
     when(namespaceStrategy.createNamespace(Mockito.any(Repository.class))).thenAnswer(invocation -> mockedNamespace);
 
     return new DefaultRepositoryManager(configuration, contextProvider,
-      keyGenerator, repositoryDAO, handlerSet, createRepositoryMatcher(), namespaceStrategy);
+      keyGenerator, repositoryDAO, handlerSet, namespaceStrategy);
   }
 
   private void createRepository(RepositoryManager m, Repository repository) throws AlreadyExistsException {
@@ -467,10 +466,6 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase {
     assertEquals(repo.getLastModified(), other.getLastModified());
   }
 
-  private RepositoryMatcher createRepositoryMatcher() {
-    return new RepositoryMatcher(Collections.emptySet());
-  }
-
   private Repository createRepository(Repository repository) throws AlreadyExistsException {
     manager.create(repository);
     assertNotNull(repository.getId());

From babea160c36ed54b6d9d1ee06e04e20cb7dd8fdd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= 
Date: Mon, 17 Sep 2018 17:49:08 +0200
Subject: [PATCH 56/58] Incorporate peer review

---
 .../scm/repository/api/RepositoryService.java | 43 ++++++++++---------
 .../repository/api/ScmProtocolProvider.java   |  4 +-
 .../scm/repository/spi/HttpScmProtocol.java   |  2 +-
 .../InitializingHttpScmProtocolWrapper.java   | 22 +++++-----
 .../web/SvnScmProtocolProviderWrapper.java    |  3 ++
 .../scm/web/protocol/HttpProtocolServlet.java |  6 +--
 .../NamespaceAndNameFromPathExtractor.java    |  7 ++-
 .../RepositoryToRepositoryDtoMapperTest.java  |  2 +-
 .../test/java/sonia/scm/it/GitLfsITCase.java  |  3 +-
 .../sonia/scm/it/RepositoryHookITCase.java    |  6 +--
 .../web/protocol/HttpProtocolServletTest.java | 22 +++-------
 ...NamespaceAndNameFromPathExtractorTest.java |  4 +-
 12 files changed, 58 insertions(+), 66 deletions(-)

diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java
index a16001dce3..bdd6e4b320 100644
--- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java
+++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java
@@ -31,6 +31,7 @@
 
 package sonia.scm.repository.api;
 
+import lombok.extern.slf4j.Slf4j;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import sonia.scm.cache.CacheManager;
@@ -80,6 +81,7 @@ import java.util.stream.Stream;
  * @apiviz.uses sonia.scm.repository.api.UnbundleCommandBuilder
  * @since 1.17
  */
+@Slf4j
 public final class RepositoryService implements Closeable {
 
   private static final Logger logger = LoggerFactory.getLogger(RepositoryService.class);
@@ -128,7 +130,7 @@ public final class RepositoryService implements Closeable {
     try {
       provider.close();
     } catch (IOException ex) {
-      logger.error("Could not close repository service provider", ex);
+      log.error("Could not close repository service provider", ex);
     }
   }
 
@@ -141,7 +143,7 @@ public final class RepositoryService implements Closeable {
    */
   public BlameCommandBuilder getBlameCommand() {
     logger.debug("create blame command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new BlameCommandBuilder(cacheManager, provider.getBlameCommand(),
       repository, preProcessorUtil);
@@ -156,7 +158,7 @@ public final class RepositoryService implements Closeable {
    */
   public BranchesCommandBuilder getBranchesCommand() {
     logger.debug("create branches command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new BranchesCommandBuilder(cacheManager,
       provider.getBranchesCommand(), repository);
@@ -171,7 +173,7 @@ public final class RepositoryService implements Closeable {
    */
   public BrowseCommandBuilder getBrowseCommand() {
     logger.debug("create browse command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new BrowseCommandBuilder(cacheManager, provider.getBrowseCommand(),
       repository, preProcessorUtil);
@@ -187,7 +189,7 @@ public final class RepositoryService implements Closeable {
    */
   public BundleCommandBuilder getBundleCommand() {
     logger.debug("create bundle command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new BundleCommandBuilder(provider.getBundleCommand(), repository);
   }
@@ -201,7 +203,7 @@ public final class RepositoryService implements Closeable {
    */
   public CatCommandBuilder getCatCommand() {
     logger.debug("create cat command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new CatCommandBuilder(provider.getCatCommand());
   }
@@ -216,7 +218,7 @@ public final class RepositoryService implements Closeable {
    */
   public DiffCommandBuilder getDiffCommand() {
     logger.debug("create diff command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new DiffCommandBuilder(provider.getDiffCommand());
   }
@@ -232,7 +234,7 @@ public final class RepositoryService implements Closeable {
    */
   public IncomingCommandBuilder getIncomingCommand() {
     logger.debug("create incoming command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new IncomingCommandBuilder(cacheManager,
       provider.getIncomingCommand(), repository, preProcessorUtil);
@@ -247,7 +249,7 @@ public final class RepositoryService implements Closeable {
    */
   public LogCommandBuilder getLogCommand() {
     logger.debug("create log command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new LogCommandBuilder(cacheManager, provider.getLogCommand(),
       repository, preProcessorUtil);
@@ -261,7 +263,7 @@ public final class RepositoryService implements Closeable {
    *                                      by the implementation of the repository service provider.
    */
   public ModificationsCommandBuilder getModificationsCommand() {
-    logger.debug("create modifications command for repository {}",repository.getNamespaceAndName());
+    logger.debug("create modifications command for repository {}", repository.getNamespaceAndName());
     return new ModificationsCommandBuilder(provider.getModificationsCommand(),repository, cacheManager.getCache(ModificationsCommandBuilder.CACHE_NAME), preProcessorUtil);
   }
 
@@ -275,7 +277,7 @@ public final class RepositoryService implements Closeable {
    */
   public OutgoingCommandBuilder getOutgoingCommand() {
     logger.debug("create outgoing command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new OutgoingCommandBuilder(cacheManager,
       provider.getOutgoingCommand(), repository, preProcessorUtil);
@@ -291,7 +293,7 @@ public final class RepositoryService implements Closeable {
    */
   public PullCommandBuilder getPullCommand() {
     logger.debug("create pull command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new PullCommandBuilder(provider.getPullCommand(), repository);
   }
@@ -306,7 +308,7 @@ public final class RepositoryService implements Closeable {
    */
   public PushCommandBuilder getPushCommand() {
     logger.debug("create push command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new PushCommandBuilder(provider.getPushCommand());
   }
@@ -329,7 +331,7 @@ public final class RepositoryService implements Closeable {
    */
   public TagsCommandBuilder getTagsCommand() {
     logger.debug("create tags command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new TagsCommandBuilder(cacheManager, provider.getTagsCommand(),
       repository);
@@ -345,7 +347,7 @@ public final class RepositoryService implements Closeable {
    */
   public UnbundleCommandBuilder getUnbundleCommand() {
     logger.debug("create unbundle command for repository {}",
-      repository.getName());
+      repository.getNamespaceAndName());
 
     return new UnbundleCommandBuilder(provider.getUnbundleCommand(),
       repository);
@@ -372,21 +374,20 @@ public final class RepositoryService implements Closeable {
     return provider.getSupportedFeatures().contains(feature);
   }
 
-
-  public Stream getSupportedProtocols() {
+  public  Stream getSupportedProtocols() {
     return protocolProviders.stream()
       .filter(protocolProvider -> protocolProvider.getType().equals(getRepository().getType()))
-      .map(this::createProviderInstanceForRepository);
+      .map(this::createProviderInstanceForRepository);
   }
 
-  private ScmProtocol createProviderInstanceForRepository(ScmProtocolProvider protocolProvider) {
+  private  T createProviderInstanceForRepository(ScmProtocolProvider protocolProvider) {
     return protocolProvider.get(repository);
   }
 
   public  T getProtocol(Class clazz) {
-    return (T) getSupportedProtocols()
+    return this.getSupportedProtocols()
       .filter(scmProtocol -> clazz.isAssignableFrom(scmProtocol.getClass()))
       .findFirst()
-      .orElseThrow(() -> new IllegalArgumentException("no implementation for " + clazz.getName() + " and repository type " + getRepository().getType()));
+      .orElseThrow(() -> new IllegalArgumentException(String.format("no implementation for %s and repository type %s", clazz.getName(),getRepository().getType())));
   }
 }
diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocolProvider.java b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocolProvider.java
index d4be5dca59..597826676d 100644
--- a/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocolProvider.java
+++ b/scm-core/src/main/java/sonia/scm/repository/api/ScmProtocolProvider.java
@@ -4,9 +4,9 @@ import sonia.scm.plugin.ExtensionPoint;
 import sonia.scm.repository.Repository;
 
 @ExtensionPoint(multi = true)
-public interface ScmProtocolProvider {
+public interface ScmProtocolProvider {
 
   String getType();
 
-  ScmProtocol get(Repository repository);
+  T get(Repository repository);
 }
diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java
index 7ec47ea284..b933abf559 100644
--- a/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java
+++ b/scm-core/src/main/java/sonia/scm/repository/spi/HttpScmProtocol.java
@@ -27,7 +27,7 @@ public abstract class HttpScmProtocol implements ScmProtocol {
 
   @Override
   public String getUrl() {
-      return URI.create(basePath + "/").resolve("repo/" + repository.getNamespace() + "/" + repository.getName()).toASCIIString();
+      return URI.create(basePath + "/").resolve(String.format("repo/%s/%s", repository.getNamespace(), repository.getName())).toASCIIString();
   }
 
   public final void serve(HttpServletRequest request, HttpServletResponse response, ServletConfig config) throws ServletException, IOException {
diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java
index 57de407edc..c1b7229036 100644
--- a/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java
+++ b/scm-core/src/main/java/sonia/scm/repository/spi/InitializingHttpScmProtocolWrapper.java
@@ -1,7 +1,6 @@
 package sonia.scm.repository.spi;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
 import sonia.scm.api.v2.resources.ScmPathInfoStore;
 import sonia.scm.config.ScmConfiguration;
 import sonia.scm.repository.Repository;
@@ -18,20 +17,19 @@ import java.util.Optional;
 import static java.util.Optional.empty;
 import static java.util.Optional.of;
 
-public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolProvider {
-
-  private static final Logger logger = LoggerFactory.getLogger(InitializingHttpScmProtocolWrapper.class);
+@Slf4j
+public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolProvider {
 
   private final Provider delegateProvider;
-  private final Provider uriInfoStore;
+  private final Provider pathInfoStore;
   private final ScmConfiguration scmConfiguration;
 
   private volatile boolean isInitialized = false;
 
 
-  protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) {
+  protected InitializingHttpScmProtocolWrapper(Provider delegateProvider, Provider pathInfoStore, ScmConfiguration scmConfiguration) {
     this.delegateProvider = delegateProvider;
-    this.uriInfoStore = uriInfoStore;
+    this.pathInfoStore = pathInfoStore;
     this.scmConfiguration = scmConfiguration;
   }
 
@@ -42,7 +40,7 @@ public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolP
   @Override
   public HttpScmProtocol get(Repository repository) {
     if (!repository.getType().equals(getType())) {
-      throw new IllegalArgumentException("cannot handle repository with type " + repository.getType() + " with protocol for type " + getType());
+      throw new IllegalArgumentException(String.format("cannot handle repository with type %s with protocol for type %s", repository.getType(), getType()));
     }
     return new ProtocolWrapper(repository, computeBasePath());
   }
@@ -53,18 +51,18 @@ public abstract class InitializingHttpScmProtocolWrapper implements ScmProtocolP
 
   private Optional getPathFromScmPathInfoIfAvailable() {
     try {
-      ScmPathInfoStore scmPathInfoStore = uriInfoStore.get();
+      ScmPathInfoStore scmPathInfoStore = pathInfoStore.get();
       if (scmPathInfoStore != null && scmPathInfoStore.get() != null) {
         return of(scmPathInfoStore.get().getRootUri().toASCIIString());
       }
     } catch (Exception e) {
-      logger.debug("could not get ScmPathInfoStore from context", e);
+      log.debug("could not get ScmPathInfoStore from context", e);
     }
     return empty();
   }
 
   private String getPathFromConfiguration() {
-    logger.debug("using base path from configuration: {}", scmConfiguration.getBaseUrl());
+    log.debug("using base path from configuration: {}", scmConfiguration.getBaseUrl());
     return scmConfiguration.getBaseUrl();
   }
 
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java
index fb7d921742..fb3b948eb9 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java
@@ -56,6 +56,9 @@ public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWr
     }
 
     @Override
+    /**
+     * Overridden to return the systems temp directory for the key {@link PARAMETER_SVN_PARENTPATH}.
+     */
     public String getInitParameter(String key) {
       if (PARAMETER_SVN_PARENTPATH.equals(key)) {
         return System.getProperty("java.io.tmpdir");
diff --git a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java
index 2a02afe7f6..bc085d2cc7 100644
--- a/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java
+++ b/scm-webapp/src/main/java/sonia/scm/web/protocol/HttpProtocolServlet.java
@@ -38,15 +38,13 @@ public class HttpProtocolServlet extends HttpServlet {
   private final PushStateDispatcher dispatcher;
   private final UserAgentParser userAgentParser;
 
-  private final NamespaceAndNameFromPathExtractor namespaceAndNameFromPathExtractor;
 
   @Inject
-  public HttpProtocolServlet(RepositoryServiceFactory serviceFactory, Provider requestProvider, PushStateDispatcher dispatcher, UserAgentParser userAgentParser, NamespaceAndNameFromPathExtractor namespaceAndNameFromPathExtractor) {
+  public HttpProtocolServlet(RepositoryServiceFactory serviceFactory, Provider requestProvider, PushStateDispatcher dispatcher, UserAgentParser userAgentParser) {
     this.serviceFactory = serviceFactory;
     this.requestProvider = requestProvider;
     this.dispatcher = dispatcher;
     this.userAgentParser = userAgentParser;
-    this.namespaceAndNameFromPathExtractor = namespaceAndNameFromPathExtractor;
   }
 
   @Override
@@ -58,7 +56,7 @@ public class HttpProtocolServlet extends HttpServlet {
     } else {
 
       String pathInfo = request.getPathInfo();
-      Optional namespaceAndName = namespaceAndNameFromPathExtractor.fromUri(pathInfo);
+      Optional namespaceAndName = NamespaceAndNameFromPathExtractor.fromUri(pathInfo);
       if (namespaceAndName.isPresent()) {
         service(request, response, namespaceAndName.get());
       } else {
diff --git a/scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java b/scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java
index 8cbdadf942..22e2433561 100644
--- a/scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java
+++ b/scm-webapp/src/main/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractor.java
@@ -8,8 +8,11 @@ import java.util.Optional;
 import static java.util.Optional.empty;
 import static java.util.Optional.of;
 
-class NamespaceAndNameFromPathExtractor {
-  Optional fromUri(String uri) {
+final class NamespaceAndNameFromPathExtractor {
+
+  private NamespaceAndNameFromPathExtractor() {}
+
+  static Optional fromUri(String uri) {
     if (uri.startsWith(HttpUtil.SEPARATOR_PATH)) {
       uri = uri.substring(1);
     }
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java
index d60b62937e..2e6048d6b8 100644
--- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryToRepositoryDtoMapperTest.java
@@ -42,7 +42,7 @@ public class RepositoryToRepositoryDtoMapperTest {
   private final URI baseUri = URI.create("http://example.com/base/");
   @SuppressWarnings("unused") // Is injected
   private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
-  @Mock//(answer = Answers.RETURNS_DEEP_STUBS)
+  @Mock
   private RepositoryServiceFactory serviceFactory;
   @Mock
   private RepositoryService repositoryService;
diff --git a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java
index 611a584485..c55a33c39a 100644
--- a/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java
+++ b/scm-webapp/src/test/java/sonia/scm/it/GitLfsITCase.java
@@ -251,8 +251,7 @@ public class GitLfsITCase {
   }
 
   private String createBatchUrl() {
-    String url = BASE_URL + "repo/" + repository.getNamespace() + "/" + repository.getName();
-    return url + "/info/lfs/objects/batch";
+    return String.format("%srepo/%s/%s/info/lfs/objects/batch", BASE_URL, repository.getNamespace(), repository.getName());
   }
 
   private byte[] download(ScmClient client, LfsObject lfsObject) throws IOException {
diff --git a/scm-webapp/src/test/java/sonia/scm/it/RepositoryHookITCase.java b/scm-webapp/src/test/java/sonia/scm/it/RepositoryHookITCase.java
index 6ad8342d8a..d74769bf39 100644
--- a/scm-webapp/src/test/java/sonia/scm/it/RepositoryHookITCase.java
+++ b/scm-webapp/src/test/java/sonia/scm/it/RepositoryHookITCase.java
@@ -172,7 +172,7 @@ public class RepositoryHookITCase extends AbstractAdminITCaseBase
     Thread.sleep(WAIT_TIME);
     
     // check debug servlet that only one commit is present
-    WebResource.Builder wr = createResource(client, "../debug/" + repository.getNamespace() + "/" + repository.getName() + "/post-receive/last");
+    WebResource.Builder wr = createResource(client, String.format("../debug/%s/%s/post-receive/last", repository.getNamespace(), repository.getName()));
     DebugHookData data = wr.get(DebugHookData.class);
     assertNotNull(data);
     assertThat(data.getChangesets(), allOf(
@@ -195,8 +195,8 @@ public class RepositoryHookITCase extends AbstractAdminITCaseBase
   
   private RepositoryClient createRepositoryClient() throws IOException 
   {
-    return REPOSITORY_CLIENT_FACTORY.create(repositoryType, 
-      IntegrationTestUtil.BASE_URL + "repo/" + repository.getNamespace() + "/" + repository.getName(),
+    return REPOSITORY_CLIENT_FACTORY.create(repositoryType,
+      String.format("%srepo/%s/%s", IntegrationTestUtil.BASE_URL, repository.getNamespace(), repository.getName()),
       IntegrationTestUtil.ADMIN_USERNAME, IntegrationTestUtil.ADMIN_PASSWORD, workingCopy
     );
   }
diff --git a/scm-webapp/src/test/java/sonia/scm/web/protocol/HttpProtocolServletTest.java b/scm-webapp/src/test/java/sonia/scm/web/protocol/HttpProtocolServletTest.java
index 2d4f6b639b..077020f60c 100644
--- a/scm-webapp/src/test/java/sonia/scm/web/protocol/HttpProtocolServletTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/web/protocol/HttpProtocolServletTest.java
@@ -20,20 +20,16 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import java.util.Optional;
 
-import static java.util.Optional.of;
 import static org.mockito.AdditionalMatchers.not;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
 public class HttpProtocolServletTest {
 
-  private static final NamespaceAndName EXISTING_REPO = new NamespaceAndName("space", "repo");
 
   @Mock
   private RepositoryServiceFactory serviceFactory;
@@ -44,8 +40,6 @@ public class HttpProtocolServletTest {
   @Mock
   private UserAgentParser userAgentParser;
   @Mock
-  private NamespaceAndNameFromPathExtractor namespaceAndNameFromPathExtractor;
-  @Mock
   private Provider requestProvider;
 
   @InjectMocks
@@ -68,8 +62,9 @@ public class HttpProtocolServletTest {
     initMocks(this);
     when(userAgentParser.parse(request)).thenReturn(userAgent);
     when(userAgent.isBrowser()).thenReturn(false);
-    when(serviceFactory.create(not(eq(EXISTING_REPO)))).thenThrow(RepositoryNotFoundException.class);
-    when(serviceFactory.create(EXISTING_REPO)).thenReturn(repositoryService);
+    NamespaceAndName existingRepo = new NamespaceAndName("space", "repo");
+    when(serviceFactory.create(not(eq(existingRepo)))).thenThrow(RepositoryNotFoundException.class);
+    when(serviceFactory.create(existingRepo)).thenReturn(repositoryService);
     when(requestProvider.get()).thenReturn(httpServletRequest);
   }
 
@@ -85,8 +80,7 @@ public class HttpProtocolServletTest {
 
   @Test
   public void shouldHandleBadPaths() throws IOException, ServletException {
-    when(request.getPathInfo()).thenReturn("/space/name");
-    when(namespaceAndNameFromPathExtractor.fromUri("/space/name")).thenReturn(Optional.empty());
+    when(request.getPathInfo()).thenReturn("/illegal");
 
     servlet.service(request, response);
 
@@ -94,11 +88,8 @@ public class HttpProtocolServletTest {
   }
 
   @Test
-  public void shouldHandleNotExistingRepository() throws RepositoryNotFoundException, IOException, ServletException {
-    when(request.getPathInfo()).thenReturn("/space/name");
-    NamespaceAndName namespaceAndName = new NamespaceAndName("space", "name");
-    when(namespaceAndNameFromPathExtractor.fromUri("/space/name")).thenReturn(of(namespaceAndName));
-    doThrow(new RepositoryNotFoundException(namespaceAndName)).when(serviceFactory).create(namespaceAndName);
+  public void shouldHandleNotExistingRepository() throws IOException, ServletException {
+    when(request.getPathInfo()).thenReturn("/not/exists");
 
     servlet.service(request, response);
 
@@ -109,7 +100,6 @@ public class HttpProtocolServletTest {
   public void shouldDelegateToProvider() throws RepositoryNotFoundException, IOException, ServletException {
     when(request.getPathInfo()).thenReturn("/space/name");
     NamespaceAndName namespaceAndName = new NamespaceAndName("space", "name");
-    when(namespaceAndNameFromPathExtractor.fromUri("/space/name")).thenReturn(of(namespaceAndName));
     doReturn(repositoryService).when(serviceFactory).create(namespaceAndName);
     Repository repository = new Repository();
     when(repositoryService.getRepository()).thenReturn(repository);
diff --git a/scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java b/scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java
index 3018870e7d..0998010069 100644
--- a/scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/web/protocol/NamespaceAndNameFromPathExtractorTest.java
@@ -38,7 +38,7 @@ public class NamespaceAndNameFromPathExtractorTest {
     return dynamicTest(
       "should extract correct namespace and name for path " + path,
       () -> {
-        Optional namespaceAndName = new NamespaceAndNameFromPathExtractor().fromUri(path);
+        Optional namespaceAndName = NamespaceAndNameFromPathExtractor.fromUri(path);
 
         assertThat(namespaceAndName.get()).isEqualTo(new NamespaceAndName("space", "repo"));
       }
@@ -59,7 +59,7 @@ public class NamespaceAndNameFromPathExtractorTest {
     return dynamicTest(
       "should not fail for wrong path " + path,
       () -> {
-        Optional namespaceAndName = new NamespaceAndNameFromPathExtractor().fromUri(path);
+        Optional namespaceAndName = NamespaceAndNameFromPathExtractor.fromUri(path);
 
         assertThat(namespaceAndName.isPresent()).isFalse();
       }

From 88506b06339e3c6be3a6143cbc93f9b42b4d4b4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= 
Date: Tue, 18 Sep 2018 08:58:03 +0200
Subject: [PATCH 57/58] Remove unnecessary annotations

---
 .../src/main/java/sonia/scm/web/Git.java           | 14 --------------
 .../scm/web/GitScmProtocolProviderWrapper.java     |  3 +--
 .../main/java/sonia/scm/web/GitServletModule.java  |  3 ---
 .../src/main/java/sonia/scm/web/Hg.java            | 14 --------------
 .../scm/web/HgScmProtocolProviderWrapper.java      |  3 +--
 .../main/java/sonia/scm/web/HgServletModule.java   |  3 ---
 .../src/main/java/sonia/scm/web/Svn.java           | 14 --------------
 .../scm/web/SvnScmProtocolProviderWrapper.java     |  2 +-
 .../main/java/sonia/scm/web/SvnServletModule.java  |  3 ---
 9 files changed, 3 insertions(+), 56 deletions(-)
 delete mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/Git.java
 delete mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/Hg.java
 delete mode 100644 scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/Svn.java

diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/Git.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/Git.java
deleted file mode 100644
index 8bcf85c8f0..0000000000
--- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/Git.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package sonia.scm.web;
-
-import com.google.inject.BindingAnnotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@BindingAnnotation
-@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
-@Retention(RetentionPolicy.RUNTIME)
-@interface Git {
-}
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java
index 8273f3950e..be97e7e539 100644
--- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitScmProtocolProviderWrapper.java
@@ -5,7 +5,6 @@ import sonia.scm.config.ScmConfiguration;
 import sonia.scm.plugin.Extension;
 import sonia.scm.repository.GitRepositoryHandler;
 import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper;
-import sonia.scm.repository.spi.ScmProviderHttpServlet;
 
 import javax.inject.Inject;
 import javax.inject.Provider;
@@ -15,7 +14,7 @@ import javax.inject.Singleton;
 @Extension
 public class GitScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper {
   @Inject
-  public GitScmProtocolProviderWrapper(@Git Provider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) {
+  public GitScmProtocolProviderWrapper(ScmGitServletProvider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) {
     super(servletProvider, uriInfoStore, scmConfiguration);
   }
 
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java
index 8c7b30572f..e731e01a62 100644
--- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java
@@ -41,7 +41,6 @@ import org.mapstruct.factory.Mappers;
 import sonia.scm.api.v2.resources.GitConfigDtoToGitConfigMapper;
 import sonia.scm.api.v2.resources.GitConfigToGitConfigDtoMapper;
 import sonia.scm.plugin.Extension;
-import sonia.scm.repository.spi.ScmProviderHttpServlet;
 import sonia.scm.web.lfs.LfsBlobStoreFactory;
 
 /**
@@ -64,7 +63,5 @@ public class GitServletModule extends ServletModule
 
     bind(GitConfigDtoToGitConfigMapper.class).to(Mappers.getMapper(GitConfigDtoToGitConfigMapper.class).getClass());
     bind(GitConfigToGitConfigDtoMapper.class).to(Mappers.getMapper(GitConfigToGitConfigDtoMapper.class).getClass());
-
-    bind(ScmProviderHttpServlet.class).annotatedWith(Git.class).toProvider(ScmGitServletProvider.class);
   }
 }
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/Hg.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/Hg.java
deleted file mode 100644
index e4fe39e724..0000000000
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/Hg.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package sonia.scm.web;
-
-import com.google.inject.BindingAnnotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@BindingAnnotation
-@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
-@Retention(RetentionPolicy.RUNTIME)
-@interface Hg {
-}
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java
index 72382f16bc..37360a5845 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgScmProtocolProviderWrapper.java
@@ -5,7 +5,6 @@ import sonia.scm.config.ScmConfiguration;
 import sonia.scm.plugin.Extension;
 import sonia.scm.repository.HgRepositoryHandler;
 import sonia.scm.repository.spi.InitializingHttpScmProtocolWrapper;
-import sonia.scm.repository.spi.ScmProviderHttpServlet;
 
 import javax.inject.Inject;
 import javax.inject.Provider;
@@ -15,7 +14,7 @@ import javax.inject.Singleton;
 @Extension
 public class HgScmProtocolProviderWrapper extends InitializingHttpScmProtocolWrapper {
   @Inject
-  public HgScmProtocolProviderWrapper(@Hg Provider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) {
+  public HgScmProtocolProviderWrapper(HgCGIServletProvider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) {
     super(servletProvider, uriInfoStore, scmConfiguration);
   }
 
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java
index 6949be2ea9..ba9ae3a0b9 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java
@@ -46,7 +46,6 @@ import sonia.scm.plugin.Extension;
 import sonia.scm.repository.HgContext;
 import sonia.scm.repository.HgContextProvider;
 import sonia.scm.repository.HgHookManager;
-import sonia.scm.repository.spi.ScmProviderHttpServlet;
 
 /**
  *
@@ -80,8 +79,6 @@ public class HgServletModule extends ServletModule
     bind(HgConfigPackagesToDtoMapper.class).to(Mappers.getMapper(HgConfigPackagesToDtoMapper.class).getClass());
     bind(HgConfigInstallationsToDtoMapper.class);
 
-    bind(ScmProviderHttpServlet.class).annotatedWith(Hg.class).toProvider(HgCGIServletProvider.class);
-
     // bind servlets
     serve(MAPPING_HOOK).with(HgHookCallbackServlet.class);
   }
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/Svn.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/Svn.java
deleted file mode 100644
index 744c1a0939..0000000000
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/Svn.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package sonia.scm.web;
-
-import com.google.inject.BindingAnnotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@BindingAnnotation
-@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
-@Retention(RetentionPolicy.RUNTIME)
-@interface Svn {
-}
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java
index fb3b948eb9..ba7d5e875a 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnScmProtocolProviderWrapper.java
@@ -27,7 +27,7 @@ public class SvnScmProtocolProviderWrapper extends InitializingHttpScmProtocolWr
   }
 
   @Inject
-  public SvnScmProtocolProviderWrapper(@Svn Provider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) {
+  public SvnScmProtocolProviderWrapper(SvnDAVServletProvider servletProvider, Provider uriInfoStore, ScmConfiguration scmConfiguration) {
     super(servletProvider, uriInfoStore, scmConfiguration);
   }
 
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java
index cd47a2fa44..8526d6380a 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/web/SvnServletModule.java
@@ -38,7 +38,6 @@ import org.mapstruct.factory.Mappers;
 import sonia.scm.api.v2.resources.SvnConfigDtoToSvnConfigMapper;
 import sonia.scm.api.v2.resources.SvnConfigToSvnConfigDtoMapper;
 import sonia.scm.plugin.Extension;
-import sonia.scm.repository.spi.ScmProviderHttpServlet;
 
 /**
  *
@@ -51,7 +50,5 @@ public class SvnServletModule extends ServletModule {
   protected void configureServlets() {
     bind(SvnConfigDtoToSvnConfigMapper.class).to(Mappers.getMapper(SvnConfigDtoToSvnConfigMapper.class).getClass());
     bind(SvnConfigToSvnConfigDtoMapper.class).to(Mappers.getMapper(SvnConfigToSvnConfigDtoMapper.class).getClass());
-
-    bind(ScmProviderHttpServlet.class).annotatedWith(Svn.class).toProvider(SvnDAVServletProvider.class);
   }
 }

From 039d752b493d53ace427a008075d4f063780e87c Mon Sep 17 00:00:00 2001
From: Mohamed Karray 
Date: Tue, 18 Sep 2018 07:44:51 +0000
Subject: [PATCH 58/58] Close branch feature/repository_protocol_v2