Skip to content

Commit

Permalink
Added utility methods for base URL (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
yelouarti authored Oct 18, 2024
1 parent 194f72c commit c0f7be0
Show file tree
Hide file tree
Showing 21 changed files with 466 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .github/badges/jacoco.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion .github/badges/version.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 0 additions & 6 deletions .github/scripts/generate_version_badge.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,3 @@ BADGE_URL="https://img.shields.io/badge/${PROPERTY_NAME}-${ENCODED_VALUE}-bright
# Download the badge
curl -o ./.github/badges/${PROPERTY_NAME}.svg $BADGE_URL

# Commit the updated badge
#git config --local user.email "action@github.com"
#git config --local user.name "GitHub Action"
#git add badges/${PROPERTY_NAME}.svg
#git commit -m "Update ${PROPERTY_NAME} badge to ${PROPERTY_VALUE}"
#git push
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.11.0]

### Added

* Added utilities for base url
* Added local publishing to build.gradle

### Changed

* In assemblers all buildSelfLink skeleton methods assign the SELF relation per default

### Fixed

* Fix exception in SpringControllerLinkBuilder when controller had no default constructor

## [0.10.0]

### Added
Expand Down
30 changes: 23 additions & 7 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

testImplementation 'org.springframework:spring-test'
testImplementation 'io.projectreactor:reactor-test'
testImplementation 'org.junit.jupiter:junit-jupiter-api'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2'
Expand All @@ -39,7 +40,10 @@ dependencies {
}

bootJar.enabled = false
jar.enabled = true
jar {
enabled = true
archiveClassifier = ''
}

jacocoTestReport {
reports {
Expand Down Expand Up @@ -100,10 +104,27 @@ publishing {
}
}
}

repositories {
mavenLocal()
}
}

signing {
useInMemoryPgpKeys(System.getenv('SIGNING_KEY'), System.getenv('SIGNING_PASSWORD'))
def signingKey = System.getenv('SIGNING_KEY')
def signingKeyId = System.getenv('SIGNING_KEY_ID')
def signingPassword = System.getenv('SIGNING_PASSWORD')

if (signingKey?.trim()) {
println 'Using in-memory PGP keys for signing.'
useInMemoryPgpKeys(signingKey, signingPassword)
} else {
println 'Using GPG command-line tool for signing.'
useGpgCmd()
ext['signing.keyId'] = signingKeyId
ext['signing.password'] = signingPassword
ext['signing.gnupg.options'] = ['--batch', '--yes', '--pinentry-mode', 'loopback']
}
sign publishing.publications.mavenJava
}

Expand Down Expand Up @@ -201,8 +222,3 @@ tasks.register('assembleBundle', Zip) {
}
}
}





