From b69b715a66e5f13a4db275c5deae9cc76ee1db78 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 29 Apr 2014 09:54:17 +0200 Subject: [PATCH] DATAREST-292, DATAREST-296 - RepositoryLinkBuilder now honors absolute base URIs. In case a base URI is an absolute one, we now rely on only the base URI as foundation for all links created. Relative base URIs are considered are considered an amendment to the current server base up until the servlet mapping. The latter allows to create a dedicated URI namespace for Spring Data REST exposed resources. --- .../webmvc/support/RepositoryLinkBuilder.java | 43 +++++++++++- .../support/RepositoryLinkBuildUnitTests.java | 70 +++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/RepositoryLinkBuildUnitTests.java diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryLinkBuilder.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryLinkBuilder.java index 7738f79ab..7b2459225 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryLinkBuilder.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryLinkBuilder.java @@ -20,30 +20,69 @@ import java.net.URI; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.rest.core.mapping.ResourceMetadata; import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkBuilder; import org.springframework.hateoas.core.LinkBuilderSupport; +import org.springframework.util.Assert; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder; +/** + * {@link LinkBuilder} to be able to create links pointing to repositories. + * + * @author Oliver Gierke + */ public class RepositoryLinkBuilder extends LinkBuilderSupport { private final ResourceMetadata metadata; + /** + * Creates a new {@link RepositoryLinkBuilder} with the given {@link ResourceMetadata} and base {@link URI}. + * + * @param metadata must not be {@literal null}. + * @param baseUri + */ public RepositoryLinkBuilder(ResourceMetadata metadata, URI baseUri) { this(metadata, prepareBuilder(baseUri, metadata)); } + /** + * Creates a new {@link RepositoryLinkBuilder} with the given {@link ResourceMetadata} and + * {@link UriComponentsBuilder}. + * + * @param metadata must not be {@literal null}. + * @param builder must not be {@literal null}. + */ private RepositoryLinkBuilder(ResourceMetadata metadata, UriComponentsBuilder builder) { super(builder); + Assert.notNull(metadata, "ResourceMetadata must not be null!"); this.metadata = metadata; } + /** + * Prepares the {@link UriComponentsBuilder} pointing to the root repository path. If the given URI is an absolute one + * (starting with {@code http://}) we'll use it as is and fallback to lookup the root URI of the current request's + * servlet mapping appending the base URI. + * + * @param baseUri must not be {@literal null}. + * @param metadata must not be {@literal null}. + * @return + */ private static UriComponentsBuilder prepareBuilder(URI baseUri, ResourceMetadata metadata) { - ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromCurrentServletMapping(); - return builder.path(baseUri.toString()).path(metadata.getPath().toString()); + Assert.notNull(baseUri, "Base URI must not be null!"); + Assert.notNull(metadata, "ResourceMetadata must not be null!"); + + UriComponentsBuilder builder = baseUri.isAbsolute() ? UriComponentsBuilder.fromUri(baseUri) + : ServletUriComponentsBuilder.fromCurrentServletMapping().path(baseUri.toString()); + + return builder.path(metadata.getPath().toString()); } + /* + * (non-Javadoc) + * @see org.springframework.hateoas.core.LinkBuilderSupport#slash(java.lang.Object) + */ @Override public RepositoryLinkBuilder slash(Object object) { diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/RepositoryLinkBuildUnitTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/RepositoryLinkBuildUnitTests.java new file mode 100644 index 000000000..b7ae2cdb5 --- /dev/null +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/RepositoryLinkBuildUnitTests.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.rest.webmvc.support; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import java.net.URI; + +import org.junit.Test; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; +import org.springframework.data.rest.core.mapping.MappingResourceMetadata; +import org.springframework.data.rest.core.mapping.ResourceMetadata; +import org.springframework.data.rest.webmvc.WebTestUtils; +import org.springframework.data.rest.webmvc.mongodb.Profile; +import org.springframework.hateoas.Link; + +/** + * Unit tests for {@link RepositoryLinkBuilder}. + * + * @author Oliver Gierke + */ +public class RepositoryLinkBuildUnitTests { + + MongoMappingContext context = new MongoMappingContext(); + + /** + * @see DATAREST-292 + */ + @Test + public void usesCurrentRequestsUriBaseForRelativeBaseUri() { + + WebTestUtils.initWebTest(); + + assertRootUriFor("api", "http://localhost/api/profile"); + } + + /** + * @see DATAREST-292, DATAREST-296 + */ + @Test + public void usesBaseUriOnlyIfItIsAbsolute() { + assertRootUriFor("http://foobar/api", "http://foobar/api/profile"); + } + + private void assertRootUriFor(String baseUri, String expectedUri) { + + MongoPersistentEntity entity = context.getPersistentEntity(Profile.class); + ResourceMetadata metadata = new MappingResourceMetadata(entity); + + RepositoryLinkBuilder builder = new RepositoryLinkBuilder(metadata, URI.create(baseUri)); + Link link = builder.withSelfRel(); + + assertThat(link.getHref(), is(expectedUri)); + } +}