🎨 Add formatter and format

This commit is contained in:
andreas.dinauer 2025-11-15 10:39:36 +01:00
parent 23667410a7
commit b44c333ae4
18 changed files with 258 additions and 144 deletions

37
format.xml Normal file
View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<profiles version="12">
<profile kind="CodeFormatterProfile" name="format" version="12">
<!-- General code formatting settings -->
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<!-- Braces in new line -->
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="next_line"/>
<!-- Spaces after keywords -->
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_keyword_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_keyword_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_keyword_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_keyword_in_switch" value="insert"/>
<!-- Else-if-statement -->
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="insert"/>
<!-- Switch-statement -->
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<!-- No Line Wrapping -->
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="9999"/>
</profile>
</profiles>

18
pom.xml
View File

@ -134,6 +134,24 @@
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.29.0</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>format</goal>
</goals>
</execution>
</executions>
<configuration>
<configFile>format.xml</configFile>
<lineEnding>LF</lineEnding>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -1,20 +1,14 @@
package dev.dinauer.metrics.service;
import dev.dinauer.metrics.service.client.AuthenticationService;
import dev.dinauer.metrics.service.client.auth.AuthenticationService;
import dev.dinauer.metrics.service.model.BucketUnit;
import dev.dinauer.metrics.service.model.Collection;
import io.quarkus.security.UnauthorizedException;
import jakarta.inject.Inject;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Size;
import jakarta.ws.rs.*;
import org.jboss.logging.Logger;
import javax.swing.text.html.Option;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalLong;
@Path("/{resource}/{metric}")
public class Resource

View File

@ -1,113 +0,0 @@
package dev.dinauer.metrics.service.client;
import io.quarkus.elytron.security.common.BcryptUtil;
import io.quarkus.security.UnauthorizedException;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import java.util.Base64;
import java.util.List;
@RequestScoped
public class AuthenticationService
{
@Context
HttpHeaders headers;
@Inject
ClientRepo clientRepo;
public boolean canWrite()
{
AuthHeader authHeader = getAuthHeader();
switch (authHeader.type())
{
case AuthType.BASIC ->
{
BasicAuthCredentials credentials = getCredentials(authHeader.credentials());
Client client = getClient(credentials);
return Permission.RW.equals(client.permission());
}
}
return false;
}
public boolean canRead()
{
AuthHeader authHeader = getAuthHeader();
switch (authHeader.type())
{
case AuthType.BASIC ->
{
BasicAuthCredentials credentials = getCredentials(authHeader.credentials());
Client client = getClient(credentials);
return List.of(Permission.RO, Permission.RW).contains(client.permission());
}
}
return false;
}
private AuthHeader getAuthHeader()
{
String authHeader = headers.getHeaderString("Authorization");
if (authHeader != null)
{
String[] sections = authHeader.split("\\s+");
if (sections.length == 2)
{
try
{
return new AuthHeader(AuthType.valueOf(sections[0].toUpperCase()), sections[1]);
}
catch (IllegalArgumentException e)
{
throw new UnauthorizedException();
}
}
}
throw new UnauthorizedException();
}
private BasicAuthCredentials getCredentials(String base64Credentials)
{
String credentials = new String(Base64.getDecoder().decode(base64Credentials));
String[] credentialSections = credentials.split(":");
if (credentialSections.length == 2)
{
String clientId = credentialSections[0];
String password = credentialSections[1];
return new BasicAuthCredentials(clientId, password);
}
throw new UnauthorizedException();
}
private Client getClient(BasicAuthCredentials credentials)
{
Client client = clientRepo.findById(credentials.clientId());
if (client != null)
{
if (BcryptUtil.matches(credentials.password(), client.password()))
{
return client;
}
throw new UnauthorizedException();
}
throw new NotFoundException();
}
private record AuthHeader(AuthType type, String credentials)
{
}
private enum AuthType
{
BASIC, BEARER
}
private record BasicAuthCredentials(String clientId, String password)
{
}
}

View File