2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
group=de.kamillionlabs
name=hateoflux
version=0.10.0
version=0.11.0
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public sealed interface SealedEmbeddedLinkAssemblerModule<EmbeddedT> permits Emb
*/
default List<Link> buildLinksForEmbedded(EmbeddedT embedded, ServerWebExchange exchange) {
List<Link> links = new ArrayList<>();
links.add(buildSelfLinkForEmbedded(embedded, exchange));
links.add(buildSelfLinkForEmbedded(embedded, exchange).withSelfRel());
links.addAll(buildOtherLinksForEmbedded(embedded, exchange));
return links;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public sealed interface SealedEntityLinkAssemblerModule<EntityT>
*/
default List<Link> buildLinksForEntity(EntityT entityToWrap, ServerWebExchange exchange) {
List<Link> links = new ArrayList<>();
links.add(buildSelfLinkForEntity(entityToWrap, exchange));
links.add(buildSelfLinkForEntity(entityToWrap, exchange).withSelfRel());
links.addAll(buildOtherLinksForEntity(entityToWrap, exchange));
return links;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ default HalListWrapper<EntityT, EmbeddedT> createEmptyListWrapper(@NonNull Strin
*/
default List<Link> buildLinksForEntityList(ServerWebExchange exchange) {
List<Link> links = new ArrayList<>();
links.add(buildSelfLinkForEntityList(exchange));
links.add(buildSelfLinkForEntityList(exchange).withSelfRel());
links.addAll(buildOtherLinksForEntityList(exchange));
return links;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2024 kamillion-suite contributors
*
* 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.
*
* @since 17.10.2024
*/

package de.kamillionlabs.hateoflux.linkbuilder;

import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.NonNull;
import org.springframework.web.server.ServerWebExchange;

import java.net.URI;

/**
* Utility class for extracting the base URL from a server web exchange or HTTP request.
*
* @author Younes El Ouarti
*/
public class BaseUrlExtractor {

private BaseUrlExtractor() {
}

/**
* Extracts the base URL from the given {@link ServerWebExchange}.
*
* @param exchange
* the server web exchange
* @return the base URL as a string
*/
public static String extractBaseUrl(@NonNull ServerWebExchange exchange) {
return extractBaseUrl(exchange.getRequest());
}

/**
* Extracts the base URL from the given {@link ServerHttpRequest}.
*
* @param request
* the server HTTP request
* @return the base URL as a string
*/
public static String extractBaseUrl(@NonNull ServerHttpRequest request) {
URI uri = request.getURI();

String scheme = uri.getScheme();
String host = uri.getHost();
int port = uri.getPort();

boolean includePort = (port != -1 && ((scheme.equals("http") && port != 80)
|| (scheme.equals("https") && port != 443)));
String portPart = includePort ? ":" + port : "";

return scheme + "://" + host + portPart;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import de.kamillionlabs.hateoflux.model.hal.Composite;
import de.kamillionlabs.hateoflux.model.link.Link;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.objenesis.SpringObjenesis;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
Expand Down Expand Up @@ -87,7 +90,7 @@ private SpringControllerLinkBuilder() {
* @param methodRef
* a functional interface implementation that references the controller method
* for which the link is to be generated.
* @return a {@link Link} object that encapsulates the URI pointing to the entity as exposed by the
* @return an expanded {@link Link} object that encapsulates the URI pointing to the entity as exposed by the
* controller method referenced
*
* @throws IllegalArgumentException
Expand All @@ -108,8 +111,17 @@ public static <ControllerT> Link linkTo(Class<ControllerT> controllerClass,

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(controllerClass);
enhancer.setCallback(interceptor);
ControllerT proxy = (ControllerT) enhancer.create();
// Set the callback types instead of actual callbacks
enhancer.setCallbackType(MethodInterceptor.class);

// Create the proxy class without instantiating it
Class<?> proxyClass = enhancer.createClass();

SpringObjenesis objenesis = new SpringObjenesis();
ControllerT proxy = (ControllerT) objenesis.newInstance(proxyClass);

// Set the callback on the proxy instance
((Factory) proxy).setCallback(0, interceptor);

// Invoke the method reference, which will capture the method details
methodRef.invoke(proxy);
Expand Down
45 changes: 43 additions & 2 deletions src/main/java/de/kamillionlabs/hateoflux/model/link/Link.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.kamillionlabs.hateoflux.linkbuilder.BaseUrlExtractor;
import de.kamillionlabs.hateoflux.linkbuilder.UriExpander;
import de.kamillionlabs.hateoflux.linkbuilder.UriTemplateData;
import lombok.Getter;
import lombok.Value;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;

import java.util.Map;

Expand Down Expand Up @@ -322,7 +325,7 @@ public Link withHreflang(String hreflang) {
*
* @param uriPart
* The URI part to be appended.
* @return A new instance of {@link Link} with the appended URI part.
* @return A new {@link Link} object with the appended URI part.
*/
public Link slash(String uriPart) {
StringBuffer newHref = new StringBuffer(this.href);
Expand All @@ -343,13 +346,51 @@ public Link slash(String uriPart) {
}


/**
* Extracts the base URL from the given {@link ServerHttpRequest} and prepends it to the current {@code href}.
*
* @param httpRequest
* The request that provides the data to extract the base URL from.
* @return A new {@link Link} object with the prepended base URL.
*/
public Link prependBaseUrl(ServerHttpRequest httpRequest) {
String baseUrl = BaseUrlExtractor.extractBaseUrl(httpRequest);
return prependBaseUrl(baseUrl);
}

/**
* Extracts the base URL from the given {@link ServerWebExchange} and prepends it to the current {@code href}.
*
* @param exchangeWithBaseUrl
* The exchange that provides the data to extract the base URL from.
* @return A new {@link Link} object with the prepended base URL.
*/
public Link prependBaseUrl(ServerWebExchange exchangeWithBaseUrl) {
String baseUrl = BaseUrlExtractor.extractBaseUrl(exchangeWithBaseUrl);
return prependBaseUrl(baseUrl);
}

/**
* Prepends the provided base URL to the current {@code href}.
*
* @param baseUrl
* Base URL to prepend to current link
* @return A new {@link Link} object with the prepended base URL.
*/
public Link prependBaseUrl(String baseUrl) {
String currentHref = this.getHref();
Link finalHref = Link.of(baseUrl).slash(currentHref);
return this.withHref(finalHref.getHref());
}


/**
* Utility method that serves as a proxy for {@link UriExpander#expand(String, Object...)}. Please refer to
* mentioned method for full documentation.
*
* @param parameters
* parameters to expand in templated href
* @return the expanded or original URI if expansion is not applicable
* @return The expanded or original URI if expansion is not applicable
*/
public Link expand(Object... parameters) {
String newHref = UriExpander.expand(this.href, parameters);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@ static class AssemblerUnderTest implements EmbeddingHalWrapperAssembler<Book, Au

@Override
public Link buildSelfLinkForEntityList(ServerWebExchange exchange) {
return Link.linkAsSelfOf("entity-list/self/link");
return Link.of("entity-list/self/link");
}

@Override
public Link buildSelfLinkForEntity(Book entityToWrap, ServerWebExchange exchange) {
return Link.linkAsSelfOf("entity/self/link");
return Link.of("entity/self/link");
}

@Override
public Link buildSelfLinkForEmbedded(Author embedded, ServerWebExchange exchange) {
return Link.linkAsSelfOf("embedded/self/link");
return Link.of("embedded/self/link");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ static class AssemblerUnderTest implements FlatHalWrapperAssembler<Book> {

@Override
public Link buildSelfLinkForEntityList(ServerWebExchange exchange) {
return Link.linkAsSelfOf("entity-list/self/link");
return Link.of("entity-list/self/link");
}

@Override
public Link buildSelfLinkForEntity(Book entityToWrap, ServerWebExchange exchange) {
return Link.linkAsSelfOf("entity/self/link");
return Link.of("entity/self/link");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ static class AssemblerUnderTest implements ReactiveEmbeddingHalWrapperAssembler<

@Override
public Link buildSelfLinkForEntityList(ServerWebExchange exchange) {
return Link.linkAsSelfOf("reactive/entity-list/self/link");
return Link.of("reactive/entity-list/self/link");
}

@Override
public Link buildSelfLinkForEntity(Book entityToWrap, ServerWebExchange exchange) {
return Link.linkAsSelfOf("reactive/entity/self/link");
return Link.of("reactive/entity/self/link");
}

@Override
public Link buildSelfLinkForEmbedded(Author embedded, ServerWebExchange exchange) {
return Link.linkAsSelfOf("reactive/embedded/self/link");
return Link.of("reactive/embedded/self/link");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ static class AssemblerUnderTest implements ReactiveFlatHalWrapperAssembler<Book>

@Override
public Link buildSelfLinkForEntityList(ServerWebExchange exchange) {
return Link.linkAsSelfOf("reactive/entity-list/self/link");
return Link.of("reactive/entity-list/self/link");
}

@Override
public Link buildSelfLinkForEntity(Book entityToWrap, ServerWebExchange exchange) {
return Link.linkAsSelfOf("reactive/entity/self/link");
return Link.of("reactive/entity/self/link");
}
}

Expand Down
Loading

0 comments on commit c0f7be0

Please sign in to comment.