-FROM eclipse-temurin:17 as builder
+FROM eclipse-temurin:21 as builder
COPY . ./preferences
WORKDIR /preferences
RUN ./gradlew assemble
-FROM eclipse-temurin:17-jre-alpine
+FROM eclipse-temurin:21-jre-alpine
USER nobody
ARG JAR_FILE=/preferences/app/build/libs/app-*.jar
COPY --from=builder ${JAR_FILE} app.jar
-EXPOSE 9080
-ENTRYPOINT [ "java","-jar","app.jar" ]
\ No newline at end of file
+EXPOSE 9001
+ENTRYPOINT [ "java","-jar","app.jar" ]
plugins {
- id 'java'
- id 'idea'
- id 'application'
- id 'io.spring.dependency-management'
- id 'org.springframework.boot'
- id 'jacoco'
- id 'com.gorylenko.gradle-git-properties'
+ id 'java'
+ id 'idea'
+ id 'application'
+ id 'io.spring.dependency-management'
+ id 'org.springframework.boot'
+ id 'jacoco'
+ id 'com.gorylenko.gradle-git-properties'
+ id 'com.diffplug.spotless'
}
def appVersion = getAppVersion()
version = appVersion
springBoot {
- buildInfo {
- properties {
- artifact = "onap-portal-ng-preferences"
- version = appVersion
- group = "org.onap.portalng"
- name = "Portal-ng user preferences service"
- }
- }
+ buildInfo {
+ properties {
+ artifact = "onap-portal-ng-preferences"
+ version = appVersion
+ group = "org.onap.portalng"
+ name = "Portal-ng user preferences service"
+ }
+ }
}
application {
}
configurations {
- compileOnly {
- extendsFrom annotationProcessor
- }
+ compileOnly {
+ extendsFrom annotationProcessor
+ }
}
repositories {
- mavenCentral()
- maven {
- url = "https://plugins.gradle.org/m2/"
- }
+ mavenCentral()
+ maven {
+ url = "https://plugins.gradle.org/m2/"
+ }
}
ext {
problemVersion = '0.27.1'
- logstashLogbackVersion = '8.1'
- springCloudWiremockVersion = '4.1.5'
- micrometerVersion = '1.0.0'
- liquibaseCoreVersion = '4.31.1'
+ swaggerAnnotationsVersion = '2.2.34'
}
dependencies {
- implementation project(':openapi')
- implementation 'org.springframework.boot:spring-boot-starter-actuator'
- implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
- implementation 'org.springframework.boot:spring-boot-starter-security'
- implementation 'org.springframework.boot:spring-boot-starter-webflux'
- implementation 'org.springframework.boot:spring-boot-starter-validation'
- implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
- implementation "org.zalando:problem:$problemVersion"
- implementation "net.logstash.logback:logstash-logback-encoder:$logstashLogbackVersion"
-
- implementation "org.liquibase:liquibase-core:$liquibaseCoreVersion"
- implementation 'org.postgresql:postgresql'
-
- implementation 'io.micrometer:micrometer-tracing'
- implementation 'io.micrometer:micrometer-tracing-bridge-otel'
- implementation 'io.opentelemetry:opentelemetry-exporter-zipkin'
- implementation 'io.micrometer:micrometer-registry-prometheus'
- implementation 'org.apache.commons:commons-lang3:3.17.0'
-
- compileOnly 'org.projectlombok:lombok'
-
- developmentOnly 'org.springframework.boot:spring-boot-devtools'
-
- annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
- annotationProcessor 'org.projectlombok:lombok'
-
- testImplementation 'org.springframework.boot:spring-boot-starter-test'
- testImplementation 'io.projectreactor:reactor-test'
- testImplementation 'io.rest-assured:rest-assured'
- testImplementation "org.springframework.cloud:spring-cloud-contract-wiremock:$springCloudWiremockVersion"
- testImplementation "org.testcontainers:postgresql"
- testCompileOnly 'org.projectlombok:lombok'
- testAnnotationProcessor 'org.projectlombok:lombok'
+ implementation project(':openapi')
+ implementation 'org.springframework.boot:spring-boot-starter-actuator'
+ implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
+ implementation 'org.springframework.boot:spring-boot-starter-security'
+ implementation 'org.springframework.boot:spring-boot-starter-webflux'
+ implementation 'org.springframework.boot:spring-boot-starter-validation'
+ implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
+ implementation "org.zalando:problem:$problemVersion"
+
+ implementation "org.liquibase:liquibase-core"
+ implementation 'org.postgresql:postgresql'
+
+ implementation 'io.micrometer:micrometer-tracing'
+ implementation 'io.micrometer:micrometer-tracing-bridge-otel'
+ implementation 'io.opentelemetry:opentelemetry-exporter-zipkin'
+ implementation 'io.micrometer:micrometer-registry-prometheus'
+
+ compileOnly 'org.projectlombok:lombok'
+ compileOnly "io.swagger.core.v3:swagger-annotations:$swaggerAnnotationsVersion"
+
+ developmentOnly 'org.springframework.boot:spring-boot-devtools'
+
+ annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
+ annotationProcessor 'org.projectlombok:lombok'
+
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
+ testImplementation 'org.springframework.security:spring-security-test'
+ testImplementation 'io.projectreactor:reactor-test'
+ testImplementation "org.testcontainers:postgresql"
+ testCompileOnly 'org.projectlombok:lombok'
+ testCompileOnly "io.swagger.core.v3:swagger-annotations:$swaggerAnnotationsVersion"
+ testAnnotationProcessor 'org.projectlombok:lombok'
}
test {
- useJUnitPlatform()
- finalizedBy(jacocoTestReport)
+ useJUnitPlatform()
+ finalizedBy(jacocoTestReport)
}
jacocoTestReport {
- reports {
- xml.required = true
- }
+ reports {
+ xml.required = true
+ }
}
// avoid generating X.X.X-plain.jar
}
def String getAppVersion() {
- Properties versionProperties = getVersionProperties()
- String major = versionProperties.getProperty('major')
- String minor = versionProperties.getProperty('minor')
- String patch = versionProperties.getProperty('patch')
- return major + '.' + minor + '.' + patch
+ Properties versionProperties = getVersionProperties()
+ String major = versionProperties.getProperty('major')
+ String minor = versionProperties.getProperty('minor')
+ String patch = versionProperties.getProperty('patch')
+ return major + '.' + minor + '.' + patch
}
def Properties getVersionProperties() {
- def versionProperties = new Properties()
- rootProject.file('version.properties').withInputStream {
- versionProperties.load(it)
- }
- return versionProperties
+ def versionProperties = new Properties()
+ rootProject.file('version.properties').withInputStream {
+ versionProperties.load(it)
+ }
+ return versionProperties
}
gitProperties {
- // if .git directory is on the same level as the root project
- dotGitDirectory = project.rootProject.layout.projectDirectory.dir(".git")
+ // if .git directory is on the same level as the root project
+ dotGitDirectory = project.rootProject.layout.projectDirectory.dir(".git")
+}
+
+spotless {
+ java {
+ googleJavaFormat()
+ }
}
package org.onap.portalng.preferences;
-import org.onap.portalng.preferences.logging.LoggerProperties;
import org.onap.portalng.preferences.configuration.PreferencesConfig;
+import org.onap.portalng.preferences.logging.LoggerProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@EnableConfigurationProperties({PreferencesConfig.class, LoggerProperties.class})
public class PreferencesApplication {
- public static void main(String[] args) {
- SpringApplication.run(PreferencesApplication.class, args);
- }
-
+ public static void main(String[] args) {
+ SpringApplication.run(PreferencesApplication.class, args);
+ }
}
package org.onap.portalng.preferences.configuration;
+import java.time.Clock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import java.time.Clock;
-
@Configuration
public class BeansConfig {
@Bean
package org.onap.portalng.preferences.configuration;
+import java.util.List;
import org.onap.portalng.preferences.util.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
-import java.util.List;
-
@Component
public class LogInterceptor implements WebFilter {
- public static final String EXCHANGE_CONTEXT_ATTRIBUTE = ServerWebExchangeContextFilter.class.getName()
- + ".EXCHANGE_CONTEXT";
+ public static final String EXCHANGE_CONTEXT_ATTRIBUTE =
+ ServerWebExchangeContextFilter.class.getName() + ".EXCHANGE_CONTEXT";
@Value("${logger.traceIdHeaderName}")
public static String X_REQUEST_ID;
List<String> xRequestIdList = exchange.getRequest().getHeaders().get(X_REQUEST_ID);
if (xRequestIdList != null && !xRequestIdList.isEmpty()) {
String xRequestId = xRequestIdList.get(0);
- Logger.requestLog(
- exchange.getRequest().getMethod(), exchange.getRequest().getURI());
+ Logger.requestLog(exchange.getRequest().getMethod(), exchange.getRequest().getURI());
exchange.getResponse().getHeaders().add(X_REQUEST_ID, xRequestId);
- exchange.getResponse().beforeCommit(() -> {
- Logger.responseLog(exchange.getResponse().getStatusCode());
- return Mono.empty();
- });
+ exchange
+ .getResponse()
+ .beforeCommit(
+ () -> {
+ Logger.responseLog(exchange.getResponse().getStatusCode());
+ return Mono.empty();
+ });
}
return chain
package org.onap.portalng.preferences.configuration;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
import jakarta.validation.constraints.NotBlank;
-import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.validation.annotation.Validated;
-@Data
+@Validated
@ConfigurationProperties("preferences")
-public class PreferencesConfig {
-
- @NotBlank
- private final String realm;
-
-}
+public record PreferencesConfig(@NotBlank String realm) {}
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
-/**
- * Configures the access control of the API endpoints.
- */
+/** Configures the access control of the API endpoints. */
// https://hantsy.github.io/spring-reactive-sample/security/config.html
@EnableWebFluxSecurity
@Configuration
@Bean
public SecurityWebFilterChain springSecurityWebFilterChain(ServerHttpSecurity http) {
- return http
- .httpBasic(basic -> basic.disable())
+ return http.httpBasic(basic -> basic.disable())
.formLogin(login -> login.disable())
.csrf(csrf -> csrf.disable())
.cors(Customizer.withDefaults())
- .authorizeExchange(exchange -> exchange
- .pathMatchers(HttpMethod.GET, "/actuator/**").permitAll()
- .anyExchange().authenticated())
+ .authorizeExchange(
+ exchange ->
+ exchange
+ .pathMatchers(HttpMethod.GET, "/actuator/**")
+ .permitAll()
+ .anyExchange()
+ .authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
.build();
}
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;
-
import reactor.core.publisher.Mono;
@RestController
@Override
public Mono<ResponseEntity<PreferencesApiDto>> getPreferences(ServerWebExchange exchange) {
- return IdTokenExchange
- .extractUserId(exchange)
- .flatMap(userid -> preferencesService.getPreferences(userid)
- .map(ResponseEntity::ok))
- .onErrorResume(ProblemException.class, ex -> {
- Logger.errorLog("user preferences", null, "preferences");
- return Mono.error(ex);
- })
+ return IdTokenExchange.extractUserId(exchange)
+ .flatMap(userid -> preferencesService.getPreferences(userid).map(ResponseEntity::ok))
+ .onErrorResume(
+ ProblemException.class,
+ ex -> {
+ Logger.errorLog("user preferences", null, "preferences");
+ return Mono.error(ex);
+ })
.onErrorReturn(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
}
@Override
- public Mono<ResponseEntity<PreferencesApiDto>> savePreferences(Mono<PreferencesApiDto> preferences,
- ServerWebExchange exchange) {
- return IdTokenExchange
- .extractUserId(exchange)
- .flatMap(userid -> preferences
- .flatMap(pref -> preferencesService
- .savePreferences(userid, pref)))
+ public Mono<ResponseEntity<PreferencesApiDto>> savePreferences(
+ Mono<PreferencesApiDto> preferences, ServerWebExchange exchange) {
+ return IdTokenExchange.extractUserId(exchange)
+ .flatMap(
+ userid -> preferences.flatMap(pref -> preferencesService.savePreferences(userid, pref)))
.map(ResponseEntity::ok)
- .onErrorResume(ProblemException.class, ex -> {
- Logger.errorLog("user preferences", null, "preferences");
- return Mono.error(ex);
- })
+ .onErrorResume(
+ ProblemException.class,
+ ex -> {
+ Logger.errorLog("user preferences", null, "preferences");
+ return Mono.error(ex);
+ })
.onErrorReturn(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
}
@Override
- public Mono<ResponseEntity<PreferencesApiDto>> updatePreferences(Mono<PreferencesApiDto> preferences,
- ServerWebExchange exchange) {
+ public Mono<ResponseEntity<PreferencesApiDto>> updatePreferences(
+ Mono<PreferencesApiDto> preferences, ServerWebExchange exchange) {
return savePreferences(preferences, exchange);
}
-
}
package org.onap.portalng.preferences.entities;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.util.Map;
-
-import org.hibernate.annotations.JdbcTypeCode;
-import org.hibernate.type.SqlTypes;
-
import com.fasterxml.jackson.databind.JsonNode;
-
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
+import lombok.Getter;
+import lombok.Setter;
+import org.hibernate.annotations.JdbcTypeCode;
+import org.hibernate.type.SqlTypes;
@Entity
@Getter
@Setter
@Table(name = "preferences")
public class PreferencesDto {
- @Id
- private String userId;
+ @Id private String userId;
@JdbcTypeCode(SqlTypes.JSON)
private JsonNode properties;
-
}
-
package org.onap.portalng.preferences.exception;
+import java.net.URI;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import org.zalando.problem.Status;
import org.zalando.problem.StatusType;
-import java.net.URI;
-
/** The default preferences exception */
@Data
@Builder
@Builder.Default private final String detail = "Please add more details here";
@Builder.Default private final URI instance = null;
-
}
+/*
+ *
+ * Copyright (c) 2023. Deutsche Telekom AG
+ *
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ *
+ */
+
package org.onap.portalng.preferences.logging;
import java.util.List;
-
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("logger")
public record LoggerProperties(
- String traceIdHeaderName,
- Boolean enabled, List<String> excludePaths) {
-}
\ No newline at end of file
+ String traceIdHeaderName, Boolean enabled, List<String> excludePaths) {}
package org.onap.portalng.preferences.logging;
+import java.util.Map;
+import java.util.function.BiConsumer;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.MDC;
-import java.util.Map;
-import java.util.function.BiConsumer;
-
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class LoggingHelper {
public static void error(
package org.onap.portalng.preferences.logging;
+import java.time.Duration;
+import java.time.LocalDateTime;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
-import java.time.Duration;
-import java.time.LocalDateTime;
-
@Slf4j
@Component
@RequiredArgsConstructor
boolean loggingDisabled = loggerProperties.enabled() == null || !loggerProperties.enabled();
boolean urlShouldBeSkipped =
- WebExchangeUtils.matchUrlsPatternsToPath(loggerProperties.excludePaths(), exchange.getRequest().getPath().value());
+ WebExchangeUtils.matchUrlsPatternsToPath(
+ loggerProperties.excludePaths(), exchange.getRequest().getPath().value());
return loggingDisabled || urlShouldBeSkipped;
}
package org.onap.portalng.preferences.logging;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange;
-import java.util.EnumMap;
-import java.util.List;
-import java.util.Map;
-
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class WebExchangeUtils {
private static final String DEFAULT_TRACE_ID = "REQUEST_ID_IS_NOT_SET";
import org.onap.portalng.preferences.entities.PreferencesDto;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+@Repository
public interface PreferencesRepository extends JpaRepository<PreferencesDto, String> {
+ @Modifying
+ @Transactional
+ @Query(value = "TRUNCATE TABLE preferences", nativeQuery = true)
+ void truncateTable();
}
package org.onap.portalng.preferences.services;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.RequiredArgsConstructor;
import org.onap.portalng.preferences.entities.PreferencesDto;
import org.onap.portalng.preferences.exception.ProblemException;
import org.onap.portalng.preferences.openapi.model.PreferencesApiDto;
import org.onap.portalng.preferences.repository.PreferencesRepository;
import org.onap.portalng.preferences.util.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import lombok.RequiredArgsConstructor;
import reactor.core.publisher.Mono;
@RequiredArgsConstructor
private final ObjectMapper objectMapper;
public Mono<PreferencesApiDto> getPreferences(String userId) {
- return Mono.just(repository
- .findById(userId)
- .orElse(defaultPreferences()))
+ return Mono.just(repository.findById(userId).orElse(defaultPreferences()))
.map(this::toPreferences);
}
return Mono.just(repository.save(preferencesDto))
.map(this::toPreferences)
- .onErrorResume(ProblemException.class, ex -> {
- Logger.errorLog("user prefrences", userId, "preferences");
- return Mono.error(ex);
- });
-
+ .onErrorResume(
+ ProblemException.class,
+ ex -> {
+ Logger.errorLog("user prefrences", userId, "preferences");
+ return Mono.error(ex);
+ });
}
private PreferencesApiDto toPreferences(PreferencesDto preferencesDto) {
}
/**
- * Get a Preferences object that is initialised with an empty string.
- * This is a) for convenience to not handle 404 on the consuming side and
- * b) for security reasons
+ * Get a Preferences object that is initialised with an empty string. This is a) for convenience
+ * to not handle 404 on the consuming side and b) for security reasons
*
* @return PreferencesDto
*/
import reactor.core.publisher.Mono;
/**
- * Represents a function that handles the
- * <a href="https://jwt.io/introduction">JWT</a> identity token.
- * Use this to check if the incoming requests are authorized to call the given
- * endpoint
+ * Represents a function that handles the <a href="https://jwt.io/introduction">JWT</a> identity
+ * token. Use this to check if the incoming requests are authorized to call the given endpoint
*/
-
public final class IdTokenExchange {
public static final String JWT_CLAIM_USERID = "sub";
- private IdTokenExchange() {
+ private IdTokenExchange() {}
- }
/**
* Extract the <code>userId</code> from the given {@link ServerWebExchange}
+ *
* @param exchange the ServerWebExchange that contains information about the incoming request
* @return the id of the user
*/
public static Mono<String> extractUserId(ServerWebExchange exchange) {
- return exchange.getPrincipal().cast(JwtAuthenticationToken.class)
+ return exchange
+ .getPrincipal()
+ .cast(JwtAuthenticationToken.class)
.map(auth -> auth.getToken().getClaimAsString(JWT_CLAIM_USERID));
}
}
package org.onap.portalng.preferences.util;
import java.net.URI;
-
+import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatusCode;
-import lombok.extern.slf4j.Slf4j;
-
@Slf4j
public class Logger {
- private Logger() {
- }
+ private Logger() {}
public static void requestLog(HttpMethod methode, URI path) {
log.info("Preferences - request - {} {}", methode, path);
}
public static void errorLog(String msg, String id, String app) {
- log.info(
- "Preferences - error - {} {} not found in {}", msg, id, app);
+ log.info("Preferences - error - {} {} not found in {}", msg, id, app);
}
- public static void errorLog(
- String msg, String id, String app, String errorDetails) {
+ public static void errorLog(String msg, String id, String app, String errorDetails) {
log.info(
"Preferences - error - {} {} not found in {} error message: {}",
msg,
-server:
- port: 9001
- address: 0.0.0.0
-
spring:
- jackson:
- serialization:
- # needed for serializing objects of type object
- FAIL_ON_EMPTY_BEANS: false
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: http://localhost:8080/realms/ONAP/protocol/openid-connect/certs #Keycloak Endpoint
datasource:
- url: jdbc:postgresql://localhost:5441/preferences
+ url: jdbc:postgresql://localhost:5432/preferences
username: postgres
password: postgres
jpa:
realm: ONAP
management:
- endpoints:
- web:
- exposure:
- include: "*"
- info:
- build:
- enabled: true
- env:
- enabled: true
- git:
- enabled: true
- java:
- enabled: true
+ zipkin:
+ tracing:
+ endpoint: http://localhost:9411/api/v2/spans
server:
- port: 9001
- address: 0.0.0.0
+ port: 9001
+ address: 0.0.0.0
spring:
application:
jackson:
serialization:
# needed for serializing objects of type object
- FAIL_ON_EMPTY_BEANS: false
+ fail-on-empty-beans: false
security:
oauth2:
resourceserver:
change-log: "classpath:/db/changelog.xml"
preferences:
- realm: ${KEYCLOAK_REALM}
+ realm: ${KEYCLOAK_REALM}
management:
endpoints:
web:
enabled: true
excludePaths:
- "/actuator/**"
+
+logging:
+ structured:
+ format:
+ console: logstash
+ level:
+ root: info
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration scan="true">
- <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
- <level>${LOGBACK_LEVEL:-info}</level>
- </filter>
- <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
- </appender>
-
- <root level="all">
- <appender-ref ref="stdout"/>
- </root>
-</configuration>
*
*/
-package org.onap.portalng.preferences.actuator;
+package org.onap.portalng.preferences;
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
-import org.onap.portalng.preferences.BaseIntegrationTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.availability.ApplicationAvailability;
import org.springframework.boot.availability.LivenessState;
import org.springframework.boot.availability.ReadinessState;
+import org.springframework.boot.test.context.SpringBootTest;
-class ActuatorIntegrationTest extends BaseIntegrationTest {
-
- @Autowired private ApplicationAvailability applicationAvailability;
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class AcutatorIntegrationTest {
+ @Autowired private ApplicationAvailability applicationAvailability;
- @Test
- void livenessProbeIsAvailable() {
- assertThat(applicationAvailability.getLivenessState()).isEqualTo(LivenessState.CORRECT);
- }
-
- @Test
- void readinessProbeIsAvailable() {
-
- assertThat(applicationAvailability.getReadinessState())
- .isEqualTo(ReadinessState.ACCEPTING_TRAFFIC);
- }
+ @Test
+ void livenessProbeIsAvailable() {
+ assertEquals(applicationAvailability.getLivenessState(), LivenessState.CORRECT);
+ }
+
+ @Test
+ void readinessProbeIsAvailable() {
+ assertEquals(applicationAvailability.getReadinessState(), ReadinessState.ACCEPTING_TRAFFIC);
+ }
}
+++ /dev/null
-/*
- *
- * Copyright (c) 2022. Deutsche Telekom AG
- *
- * 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.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- *
- */
-
-package org.onap.portalng.preferences;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.github.tomakehurst.wiremock.client.WireMock;
-import com.nimbusds.jose.jwk.JWKSet;
-import org.onap.portalng.preferences.util.IdTokenExchange;
-import org.onap.portalng.preferences.configuration.PreferencesConfig;
-import io.restassured.RestAssured;
-import io.restassured.filter.log.RequestLoggingFilter;
-import io.restassured.filter.log.ResponseLoggingFilter;
-import io.restassured.specification.RequestSpecification;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.server.LocalServerPort;
-import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-
-import java.util.List;
-import java.util.UUID;
-
-/** Base class for all tests that has the common config including port, realm, logging and auth. */
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@AutoConfigureWireMock(port = 0)
-public abstract class BaseIntegrationTest {
-
- @LocalServerPort protected int port;
- @Value("${preferences.realm}")
- protected String realm;
-
- @Autowired protected ObjectMapper objectMapper;
- @Autowired private TokenGenerator tokenGenerator;
- @Autowired protected PreferencesConfig preferencesConfig;
-
- @BeforeAll
- public static void setup() {
- RestAssured.filters(new RequestLoggingFilter(), new ResponseLoggingFilter());
- }
-
- /** Mocks the OIDC auth flow. */
- @BeforeEach
- public void mockAuth() {
- WireMock.reset();
-
- WireMock.stubFor(
- WireMock.get(
- WireMock.urlMatching(
- "/realms/%s/protocol/openid-connect/certs".formatted(realm)))
- .willReturn(
- WireMock.aResponse()
- .withHeader("Content-Type", JWKSet.MIME_TYPE)
- .withBody(tokenGenerator.getJwkSet().toString())));
-
- final TokenGenerator.TokenGeneratorConfig config =
- TokenGenerator.TokenGeneratorConfig.builder().port(port).realm(realm).sub("test-user").build();
-
- WireMock.stubFor(
- WireMock.post(
- WireMock.urlMatching(
- "/realms/%s/protocol/openid-connect/token".formatted(realm)))
- .withBasicAuth("test", "test")
- .withRequestBody(WireMock.containing("grant_type=client_credentials"))
- .willReturn(
- WireMock.aResponse()
- .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE)
- .withBody(
- objectMapper
- .createObjectNode()
- .put("token_type", "bearer")
- .put("access_token", tokenGenerator.generateToken(config))
- .put("expires_in", config.getExpireIn().getSeconds())
- .put("refresh_token", tokenGenerator.generateToken(config))
- .put("refresh_expires_in", config.getExpireIn().getSeconds())
- .put("not-before-policy", 0)
- .put("session_state", UUID.randomUUID().toString())
- .put("scope", "email profile")
- .toString())));
- }
-
- /**
- * Builds an OAuth2 configuration including the roles, port and realm. This config can be used to
- * generate OAuth2 access tokens.
- *
- * @param sub the userId
- * @param roles the roles used for RBAC
- * @return the OAuth2 configuration
- */
- protected TokenGenerator.TokenGeneratorConfig getTokenGeneratorConfig(String sub, List<String> roles) {
- return TokenGenerator.TokenGeneratorConfig.builder()
- .port(port)
- .sub(sub)
- .realm(realm)
- .roles(roles)
- .build();
- }
-
- /** Get a RequestSpecification that does not have an Identity header. */
- protected RequestSpecification unauthenticatedRequestSpecification() {
- return RestAssured.given().port(port);
- }
-
- /**
- * Object to store common attributes of requests that are going to be made. Adds an Identity
- * header for the <code>onap_admin</code> role to the request.
- * @return the definition of the incoming request (northbound)
- */
- protected RequestSpecification requestSpecification() {
- final String idToken = tokenGenerator.generateToken(getTokenGeneratorConfig("test-user", List.of("foo")));
-
- return unauthenticatedRequestSpecification()
- .auth()
- .preemptive()
- .oauth2(idToken)
- .header(HttpHeaders.AUTHORIZATION, "Bearer " + idToken);
- }
-
- /**
- * Object to store common attributes of requests that are going to be made. Adds an Identity
- * header for the <code>onap_admin</code> role to the request.
- * @param userId the userId that should be contained in the incoming request
- * @return the definition of the incoming request (northbound)
- */
- protected RequestSpecification requestSpecification(String userId) {
- final String idToken = tokenGenerator.generateToken(getTokenGeneratorConfig(userId, List.of("foo")));
-
- return unauthenticatedRequestSpecification()
- .auth()
- .preemptive()
- .oauth2(idToken)
- .header(HttpHeaders.AUTHORIZATION, "Bearer " + idToken);
- }
-}
--- /dev/null
+/*
+ *
+ * Copyright (c) 2025. Deutsche Telekom AG
+ *
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ *
+ */
+
+package org.onap.portalng.preferences;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.Map;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.onap.portalng.preferences.openapi.model.PreferencesApiDto;
+import org.onap.portalng.preferences.repository.PreferencesRepository;
+import org.onap.portalng.preferences.services.PreferencesService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ApplicationContext;
+import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class PreferencesControllerIntegrationTest {
+
+ @Autowired private WebTestClient webTestClient;
+ @Autowired private ObjectMapper objectMapper;
+
+ @BeforeEach
+ void setup(
+ final ApplicationContext context,
+ @Autowired final PreferencesRepository preferencesRepository) {
+ webTestClient =
+ WebTestClient.bindToApplicationContext(context)
+ .apply(SecurityMockServerConfigurers.springSecurity())
+ .configureClient()
+ .build();
+ preferencesRepository.truncateTable();
+ }
+
+ @Test
+ void testAuthenticatedAccess() {
+ webTestClient
+ .mutateWith(SecurityMockServerConfigurers.mockJwt().jwt(jwt -> jwt.claim("sub", "user")))
+ .get()
+ .uri("/v1/preferences")
+ .exchange()
+ .expectStatus()
+ .isOk();
+ }
+
+ @Test
+ void testUnauthorizedAccess() {
+ webTestClient.get().uri("/v1/preferences").exchange().expectStatus().isUnauthorized();
+ }
+
+ @Test
+ void thatDefaultUserPreferencesCanBeRetrieved() throws Exception {
+ final var prefs = getDefaultPreferencesApiDto();
+ webTestClient
+ .mutateWith(SecurityMockServerConfigurers.mockJwt().jwt(jwt -> jwt.claim("sub", "user")))
+ .get()
+ .uri("/v1/preferences")
+ .exchange()
+ .expectStatus()
+ .isOk()
+ .expectBody()
+ .json(objectMapper.writeValueAsString(prefs));
+ }
+
+ @Test
+ void thatSimpleUserPreferencesCanBeSaved() throws Exception {
+ final var prefs = getSimplePreferencesApiDto();
+ webTestClient
+ .mutateWith(SecurityMockServerConfigurers.mockJwt().jwt(jwt -> jwt.claim("sub", "user")))
+ .post()
+ .uri("/v1/preferences")
+ .bodyValue(prefs)
+ .exchange()
+ .expectStatus()
+ .isOk()
+ .expectBody()
+ .json(objectMapper.writeValueAsString(prefs));
+ }
+
+ @Test
+ void thatSimpleUserPreferencesCanBeUpdated() throws Exception {
+ final var prefs = getSimplePreferencesApiDto();
+ webTestClient
+ .mutateWith(SecurityMockServerConfigurers.mockJwt().jwt(jwt -> jwt.claim("sub", "user")))
+ .put()
+ .uri("/v1/preferences")
+ .bodyValue(prefs)
+ .exchange()
+ .expectStatus()
+ .isOk()
+ .expectBody()
+ .json(objectMapper.writeValueAsString(prefs));
+ }
+
+ @Test
+ void thatComplexUserPreferencesCanBeRetrieved(
+ @Autowired final PreferencesService preferencesService) throws Exception {
+ final var prefs = getComplexPreferencesApiDto();
+ preferencesService.savePreferences("user", prefs);
+ webTestClient
+ .mutateWith(SecurityMockServerConfigurers.mockJwt().jwt(jwt -> jwt.claim("sub", "user")))
+ .get()
+ .uri("/v1/preferences")
+ .exchange()
+ .expectStatus()
+ .isOk()
+ .expectBody()
+ .json(objectMapper.writeValueAsString(prefs));
+ }
+
+ private PreferencesApiDto getDefaultPreferencesApiDto() {
+ return new PreferencesApiDto().properties(null);
+ }
+
+ private PreferencesApiDto getSimplePreferencesApiDto() throws Exception {
+ return new PreferencesApiDto()
+ .properties(objectMapper.readValue("{\"appStarter\":\"appStarterValue\"}", Map.class));
+ }
+
+ private PreferencesApiDto getComplexPreferencesApiDto() throws Exception {
+ return new PreferencesApiDto()
+ .properties(
+ objectMapper.readValue(
+ "{\"appStarter\":\"appStarterValue1\", \"dashboard\":{\"dashboardKey\":\"dashboardValue\"}}",
+ Map.class));
+ }
+}
+++ /dev/null
-/*
- *
- * Copyright (c) 2022. Deutsche Telekom AG
- *
- * 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.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- *
- */
-
-package org.onap.portalng.preferences;
-
-import java.time.Clock;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.UUID;
-
-import com.nimbusds.jose.JOSEObjectType;
-import com.nimbusds.jose.JWSAlgorithm;
-import com.nimbusds.jose.JWSHeader;
-import com.nimbusds.jose.JWSSigner;
-import com.nimbusds.jose.crypto.RSASSASigner;
-import com.nimbusds.jose.jwk.JWKSet;
-import com.nimbusds.jose.jwk.KeyUse;
-import com.nimbusds.jose.jwk.RSAKey;
-import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
-import com.nimbusds.jwt.JWTClaimsSet;
-import com.nimbusds.jwt.SignedJWT;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import lombok.Builder;
-import lombok.Getter;
-import lombok.NonNull;
-
-@Component
-public class TokenGenerator {
-
- private static final String ROLES_CLAIM = "roles";
- private static final String USERID_CLAIM = "sub";
-
- private final Clock clock;
- private final RSAKey jwk;
- private final JWKSet jwkSet;
- private final JWSSigner signer;
-
- public TokenGenerator(Clock clock) {
- try {
- this.clock = clock;
- jwk =
- new RSAKeyGenerator(2048)
- .keyUse(KeyUse.SIGNATURE)
- .keyID(UUID.randomUUID().toString())
- .generate();
- jwkSet = new JWKSet(jwk);
- signer = new RSASSASigner(jwk);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public JWKSet getJwkSet() {
- return jwkSet;
- }
-
- public String generateToken(TokenGeneratorConfig config) {
- final Instant iat = clock.instant();
- final Instant exp = iat.plus(config.expireIn);
-
- final JWTClaimsSet claims =
- new JWTClaimsSet.Builder()
- .jwtID(UUID.randomUUID().toString())
- .subject(UUID.randomUUID().toString())
- .issuer(config.issuer())
- .issueTime(Date.from(iat))
- .expirationTime(Date.from(exp))
- .claim(ROLES_CLAIM, config.getRoles())
- .claim(USERID_CLAIM, config.getSub())
- .build();
-
- final SignedJWT jwt =
- new SignedJWT(
- new JWSHeader.Builder(JWSAlgorithm.RS256)
- .keyID(jwk.getKeyID())
- .type(JOSEObjectType.JWT)
- .build(),
- claims);
-
- try {
- jwt.sign(signer);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
-
- return jwt.serialize();
- }
-
- @Getter
- @Builder
- public static class TokenGeneratorConfig {
- private final int port;
-
- @NonNull private final String sub;
-
- @NonNull private final String realm;
-
- @NonNull @Builder.Default private final Duration expireIn = Duration.ofMinutes(5);
-
- @Builder.Default private final List<String> roles = Collections.emptyList();
-
- public String issuer() {
- return "http://localhost:%d/realms/%s".formatted(port, realm);
- }
- }
-}
+++ /dev/null
-/*
- *
- * Copyright (c) 2022. Deutsche Telekom AG
- *
- * 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.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- *
- */
-
-package org.onap.portalng.preferences.preferences;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.junit.jupiter.api.Test;
-import org.onap.portalng.preferences.BaseIntegrationTest;
-import org.onap.portalng.preferences.openapi.model.PreferencesApiDto;
-import org.onap.portalng.preferences.services.PreferencesService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-
-import io.restassured.http.ContentType;
-
-class PreferencesControllerIntegrationTest extends BaseIntegrationTest {
-
- @Autowired
- PreferencesService preferencesService;
-
- @Test
- void thatUserPreferencesCanBeRetrieved() {
- // First save a user preference before a GET can run
- PreferencesApiDto expectedResponse = new PreferencesApiDto()
- .properties("{\"properties\": {\"dashboard\": {\"key1:\": \"value2\"}, \"appStarter\": \"value1\"}}");
- preferencesService
- .savePreferences("test-user", expectedResponse)
- .block();
-
- PreferencesApiDto actualResponse = requestSpecification("test-user")
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .when()
- .get("/v1/preferences")
- .then()
- .statusCode(HttpStatus.OK.value())
- .extract()
- .body()
- .as(PreferencesApiDto.class);
-
- assertThat(actualResponse).isNotNull();
- assertThat(actualResponse.getProperties()).isEqualTo(expectedResponse.getProperties());
- }
-
- @Test
- void thatUserPreferencesCanNotBeRetrieved() {
- unauthenticatedRequestSpecification()
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .contentType(ContentType.JSON)
- .when()
- .get("/v1/preferences")
- .then()
- .statusCode(HttpStatus.UNAUTHORIZED.value());
- }
-
- @Test
- void thatUserPreferencesCanBeSaved() {
- PreferencesApiDto expectedResponse = new PreferencesApiDto()
- .properties("""
- {
- "properties": { "appStarter": "value1",
- "dashboard": {"key1:" : "value2"}
- }\s
- }\
- """);
- PreferencesApiDto actualResponse = requestSpecification()
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .contentType(ContentType.JSON)
- .body(expectedResponse)
- .when()
- .post("/v1/preferences")
- .then()
- .statusCode(HttpStatus.OK.value())
- .extract()
- .body()
- .as(PreferencesApiDto.class);
-
- assertThat(actualResponse).isNotNull();
- assertThat(actualResponse.getProperties()).isEqualTo(expectedResponse.getProperties());
- }
-
- @Test
- void thatUserPreferencesCanBeUpdated() {
- // First save a user preference before a GET can run
- PreferencesApiDto initialPreferences = new PreferencesApiDto()
- .properties("""
- {
- "properties": { "appStarter": "value1",
- "dashboard": {"key1:" : "value2"}
- }\s
- }\
- """);
- preferencesService
- .savePreferences("test-user", initialPreferences)
- .block();
-
- PreferencesApiDto expectedResponse = new PreferencesApiDto()
- .properties("""
- {
- "properties": { "appStarter": "value3",
- "dashboard": {"key2:" : "value4"}
- }\s
- }\
- """);
- PreferencesApiDto actualResponse = requestSpecification("test-user")
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .contentType(ContentType.JSON)
- .body(expectedResponse)
- .when()
- .put("/v1/preferences")
- .then()
- .statusCode(HttpStatus.OK.value())
- .extract()
- .body()
- .as(PreferencesApiDto.class);
-
- assertThat(actualResponse).isNotNull();
- assertThat(actualResponse.getProperties()).isEqualTo(expectedResponse.getProperties());
- }
-
- @Test
- void thatUserPreferencesCanNotBeFound() {
-
- PreferencesApiDto actualResponse = requestSpecification("test-canNotBeFound")
- .given()
- .accept(MediaType.APPLICATION_JSON_VALUE)
- .when()
- .get("/v1/preferences")
- .then()
- .statusCode(HttpStatus.OK.value())
- .extract()
- .body()
- .as(PreferencesApiDto.class);
-
- assertThat(actualResponse).isNotNull();
- assertThat(actualResponse.getProperties()).isNull();
- }
-}
address: 0.0.0.0
spring:
+ application:
+ name: preferences-test
jackson:
serialization:
# needed for serializing objects of type object
- FAIL_ON_EMPTY_BEANS: false
+ fail-on-empty-beans: false
security:
oauth2:
resourceserver:
jwt:
- jwk-set-uri: http://localhost:${wiremock.server.port}/realms/ONAP/protocol/openid-connect/certs #Keycloak Endpoint
+ # this value needs to be set for SpringBoot Context, but the tests us mockJwt so it doesn't need to be a valid address
+ jwk-set-uri: http://localhost
datasource:
- url: jdbc:tc:postgresql:16:///preferences
+ url: jdbc:tc:postgresql:///preferences
username: postgres
password: postgres
jpa:
preferences:
realm: ONAP
-
management:
endpoints:
web:
enabled: true
java:
enabled: true
+ tracing:
+ enabled: false
logger:
- traceIdHeaderName: ${TRACE_ID_HEADER_NAME}
+ traceIdHeaderName: x-b3-traceid
enabled: true
excludePaths:
- "/actuator/**"
+
+logging:
+ structured:
+ format:
+ console: logstash
+ level:
+ root: info
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration scan="true">
- <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
- <level>${LOGBACK_LEVEL:-info}</level>
- </filter>
- <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
- </appender>
-
- <root level="all">
- <appender-ref ref="stdout"/>
- </root>
-</configuration>
// this build.gradle is mainly here to satisfy the Jenkins gradle plugin
allprojects {
repositories {
- mavenCentral()
+ mavenCentral()
}
}
KEYCLOAK_IMAGE=quay.io/keycloak/keycloak
-KEYCLOAK_VERSION=22.04
+KEYCLOAK_VERSION=26.3
KEYCLOAK_USER=admin
-KEYCLOAK_PASSWORD=password
-KEYCLOAK_DB=keycloak
-KEYCLOAK_DB_USER=keycloak
-KEYCLOAK_DB_PASSWORD=password
-POSTGRES_IMAGE=postgres
-POSTGRES_VERSION=15rc1
-MONGO_IMAGE=mongo
-MONGO_VERSION=latest
-MONGO_USER=root
-MONGO_PASSWORD=password
+KEYCLOAK_PASSWORD=admin
+POSTGRES_IMAGE=docker.io/postgres
+POSTGRES_VERSION=16
+POSTGRES_USER=postgres
+POSTGRES_PASSWORD=postgres
+JAEGER_IMAGE=cr.jaegertracing.io/jaegertracing/jaeger
+JAEGER_VERSION=2.8.0
-version: '3'
-
-volumes:
- postgres_data:
- driver: local
-
services:
- postgres:
- image: "${POSTGRES_IMAGE}:${POSTGRES_VERSION}"
- volumes:
- - postgres_data:/var/lib/postgresql/data
- environment:
- POSTGRES_DB: ${KEYCLOAK_DB}
- POSTGRES_USER: ${KEYCLOAK_DB_USER}
- POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
keycloak:
- image: "${KEYCLOAK_IMAGE}:${KEYCLOAK_VERSION}"
- environment:
- DB_VENDOR: POSTGRES
- DB_ADDR: postgres
- DB_DATABASE: ${KEYCLOAK_DB}
- DB_USER: ${KEYCLOAK_DB_USER}
- DB_SCHEMA: public
- DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
- KEYCLOAK_USER: ${KEYCLOAK_USER}
- KEYCLOAK_PASSWORD: ${KEYCLOAK_PASSWORD}
- KEYCLOAK_IMPORT: /config/onap-realm.json
- ports:
- - 8080:8080
- volumes:
- - ./config:/config
- depends_on:
- - postgres
- mongo:
- image: "${MONGO_IMAGE}:${MONGO_VERSION}"
+ command: start-dev --import-realm
+ image: "${KEYCLOAK_IMAGE}:${KEYCLOAK_VERSION}"
+ environment:
+ KC_BOOTSTRAP_ADMIN_USERNAME: ${KEYCLOAK_USER}
+ KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_PASSWORD}
ports:
- - 27017:27017
+ - 8080:8080
+ volumes:
+ - ./config:/opt/keycloak/data/import
+ postgres:
+ image: "${POSTGRES_IMAGE}:${POSTGRES_VERSION}"
+ ports:
+ - 5432:5432
environment:
- MONGO_INITDB_ROOT_USERNAME: ${MONGO_USER}
- MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
+ POSTGRES_USER: ${POSTGRES_USER}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_DB: preferences
+ jaeger:
+ image: "${JAEGER_IMAGE}:${JAEGER_VERSION}"
+ ports:
+ - '9411:9411'
+ - '5778:5778'
+ - '4318:4318'
+ - '4317:4317'
+ - '16686:16686'
plugins {
- id 'java'
- id 'org.openapi.generator'
+ id 'java'
+ id 'org.openapi.generator'
}
dependencies {
- compileOnly 'io.swagger.core.v3:swagger-annotations:2.2.34'
- compileOnly 'org.springframework.boot:spring-boot-starter-webflux:3.5.4'
- compileOnly 'jakarta.validation:jakarta.validation-api:3.1.1'
+ compileOnly 'io.swagger.core.v3:swagger-annotations:2.2.34'
+ compileOnly 'org.springframework.boot:spring-boot-starter-webflux:3.5.4'
+ compileOnly 'jakarta.validation:jakarta.validation-api:3.1.1'
}
// https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator-gradle-plugin/README.adoc
openApiGenerate {
- generatorName = "spring"
- library = "spring-boot"
- inputSpec = "$projectDir/src/main/resources/api/api.yml"
- outputDir = "$buildDir/openapi"
- configOptions = [
- hideGenerationTimestamp: "true",
- openApiNullable: "false",
- skipDefaultInterface: "true",
- dateLibrary: "java8",
- interfaceOnly: "true",
- useTags: "true",
- useOptional: "true",
- reactive: "true",
- useSpringBoot3: "true"
- ]
- generateApiTests = false
- generateApiDocumentation = false
- generateModelTests = false
- generateModelDocumentation = false
- invokerPackage = "org.onap.portalng.preferences.openapi"
- apiPackage = "org.onap.portalng.preferences.openapi.api"
- modelPackage = "org.onap.portalng.preferences.openapi.model"
- modelNameSuffix = "ApiDto"
+ generatorName = "spring"
+ library = "spring-boot"
+ inputSpec = "$projectDir/src/main/resources/api/api.yml"
+ outputDir = "$buildDir/openapi"
+ configOptions = [
+ hideGenerationTimestamp: "true",
+ openApiNullable: "false",
+ skipDefaultInterface: "true",
+ dateLibrary: "java8",
+ interfaceOnly: "true",
+ useTags: "true",
+ useOptional: "true",
+ reactive: "true",
+ useSpringBoot3: "true"
+ ]
+ generateApiTests = false
+ generateApiDocumentation = false
+ generateModelTests = false
+ generateModelDocumentation = false
+ invokerPackage = "org.onap.portalng.preferences.openapi"
+ apiPackage = "org.onap.portalng.preferences.openapi.api"
+ modelPackage = "org.onap.portalng.preferences.openapi.model"
+ modelNameSuffix = "ApiDto"
}
compileJava {
- dependsOn tasks.openApiGenerate
+ dependsOn tasks.openApiGenerate
}
sourceSets {
- main {
- java {
- srcDirs += file("$buildDir/openapi/src/main/java")
- }
+ main {
+ java {
+ srcDirs += file("$buildDir/openapi/src/main/java")
}
+ }
}
tasks.withType(Test).configureEach {
- useJUnitPlatform()
+ useJUnitPlatform()
}
// Centrally declare plugin versions here
pluginManagement {
- // https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_version_management
- plugins {
- id 'io.spring.dependency-management' version '1.1.7'
- id 'org.springframework.boot' version '3.4.5'
- id 'com.github.hierynomus.license' version '0.16.1'
- id 'com.gorylenko.gradle-git-properties' version '2.5.0'
- id 'org.openapi.generator' version '7.13.0'
- }
- // https://docs.gradle.org/current/userguide/plugins.html#sec:custom_plugin_repositories
- repositories {
- mavenCentral()
- gradlePluginPortal()
- }
+ // https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_version_management
+ plugins {
+ id 'io.spring.dependency-management' version '1.1.7'
+ id 'org.springframework.boot' version '3.5.4'
+ id 'com.github.hierynomus.license' version '0.16.1'
+ id 'com.gorylenko.gradle-git-properties' version '2.5.2'
+ id 'org.openapi.generator' version '7.14.0'
+ id 'com.diffplug.spotless' version '7.2.1'
+ }
+ // https://docs.gradle.org/current/userguide/plugins.html#sec:custom_plugin_repositories
+ repositories {
+ mavenCentral()
+ gradlePluginPortal()
+ }
}
// This is a preview feature, enable in the future and remove repositories blocks from sub build.gradles
// https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:centralized-repository-declaration
// dependencyResolutionManagement {
-// maven {
-// url "${maven_central_url}"
-// credentials {
-// username = "${artifactory_user}"
-// password = "${artifactory_password}"
-// }
-// }
-// maven {
-// url "${gradle_plugins_url}"
-// credentials {
-// username = "${artifactory_user}"
-// password = "${artifactory_password}"
-// }
-// }
+// maven {
+// url "${maven_central_url}"
+// credentials {
+// username = "${artifactory_user}"
+// password = "${artifactory_password}"
+// }
+// }
+// maven {
+// url "${gradle_plugins_url}"
+// credentials {
+// username = "${artifactory_user}"
+// password = "${artifactory_password}"
+// }
+// }
// }
rootProject.name = 'preferences'