@ -2,8 +2,7 @@ package dev.dinauer.metrics.service.client;
import java.util.Objects;
public record Client(String id, String password, Permission permission)
{
public record Client(String id, String password, Permission permission) {
@Override
public boolean equals(Object object)
{

View File

@ -13,7 +13,7 @@ import java.util.List;
@ApplicationScoped
public class ClientRepo
{
private final static String CLIENT_PROPERTY_PREFIX= "dev.dinauer.metrics-service.client";
private final static String CLIENT_PROPERTY_PREFIX = "dev.dinauer.metrics-service.client";
List<Client> clients;

View File

@ -2,5 +2,5 @@ package dev.dinauer.metrics.service.client;
public enum Permission
{
RW, RO
RW, RO, WO
}

View File

@ -0,0 +1,74 @@
package dev.dinauer.metrics.service.client.auth;
import dev.dinauer.metrics.service.client.Client;
import dev.dinauer.metrics.service.client.Permission;
import dev.dinauer.metrics.service.client.auth.utils.AuthHeader;
import dev.dinauer.metrics.service.client.auth.utils.AuthType;
import io.quarkus.security.UnauthorizedException;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import java.util.List;
@RequestScoped
public class AuthenticationService
{
private static final List<Permission> READ_PERMISSIONS = List.of(Permission.RO, Permission.RW);
private static final List<Permission> WRITE_PERMISSIONS = List.of(Permission.WO, Permission.RW);
@Context
HttpHeaders headers;
@Inject
BasicAuthClientProvider basicAuthClientProvider;
@Inject
BearerAuthClientProvider bearerAuthClientProvider;
public boolean canWrite()
{
return WRITE_PERMISSIONS.contains(getClient().permission());
}
public boolean canRead()
{
return READ_PERMISSIONS.contains(getClient().permission());
}
private Client getClient()
{
AuthHeader header = getAuthHeader();
switch (header.type())
{
case BASIC -> {
return basicAuthClientProvider.get(header.credentials());
}
case BEARER -> {
return bearerAuthClientProvider.get(header.credentials());
}
}
throw new UnauthorizedException();
}
private AuthHeader getAuthHeader()
{
String authHeader = headers.getHeaderString("Authorization");
if (authHeader != null)
{
String[] sections = authHeader.split("\\s+");
if (sections.length == 2)
{
try
{
return new AuthHeader(AuthType.valueOf(sections[0].toUpperCase()), sections[1]);
} catch (IllegalArgumentException e)
{
throw new UnauthorizedException();
}
}
}
throw new UnauthorizedException();
}
}

View File

@ -0,0 +1,47 @@
package dev.dinauer.metrics.service.client.auth;
import dev.dinauer.metrics.service.client.Client;
import dev.dinauer.metrics.service.client.ClientRepo;
import dev.dinauer.metrics.service.client.auth.utils.BasicAuthCredentials;
import io.quarkus.elytron.security.common.BcryptUtil;
import io.quarkus.security.UnauthorizedException;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.NotFoundException;
import java.util.Base64;
@ApplicationScoped
public class BasicAuthClientProvider
{
@Inject
ClientRepo clientRepo;
public Client get(String credentials)
{
BasicAuthCredentials basicAuthCredentials = getCredentials(credentials);
Client client = clientRepo.findById(basicAuthCredentials.clientId());
if (client != null)
{
if (BcryptUtil.matches(basicAuthCredentials.password(), client.password()))
{
return client;
}
throw new UnauthorizedException();
}
throw new NotFoundException();
}
private BasicAuthCredentials getCredentials(String base64Credentials)
{
String credentials = new String(Base64.getDecoder().decode(base64Credentials));
String[] credentialSections = credentials.split(":");
if (credentialSections.length == 2)
{
String clientId = credentialSections[0];
String password = credentialSections[1];
return new BasicAuthCredentials(clientId, password);
}
throw new UnauthorizedException();
}
}

View File

@ -0,0 +1,44 @@
package dev.dinauer.metrics.service.client.auth;
import dev.dinauer.metrics.service.client.Client;
import dev.dinauer.metrics.service.client.Permission;
import io.quarkus.security.UnauthorizedException;
import io.smallrye.jwt.auth.principal.JWTParser;
import io.smallrye.jwt.auth.principal.ParseException;
import io.smallrye.jwt.build.Jwt;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.jwt.JsonWebToken;
import java.util.Optional;
@ApplicationScoped
public class BearerAuthClientProvider
{
@Inject
JWTParser parser;
@ConfigProperty(name = "dev.dinauer.metrics-service.jwt.client.field")
String clientIdField;
public Client get(String credentials)
{
try
{
JsonWebToken token = parser.parse(credentials);
if (token != null)
{
Optional<String> user = token.claim(clientIdField);
if (user.isPresent())
{
return new Client(user.get(), null, Permission.RO);
}
}
throw new UnauthorizedException();
} catch (ParseException e)
{
throw new UnauthorizedException();
}
}
}

View File

@ -0,0 +1,4 @@
package dev.dinauer.metrics.service.client.auth.utils;
public record AuthHeader(AuthType type, String credentials) {
}

View File

@ -0,0 +1,6 @@
package dev.dinauer.metrics.service.client.auth.utils;
public enum AuthType
{
BASIC, BEARER
}

View File

@ -0,0 +1,4 @@
package dev.dinauer.metrics.service.client.auth.utils;
public record BasicAuthCredentials(String clientId, String password) {
}

View File

@ -84,8 +84,7 @@ public class Collection
try
{
this.metrics = OBJECT_MAPPER.writeValueAsString(metrics);
}
catch (JsonProcessingException e)
} catch (JsonProcessingException e)
{
throw new RuntimeException(e);
}
@ -124,9 +123,10 @@ public class Collection
{
try
{
return OBJECT_MAPPER.readValue(metrics, new TypeReference<Map<String, Metric>>() {});
}
catch (JsonProcessingException e)
return OBJECT_MAPPER.readValue(metrics, new TypeReference<Map<String, Metric>>()
{
});
} catch (JsonProcessingException e)
{
throw new RuntimeException(e);
}

View File

@ -14,19 +14,19 @@ public class TimestampGenerator
{
switch (unit)
{
case BucketUnit.RAW ->
case BucketUnit.RAW:
{
return timestamp.format(DateTimeFormatter.ISO_DATE_TIME).substring(0, 19);
}
case BucketUnit.HOURLY ->
case BucketUnit.HOURLY:
{
return timestamp.format(DateTimeFormatter.ISO_DATE_TIME).substring(0, 13);
}
case BucketUnit.DAILY ->
case BucketUnit.DAILY:
{
return timestamp.format(DateTimeFormatter.ISO_DATE_TIME).substring(0, 10);
}
case BucketUnit.WEEKLY ->
case BucketUnit.WEEKLY:
{
String week = String.valueOf(timestamp.get(WeekFields.ISO.weekOfWeekBasedYear()));
String year = String.valueOf(timestamp.get(WeekFields.ISO.weekBasedYear()));
@ -35,15 +35,15 @@ public class TimestampGenerator
String yearString = "0".repeat(4 - year.length()).concat(year);
return String.format("%s-W%s", yearString, weekString);
}
case BucketUnit.MONTHLY ->
case BucketUnit.MONTHLY:
{
return timestamp.format(DateTimeFormatter.ISO_DATE_TIME).substring(0, 7);
}
case BucketUnit.YEARLY ->
case BucketUnit.YEARLY:
{
return timestamp.format(DateTimeFormatter.ISO_DATE_TIME).substring(0, 4);
}
case BucketUnit.TOTAL ->
case BucketUnit.TOTAL:
{
return "TOTAL";
}

View File

@ -4,6 +4,7 @@ quarkus.http.root-path=/api/metrics
dev.dinauer.metrics-service.buckets=RAW,HOURLY,DAILY,WEEKLY,MONTHLY,YEARLY,TOTAL
dev.dinauer.metrics-service.client.kubooboo.ro=3749832748923748923
dev.dinauer.metrics-service.jwt.client.field=upn
# JWT
mp.jwt.verify.publickey.location=dev/publicKey.pem

View File

@ -3,6 +3,7 @@ package dev.dinauer;
import io.quarkus.test.junit.QuarkusIntegrationTest;
@QuarkusIntegrationTest
class GreetingResourceIT extends GreetingResourceTest {
class GreetingResourceIT extends GreetingResourceTest
{
// Execute the same tests but in packaged mode.
}

View File

@ -7,14 +7,12 @@ import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
class GreetingResourceTest {
class GreetingResourceTest
{
@Test
void testHelloEndpoint() {
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("Hello from Quarkus REST"));
void testHelloEndpoint()
{
given().when().get("/hello").then().statusCode(200).body(is("Hello from Quarkus REST"));
}
}